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