main.py revision 11338:5981f61b8936
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="TICK[,TICK]", action='append', split=',',
98        help="Create breakpoint(s) at TICK(s) " \
99             "(kills process if no debugger attached)")
100    option("--debug-help", action='store_true',
101        help="Print help on debug flags")
102    option("--debug-flags", metavar="FLAG[,FLAG]", action='append', split=',',
103        help="Sets the flags for debug output (-FLAG disables a flag)")
104    option("--debug-start", metavar="TICK", type='int',
105        help="Start debug output at TICK")
106    option("--debug-end", metavar="TICK", type='int',
107        help="End debug output at TICK")
108    option("--debug-file", metavar="FILE", default="cout",
109        help="Sets the output file for debug [Default: %default]")
110    option("--debug-ignore", metavar="EXPR", action='append', split=':',
111        help="Ignore EXPR sim objects")
112    option("--remote-gdb-port", type='int', default=7000,
113        help="Remote gdb base port (set to 0 to disable listening)")
114
115    # Help options
116    group("Help Options")
117    option("--list-sim-objects", action='store_true', default=False,
118        help="List all built-in SimObjects, their params and default values")
119
120    # load the options.py config file to allow people to set their own
121    # default options
122    options_file = config.get('options.py')
123    if options_file:
124        scope = { 'options' : options }
125        execfile(options_file, scope)
126
127    arguments = options.parse_args()
128    return options,arguments
129
130def interact(scope):
131    banner = "gem5 Interactive Console"
132
133    ipshell = None
134    prompt_in1 = "gem5 \\#> "
135    prompt_out = "gem5 \\#: "
136
137    # Is IPython version 0.10 or earlier available?
138    try:
139        from IPython.Shell import IPShellEmbed
140        ipshell = IPShellEmbed(argv=["-prompt_in1", prompt_in1,
141                                     "-prompt_out", prompt_out],
142                               banner=banner, user_ns=scope)
143    except ImportError:
144        pass
145
146    # Is IPython version 0.11 or later available?
147    if not ipshell:
148        try:
149            import IPython
150            from IPython.config.loader import Config
151            from IPython.frontend.terminal.embed import InteractiveShellEmbed
152
153            cfg = Config()
154            cfg.PromptManager.in_template = prompt_in1
155            cfg.PromptManager.out_template = prompt_out
156            ipshell = InteractiveShellEmbed(config=cfg, user_ns=scope,
157                                            banner1=banner)
158        except ImportError:
159            pass
160
161    if ipshell:
162        ipshell()
163    else:
164        # Use the Python shell in the standard library if IPython
165        # isn't available.
166        code.InteractiveConsole(scope).interact(banner)
167
168def main(*args):
169    import m5
170
171    import core
172    import debug
173    import defines
174    import event
175    import info
176    import stats
177    import trace
178
179    from util import fatal
180
181    if len(args) == 0:
182        options, arguments = parse_options()
183    elif len(args) == 2:
184        options, arguments = args
185    else:
186        raise TypeError, "main() takes 0 or 2 arguments (%d given)" % len(args)
187
188    m5.options = options
189
190    def check_tracing():
191        if defines.TRACING_ON:
192            return
193
194        fatal("Tracing is not enabled.  Compile with TRACING_ON")
195
196    # Set the main event queue for the main thread.
197    event.mainq = event.getEventQueue(0)
198    event.setEventQueue(event.mainq)
199
200    if not os.path.isdir(options.outdir):
201        os.makedirs(options.outdir)
202
203    # These filenames are used only if the redirect_std* options are set
204    stdout_file = os.path.join(options.outdir, options.stdout_file)
205    stderr_file = os.path.join(options.outdir, options.stderr_file)
206
207    # Print redirection notices here before doing any redirection
208    if options.redirect_stdout and not options.redirect_stderr:
209        print "Redirecting stdout and stderr to", stdout_file
210    else:
211        if options.redirect_stdout:
212            print "Redirecting stdout to", stdout_file
213        if options.redirect_stderr:
214            print "Redirecting stderr to", stderr_file
215
216    # Now redirect stdout/stderr as desired
217    if options.redirect_stdout:
218        redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
219        os.dup2(redir_fd, sys.stdout.fileno())
220        if not options.redirect_stderr:
221            os.dup2(redir_fd, sys.stderr.fileno())
222
223    if options.redirect_stderr:
224        redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
225        os.dup2(redir_fd, sys.stderr.fileno())
226
227    done = False
228
229    if options.build_info:
230        done = True
231        print 'Build information:'
232        print
233        print 'compiled %s' % defines.compileDate;
234        print 'build options:'
235        keys = defines.buildEnv.keys()
236        keys.sort()
237        for key in keys:
238            val = defines.buildEnv[key]
239            print '    %s = %s' % (key, val)
240        print
241
242    if options.copyright:
243        done = True
244        print info.COPYING
245        print
246
247    if options.readme:
248        done = True
249        print 'Readme:'
250        print
251        print info.README
252        print
253
254    if options.debug_help:
255        done = True
256        check_tracing()
257        debug.help()
258
259    if options.list_sim_objects:
260        import SimObject
261        done = True
262        print "SimObjects:"
263        objects = SimObject.allClasses.keys()
264        objects.sort()
265        for name in objects:
266            obj = SimObject.allClasses[name]
267            print "    %s" % obj
268            params = obj._params.keys()
269            params.sort()
270            for pname in params:
271                param = obj._params[pname]
272                default = getattr(param, 'default', '')
273                print "        %s" % pname
274                if default:
275                    print "            default: %s" % default
276                print "            desc: %s" % param.desc
277                print
278            print
279
280    if done:
281        sys.exit(0)
282
283    # setting verbose and quiet at the same time doesn't make sense
284    if options.verbose > 0 and options.quiet > 0:
285        options.usage(2)
286
287    verbose = options.verbose - options.quiet
288    if verbose >= 0:
289        print "gem5 Simulator System.  http://gem5.org"
290        print brief_copyright
291        print
292
293        print "gem5 compiled %s" % defines.compileDate;
294
295        print "gem5 started %s" % \
296            datetime.datetime.now().strftime("%b %e %Y %X")
297        print "gem5 executing on %s, pid %d" % \
298            (socket.gethostname(), os.getpid())
299
300        # in Python 3 pipes.quote() is moved to shlex.quote()
301        import pipes
302        print "command line:", " ".join(map(pipes.quote, sys.argv))
303        print
304
305    # check to make sure we can find the listed script
306    if not arguments or not os.path.isfile(arguments[0]):
307        if arguments and not os.path.isfile(arguments[0]):
308            print "Script %s not found" % arguments[0]
309
310        options.usage(2)
311
312    # tell C++ about output directory
313    core.setOutputDir(options.outdir)
314
315    # update the system path with elements from the -p option
316    sys.path[0:0] = options.path
317
318    # set stats options
319    stats.initText(options.stats_file)
320
321    # set debugging options
322    debug.setRemoteGDBPort(options.remote_gdb_port)
323    for when in options.debug_break:
324        debug.schedBreak(int(when))
325
326    if options.debug_flags:
327        check_tracing()
328
329        on_flags = []
330        off_flags = []
331        for flag in options.debug_flags:
332            off = False
333            if flag.startswith('-'):
334                flag = flag[1:]
335                off = True
336
337            if flag not in debug.flags:
338                print >>sys.stderr, "invalid debug flag '%s'" % flag
339                sys.exit(1)
340
341            if off:
342                debug.flags[flag].disable()
343            else:
344                debug.flags[flag].enable()
345
346    if options.debug_start:
347        check_tracing()
348        e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
349        event.mainq.schedule(e, options.debug_start)
350    else:
351        trace.enable()
352
353    if options.debug_end:
354        check_tracing()
355        e = event.create(trace.disable, event.Event.Debug_Enable_Pri)
356        event.mainq.schedule(e, options.debug_end)
357
358    trace.output(options.debug_file)
359
360    for ignore in options.debug_ignore:
361        check_tracing()
362        trace.ignore(ignore)
363
364    sys.argv = arguments
365    sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
366
367    filename = sys.argv[0]
368    filedata = file(filename, 'r').read()
369    filecode = compile(filedata, filename, 'exec')
370    scope = { '__file__' : filename,
371              '__name__' : '__m5_main__' }
372
373    # we want readline if we're doing anything interactive
374    if options.interactive or options.pdb:
375        exec "import readline" in scope
376
377    # if pdb was requested, execfile the thing under pdb, otherwise,
378    # just do the execfile normally
379    if options.pdb:
380        import pdb
381        import traceback
382
383        pdb = pdb.Pdb()
384        try:
385            pdb.run(filecode, scope)
386        except SystemExit:
387            print "The program exited via sys.exit(). Exit status: ",
388            print sys.exc_info()[1]
389        except:
390            traceback.print_exc()
391            print "Uncaught exception. Entering post mortem debugging"
392            t = sys.exc_info()[2]
393            while t.tb_next is not None:
394                t = t.tb_next
395                pdb.interaction(t.tb_frame,t)
396    else:
397        exec filecode in scope
398
399    # once the script is done
400    if options.interactive:
401        interact(scope)
402
403if __name__ == '__main__':
404    from pprint import pprint
405
406    options, arguments = parse_options()
407
408    print 'opts:'
409    pprint(options, indent=4)
410    print
411
412    print 'args:'
413    pprint(arguments, indent=4)
414