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