main.py revision 11161:15492f220f16
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    # Set the main event queue for the main thread.
194    event.mainq = event.getEventQueue(0)
195    event.setEventQueue(event.mainq)
196
197    if not os.path.isdir(options.outdir):
198        os.makedirs(options.outdir)
199
200    # These filenames are used only if the redirect_std* options are set
201    stdout_file = os.path.join(options.outdir, options.stdout_file)
202    stderr_file = os.path.join(options.outdir, options.stderr_file)
203
204    # Print redirection notices here before doing any redirection
205    if options.redirect_stdout and not options.redirect_stderr:
206        print "Redirecting stdout and stderr to", stdout_file
207    else:
208        if options.redirect_stdout:
209            print "Redirecting stdout to", stdout_file
210        if options.redirect_stderr:
211            print "Redirecting stderr to", stderr_file
212
213    # Now redirect stdout/stderr as desired
214    if options.redirect_stdout:
215        redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
216        os.dup2(redir_fd, sys.stdout.fileno())
217        if not options.redirect_stderr:
218            os.dup2(redir_fd, sys.stderr.fileno())
219
220    if options.redirect_stderr:
221        redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
222        os.dup2(redir_fd, sys.stderr.fileno())
223
224    done = False
225
226    if options.build_info:
227        done = True
228        print 'Build information:'
229        print
230        print 'compiled %s' % defines.compileDate;
231        print 'build options:'
232        keys = defines.buildEnv.keys()
233        keys.sort()
234        for key in keys:
235            val = defines.buildEnv[key]
236            print '    %s = %s' % (key, val)
237        print
238
239    if options.copyright:
240        done = True
241        print info.COPYING
242        print
243
244    if options.readme:
245        done = True
246        print 'Readme:'
247        print
248        print info.README
249        print
250
251    if options.debug_help:
252        done = True
253        check_tracing()
254        debug.help()
255
256    if options.list_sim_objects:
257        import SimObject
258        done = True
259        print "SimObjects:"
260        objects = SimObject.allClasses.keys()
261        objects.sort()
262        for name in objects:
263            obj = SimObject.allClasses[name]
264            print "    %s" % obj
265            params = obj._params.keys()
266            params.sort()
267            for pname in params:
268                param = obj._params[pname]
269                default = getattr(param, 'default', '')
270                print "        %s" % pname
271                if default:
272                    print "            default: %s" % default
273                print "            desc: %s" % param.desc
274                print
275            print
276
277    if done:
278        sys.exit(0)
279
280    # setting verbose and quiet at the same time doesn't make sense
281    if options.verbose > 0 and options.quiet > 0:
282        options.usage(2)
283
284    verbose = options.verbose - options.quiet
285    if verbose >= 0:
286        print "gem5 Simulator System.  http://gem5.org"
287        print brief_copyright
288        print
289
290        print "gem5 compiled %s" % defines.compileDate;
291
292        print "gem5 started %s" % \
293            datetime.datetime.now().strftime("%b %e %Y %X")
294        print "gem5 executing on %s, pid %d" % \
295            (socket.gethostname(), os.getpid())
296
297        # in Python 3 pipes.quote() is moved to shlex.quote()
298        import pipes
299        print "command line:", " ".join(map(pipes.quote, sys.argv))
300        print
301
302    # check to make sure we can find the listed script
303    if not arguments or not os.path.isfile(arguments[0]):
304        if arguments and not os.path.isfile(arguments[0]):
305            print "Script %s not found" % arguments[0]
306
307        options.usage(2)
308
309    # tell C++ about output directory
310    core.setOutputDir(options.outdir)
311
312    # update the system path with elements from the -p option
313    sys.path[0:0] = options.path
314
315    # set stats options
316    stats.initText(options.stats_file)
317
318    # set debugging options
319    debug.setRemoteGDBPort(options.remote_gdb_port)
320    for when in options.debug_break:
321        debug.schedBreak(int(when))
322
323    if options.debug_flags:
324        check_tracing()
325
326        on_flags = []
327        off_flags = []
328        for flag in options.debug_flags:
329            off = False
330            if flag.startswith('-'):
331                flag = flag[1:]
332                off = True
333
334            if flag not in debug.flags:
335                print >>sys.stderr, "invalid debug flag '%s'" % flag
336                sys.exit(1)
337
338            if off:
339                debug.flags[flag].disable()
340            else:
341                debug.flags[flag].enable()
342
343    if options.debug_start:
344        check_tracing()
345        e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
346        event.mainq.schedule(e, options.debug_start)
347    else:
348        trace.enable()
349
350    trace.output(options.debug_file)
351
352    for ignore in options.debug_ignore:
353        check_tracing()
354        trace.ignore(ignore)
355
356    sys.argv = arguments
357    sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
358
359    filename = sys.argv[0]
360    filedata = file(filename, 'r').read()
361    filecode = compile(filedata, filename, 'exec')
362    scope = { '__file__' : filename,
363              '__name__' : '__m5_main__' }
364
365    # we want readline if we're doing anything interactive
366    if options.interactive or options.pdb:
367        exec "import readline" in scope
368
369    # if pdb was requested, execfile the thing under pdb, otherwise,
370    # just do the execfile normally
371    if options.pdb:
372        import pdb
373        import traceback
374
375        pdb = pdb.Pdb()
376        try:
377            pdb.run(filecode, scope)
378        except SystemExit:
379            print "The program exited via sys.exit(). Exit status: ",
380            print sys.exc_info()[1]
381        except:
382            traceback.print_exc()
383            print "Uncaught exception. Entering post mortem debugging"
384            t = sys.exc_info()[2]
385            while t.tb_next is not None:
386                t = t.tb_next
387                pdb.interaction(t.tb_frame,t)
388    else:
389        exec filecode in scope
390
391    # once the script is done
392    if options.interactive:
393        interact(scope)
394
395if __name__ == '__main__':
396    from pprint import pprint
397
398    options, arguments = parse_options()
399
400    print 'opts:'
401    pprint(options, indent=4)
402    print
403
404    print 'args:'
405    pprint(arguments, indent=4)
406