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