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