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