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