main.py revision 9960
1# Copyright (c) 2005 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Nathan Binkert
28
29import code
30import datetime
31import os
32import socket
33import sys
34
35__all__ = [ 'options', 'arguments', 'main' ]
36
37usage="%prog [gem5 options] script.py [script options]"
38version="%prog 2.0"
39brief_copyright=\
40    "gem5 is copyrighted software; use the --copyright option for details."
41
42def parse_options():
43    import config
44    from options import OptionParser
45
46    options = OptionParser(usage=usage, version=version,
47                           description=brief_copyright)
48    option = options.add_option
49    group = options.set_group
50
51    # Help options
52    option('-B', "--build-info", action="store_true", default=False,
53        help="Show build information")
54    option('-C', "--copyright", action="store_true", default=False,
55        help="Show full copyright information")
56    option('-R', "--readme", action="store_true", default=False,
57        help="Show the readme")
58
59    # Options for configuring the base simulator
60    option('-d', "--outdir", metavar="DIR", default="m5out",
61        help="Set the output directory to DIR [Default: %default]")
62    option('-r', "--redirect-stdout", action="store_true", default=False,
63        help="Redirect stdout (& stderr, without -e) to file")
64    option('-e', "--redirect-stderr", action="store_true", default=False,
65        help="Redirect stderr to file")
66    option("--stdout-file", metavar="FILE", default="simout",
67        help="Filename for -r redirection [Default: %default]")
68    option("--stderr-file", metavar="FILE", default="simerr",
69        help="Filename for -e redirection [Default: %default]")
70    option('-i', "--interactive", action="store_true", default=False,
71        help="Invoke the interactive interpreter after running the script")
72    option("--pdb", action="store_true", default=False,
73        help="Invoke the python debugger before running the script")
74    option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
75        help="Prepend PATH to the system path when invoking the script")
76    option('-q', "--quiet", action="count", default=0,
77        help="Reduce verbosity")
78    option('-v', "--verbose", action="count", default=0,
79        help="Increase verbosity")
80
81    # Statistics options
82    group("Statistics Options")
83    option("--stats-file", metavar="FILE", default="stats.txt",
84        help="Sets the output file for statistics [Default: %default]")
85
86    # Configuration Options
87    group("Configuration Options")
88    option("--dump-config", metavar="FILE", default="config.ini",
89        help="Dump configuration output file [Default: %default]")
90    option("--json-config", metavar="FILE", default="config.json",
91        help="Create JSON output of the configuration [Default: %default]")
92    option("--dot-config", metavar="FILE", default="config.dot",
93        help="Create DOT & pdf outputs of the configuration [Default: %default]")
94
95    # Debugging options
96    group("Debugging Options")
97    option("--debug-break", metavar="TIME[,TIME]", action='append', split=',',
98        help="Tick to create a breakpoint")
99    option("--debug-help", action='store_true',
100        help="Print help on debug flags")
101    option("--debug-flags", metavar="FLAG[,FLAG]", action='append', split=',',
102        help="Sets the flags for debug output (-FLAG disables a flag)")
103    option("--debug-start", metavar="TIME", type='int',
104        help="Start debug output at TIME (must be in ticks)")
105    option("--debug-file", metavar="FILE", default="cout",
106        help="Sets the output file for debug [Default: %default]")
107    option("--debug-ignore", metavar="EXPR", action='append', split=':',
108        help="Ignore EXPR sim objects")
109    option("--remote-gdb-port", type='int', default=7000,
110        help="Remote gdb base port (set to 0 to disable listening)")
111
112    # Help options
113    group("Help Options")
114    option("--list-sim-objects", action='store_true', default=False,
115        help="List all built-in SimObjects, their params and default values")
116
117    # load the options.py config file to allow people to set their own
118    # default options
119    options_file = config.get('options.py')
120    if options_file:
121        scope = { 'options' : options }
122        execfile(options_file, scope)
123
124    arguments = options.parse_args()
125    return options,arguments
126
127def interact(scope):
128    banner = "gem5 Interactive Console"
129
130    ipshell = None
131    prompt_in1 = "gem5 \\#> "
132    prompt_out = "gem5 \\#: "
133
134    # Is IPython version 0.10 or earlier available?
135    try:
136        from IPython.Shell import IPShellEmbed
137        ipshell = IPShellEmbed(argv=["-prompt_in1", prompt_in1,
138                                     "-prompt_out", prompt_out],
139                               banner=banner, user_ns=scope)
140    except ImportError:
141        pass
142
143    # Is IPython version 0.11 or later available?
144    if not ipshell:
145        try:
146            import IPython
147            from IPython.config.loader import Config
148            from IPython.frontend.terminal.embed import InteractiveShellEmbed
149
150            cfg = Config()
151            cfg.PromptManager.in_template = prompt_in1
152            cfg.PromptManager.out_template = prompt_out
153            ipshell = InteractiveShellEmbed(config=cfg, user_ns=scope,
154                                            banner1=banner)
155        except ImportError:
156            pass
157
158    if ipshell:
159        ipshell()
160    else:
161        # Use the Python shell in the standard library if IPython
162        # isn't available.
163        code.InteractiveConsole(scope).interact(banner)
164
165def main(*args):
166    import m5
167
168    import core
169    import debug
170    import defines
171    import event
172    import info
173    import stats
174    import trace
175
176    from util import fatal
177
178    if len(args) == 0:
179        options, arguments = parse_options()
180    elif len(args) == 2:
181        options, arguments = args
182    else:
183        raise TypeError, "main() takes 0 or 2 arguments (%d given)" % len(args)
184
185    m5.options = options
186
187    def check_tracing():
188        if defines.TRACING_ON:
189            return
190
191        fatal("Tracing is not enabled.  Compile with TRACING_ON")
192
193    if not os.path.isdir(options.outdir):
194        os.makedirs(options.outdir)
195
196    # These filenames are used only if the redirect_std* options are set
197    stdout_file = os.path.join(options.outdir, options.stdout_file)
198    stderr_file = os.path.join(options.outdir, options.stderr_file)
199
200    # Print redirection notices here before doing any redirection
201    if options.redirect_stdout and not options.redirect_stderr:
202        print "Redirecting stdout and stderr to", stdout_file
203    else:
204        if options.redirect_stdout:
205            print "Redirecting stdout to", stdout_file
206        if options.redirect_stderr:
207            print "Redirecting stderr to", stderr_file
208
209    # Now redirect stdout/stderr as desired
210    if options.redirect_stdout:
211        redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
212        os.dup2(redir_fd, sys.stdout.fileno())
213        if not options.redirect_stderr:
214            os.dup2(redir_fd, sys.stderr.fileno())
215
216    if options.redirect_stderr:
217        redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
218        os.dup2(redir_fd, sys.stderr.fileno())
219
220    done = False
221
222    if options.build_info:
223        done = True
224        print 'Build information:'
225        print
226        print 'compiled %s' % defines.compileDate;
227        print 'build options:'
228        keys = defines.buildEnv.keys()
229        keys.sort()
230        for key in keys:
231            val = defines.buildEnv[key]
232            print '    %s = %s' % (key, val)
233        print
234
235    if options.copyright:
236        done = True
237        print info.COPYING
238        print
239
240    if options.readme:
241        done = True
242        print 'Readme:'
243        print
244        print info.README
245        print
246
247    if options.debug_help:
248        done = True
249        check_tracing()
250        debug.help()
251
252    if options.list_sim_objects:
253        import SimObject
254        done = True
255        print "SimObjects:"
256        objects = SimObject.allClasses.keys()
257        objects.sort()
258        for name in objects:
259            obj = SimObject.allClasses[name]
260            print "    %s" % obj
261            params = obj._params.keys()
262            params.sort()
263            for pname in params:
264                param = obj._params[pname]
265                default = getattr(param, 'default', '')
266                print "        %s" % pname
267                if default:
268                    print "            default: %s" % default
269                print "            desc: %s" % param.desc
270                print
271            print
272
273    if done:
274        sys.exit(0)
275
276    # setting verbose and quiet at the same time doesn't make sense
277    if options.verbose > 0 and options.quiet > 0:
278        options.usage(2)
279
280    verbose = options.verbose - options.quiet
281    if options.verbose >= 0:
282        print "gem5 Simulator System.  http://gem5.org"
283        print brief_copyright
284        print
285
286        print "gem5 compiled %s" % defines.compileDate;
287
288        print "gem5 started %s" % \
289            datetime.datetime.now().strftime("%b %e %Y %X")
290        print "gem5 executing on %s" % socket.gethostname()
291
292        print "command line:",
293        for argv in sys.argv:
294            print argv,
295        print
296
297    # check to make sure we can find the listed script
298    if not arguments or not os.path.isfile(arguments[0]):
299        if arguments and not os.path.isfile(arguments[0]):
300            print "Script %s not found" % arguments[0]
301
302        options.usage(2)
303
304    # tell C++ about output directory
305    core.setOutputDir(options.outdir)
306
307    # update the system path with elements from the -p option
308    sys.path[0:0] = options.path
309
310    # set stats options
311    stats.initText(options.stats_file)
312
313    # set debugging options
314    debug.setRemoteGDBPort(options.remote_gdb_port)
315    for when in options.debug_break:
316        debug.schedBreak(int(when))
317
318    if options.debug_flags:
319        check_tracing()
320
321        on_flags = []
322        off_flags = []
323        for flag in options.debug_flags:
324            off = False
325            if flag.startswith('-'):
326                flag = flag[1:]
327                off = True
328
329            if flag not in debug.flags:
330                print >>sys.stderr, "invalid debug flag '%s'" % flag
331                sys.exit(1)
332
333            if off:
334                debug.flags[flag].disable()
335            else:
336                debug.flags[flag].enable()
337
338    if options.debug_start:
339        check_tracing()
340        e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
341        event.mainq.schedule(e, options.debug_start)
342    else:
343        trace.enable()
344
345    trace.output(options.debug_file)
346
347    for ignore in options.debug_ignore:
348        check_tracing()
349        trace.ignore(ignore)
350
351    sys.argv = arguments
352    sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
353
354    filename = sys.argv[0]
355    filedata = file(filename, 'r').read()
356    filecode = compile(filedata, filename, 'exec')
357    scope = { '__file__' : filename,
358              '__name__' : '__m5_main__' }
359
360    # we want readline if we're doing anything interactive
361    if options.interactive or options.pdb:
362        exec "import readline" in scope
363
364    # if pdb was requested, execfile the thing under pdb, otherwise,
365    # just do the execfile normally
366    if options.pdb:
367        import pdb
368        import traceback
369
370        pdb = pdb.Pdb()
371        try:
372            pdb.run(filecode, scope)
373        except SystemExit:
374            print "The program exited via sys.exit(). Exit status: ",
375            print sys.exc_info()[1]
376        except:
377            traceback.print_exc()
378            print "Uncaught exception. Entering post mortem debugging"
379            t = sys.exc_info()[2]
380            while t.tb_next is not None:
381                t = t.tb_next
382                pdb.interaction(t.tb_frame,t)
383    else:
384        exec filecode in scope
385
386    # once the script is done
387    if options.interactive:
388        interact(scope)
389
390if __name__ == '__main__':
391    from pprint import pprint
392
393    options, arguments = parse_options()
394
395    print 'opts:'
396    pprint(options, indent=4)
397    print
398
399    print 'args:'
400    pprint(arguments, indent=4)
401