main.py revision 11923:d2f0605ac2af
1# Copyright (c) 2016 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder.  You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2005 The Regents of The University of Michigan
14# All rights reserved.
15#
16# Redistribution and use in source and binary forms, with or without
17# modification, are permitted provided that the following conditions are
18# met: redistributions of source code must retain the above copyright
19# notice, this list of conditions and the following disclaimer;
20# redistributions in binary form must reproduce the above copyright
21# notice, this list of conditions and the following disclaimer in the
22# documentation and/or other materials provided with the distribution;
23# neither the name of the copyright holders nor the names of its
24# contributors may be used to endorse or promote products derived from
25# this software without specific prior written permission.
26#
27# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38#
39# Authors: Nathan Binkert
40
41import code
42import datetime
43import os
44import socket
45import sys
46
47__all__ = [ 'options', 'arguments', 'main' ]
48
49usage="%prog [gem5 options] script.py [script options]"
50version="%prog 2.0"
51brief_copyright=\
52    "gem5 is copyrighted software; use the --copyright option for details."
53
54def parse_options():
55    import config
56    from options import OptionParser
57
58    options = OptionParser(usage=usage, version=version,
59                           description=brief_copyright)
60    option = options.add_option
61    group = options.set_group
62
63    listener_modes = ( "on", "off", "auto" )
64
65    # Help options
66    option('-B', "--build-info", action="store_true", default=False,
67        help="Show build information")
68    option('-C', "--copyright", action="store_true", default=False,
69        help="Show full copyright information")
70    option('-R', "--readme", action="store_true", default=False,
71        help="Show the readme")
72
73    # Options for configuring the base simulator
74    option('-d', "--outdir", metavar="DIR", default="m5out",
75        help="Set the output directory to DIR [Default: %default]")
76    option('-r', "--redirect-stdout", action="store_true", default=False,
77        help="Redirect stdout (& stderr, without -e) to file")
78    option('-e', "--redirect-stderr", action="store_true", default=False,
79        help="Redirect stderr to file")
80    option("--stdout-file", metavar="FILE", default="simout",
81        help="Filename for -r redirection [Default: %default]")
82    option("--stderr-file", metavar="FILE", default="simerr",
83        help="Filename for -e redirection [Default: %default]")
84    option("--listener-mode", metavar="{on,off,auto}",
85        choices=listener_modes, default="auto",
86        help="Port (e.g., gdb) listener mode (auto: Enable if running " \
87        "interactively) [Default: %default]")
88    option('-i', "--interactive", action="store_true", default=False,
89        help="Invoke the interactive interpreter after running the script")
90    option("--pdb", action="store_true", default=False,
91        help="Invoke the python debugger before running the script")
92    option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
93        help="Prepend PATH to the system path when invoking the script")
94    option('-q', "--quiet", action="count", default=0,
95        help="Reduce verbosity")
96    option('-v', "--verbose", action="count", default=0,
97        help="Increase verbosity")
98
99    # Statistics options
100    group("Statistics Options")
101    option("--stats-file", metavar="FILE", default="stats.txt",
102        help="Sets the output file for statistics [Default: %default]")
103
104    # Configuration Options
105    group("Configuration Options")
106    option("--dump-config", metavar="FILE", default="config.ini",
107        help="Dump configuration output file [Default: %default]")
108    option("--json-config", metavar="FILE", default="config.json",
109        help="Create JSON output of the configuration [Default: %default]")
110    option("--dot-config", metavar="FILE", default="config.dot",
111        help="Create DOT & pdf outputs of the configuration [Default: %default]")
112    option("--dot-dvfs-config", metavar="FILE", default=None,
113        help="Create DOT & pdf outputs of the DVFS configuration" + \
114             " [Default: %default]")
115
116    # Debugging options
117    group("Debugging Options")
118    option("--debug-break", metavar="TICK[,TICK]", action='append', split=',',
119        help="Create breakpoint(s) at TICK(s) " \
120             "(kills process if no debugger attached)")
121    option("--debug-help", action='store_true',
122        help="Print help on debug flags")
123    option("--debug-flags", metavar="FLAG[,FLAG]", action='append', split=',',
124        help="Sets the flags for debug output (-FLAG disables a flag)")
125    option("--debug-start", metavar="TICK", type='int',
126        help="Start debug output at TICK")
127    option("--debug-end", metavar="TICK", type='int',
128        help="End debug output at TICK")
129    option("--debug-file", metavar="FILE", default="cout",
130        help="Sets the output file for debug [Default: %default]")
131    option("--debug-ignore", metavar="EXPR", action='append', split=':',
132        help="Ignore EXPR sim objects")
133    option("--remote-gdb-port", type='int', default=7000,
134        help="Remote gdb base port (set to 0 to disable listening)")
135
136    # Help options
137    group("Help Options")
138    option("--list-sim-objects", action='store_true', default=False,
139        help="List all built-in SimObjects, their params and default values")
140
141    # load the options.py config file to allow people to set their own
142    # default options
143    options_file = config.get('options.py')
144    if options_file:
145        scope = { 'options' : options }
146        execfile(options_file, scope)
147
148    arguments = options.parse_args()
149    return options,arguments
150
151def interact(scope):
152    banner = "gem5 Interactive Console"
153
154    ipshell = None
155    prompt_in1 = "gem5 \\#> "
156    prompt_out = "gem5 \\#: "
157
158    # Is IPython version 0.10 or earlier available?
159    try:
160        from IPython.Shell import IPShellEmbed
161        ipshell = IPShellEmbed(argv=["-prompt_in1", prompt_in1,
162                                     "-prompt_out", prompt_out],
163                               banner=banner, user_ns=scope)
164    except ImportError:
165        pass
166
167    # Is IPython version 0.11 or later available?
168    if not ipshell:
169        try:
170            import IPython
171            from IPython.config.loader import Config
172            from IPython.terminal.embed import InteractiveShellEmbed
173
174            cfg = Config()
175            cfg.PromptManager.in_template = prompt_in1
176            cfg.PromptManager.out_template = prompt_out
177            ipshell = InteractiveShellEmbed(config=cfg, user_ns=scope,
178                                            banner1=banner)
179        except ImportError:
180            pass
181
182    if ipshell:
183        ipshell()
184    else:
185        # Use the Python shell in the standard library if IPython
186        # isn't available.
187        code.InteractiveConsole(scope).interact(banner)
188
189def main(*args):
190    import m5
191
192    import core
193    import debug
194    import defines
195    import event
196    import info
197    import stats
198    import trace
199
200    from util import inform, fatal, panic, isInteractive
201
202    if len(args) == 0:
203        options, arguments = parse_options()
204    elif len(args) == 2:
205        options, arguments = args
206    else:
207        raise TypeError, "main() takes 0 or 2 arguments (%d given)" % len(args)
208
209    m5.options = options
210
211    def check_tracing():
212        if defines.TRACING_ON:
213            return
214
215        fatal("Tracing is not enabled.  Compile with TRACING_ON")
216
217    # Set the main event queue for the main thread.
218    event.mainq = event.getEventQueue(0)
219    event.setEventQueue(event.mainq)
220
221    if not os.path.isdir(options.outdir):
222        os.makedirs(options.outdir)
223
224    # These filenames are used only if the redirect_std* options are set
225    stdout_file = os.path.join(options.outdir, options.stdout_file)
226    stderr_file = os.path.join(options.outdir, options.stderr_file)
227
228    # Print redirection notices here before doing any redirection
229    if options.redirect_stdout and not options.redirect_stderr:
230        print "Redirecting stdout and stderr to", stdout_file
231    else:
232        if options.redirect_stdout:
233            print "Redirecting stdout to", stdout_file
234        if options.redirect_stderr:
235            print "Redirecting stderr to", stderr_file
236
237    # Now redirect stdout/stderr as desired
238    if options.redirect_stdout:
239        redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
240        os.dup2(redir_fd, sys.stdout.fileno())
241        if not options.redirect_stderr:
242            os.dup2(redir_fd, sys.stderr.fileno())
243
244    if options.redirect_stderr:
245        redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
246        os.dup2(redir_fd, sys.stderr.fileno())
247
248    done = False
249
250    if options.build_info:
251        done = True
252        print 'Build information:'
253        print
254        print 'compiled %s' % defines.compileDate;
255        print 'build options:'
256        keys = defines.buildEnv.keys()
257        keys.sort()
258        for key in keys:
259            val = defines.buildEnv[key]
260            print '    %s = %s' % (key, val)
261        print
262
263    if options.copyright:
264        done = True
265        print info.COPYING
266        print
267
268    if options.readme:
269        done = True
270        print 'Readme:'
271        print
272        print info.README
273        print
274
275    if options.debug_help:
276        done = True
277        check_tracing()
278        debug.help()
279
280    if options.list_sim_objects:
281        import SimObject
282        done = True
283        print "SimObjects:"
284        objects = SimObject.allClasses.keys()
285        objects.sort()
286        for name in objects:
287            obj = SimObject.allClasses[name]
288            print "    %s" % obj
289            params = obj._params.keys()
290            params.sort()
291            for pname in params:
292                param = obj._params[pname]
293                default = getattr(param, 'default', '')
294                print "        %s" % pname
295                if default:
296                    print "            default: %s" % default
297                print "            desc: %s" % param.desc
298                print
299            print
300
301    if done:
302        sys.exit(0)
303
304    # setting verbose and quiet at the same time doesn't make sense
305    if options.verbose > 0 and options.quiet > 0:
306        options.usage(2)
307
308    verbose = options.verbose - options.quiet
309    if verbose >= 0:
310        print "gem5 Simulator System.  http://gem5.org"
311        print brief_copyright
312        print
313
314        print "gem5 compiled %s" % defines.compileDate;
315
316        print "gem5 started %s" % \
317            datetime.datetime.now().strftime("%b %e %Y %X")
318        print "gem5 executing on %s, pid %d" % \
319            (socket.gethostname(), os.getpid())
320
321        # in Python 3 pipes.quote() is moved to shlex.quote()
322        import pipes
323        print "command line:", " ".join(map(pipes.quote, sys.argv))
324        print
325
326    # check to make sure we can find the listed script
327    if not arguments or not os.path.isfile(arguments[0]):
328        if arguments and not os.path.isfile(arguments[0]):
329            print "Script %s not found" % arguments[0]
330
331        options.usage(2)
332
333    # tell C++ about output directory
334    core.setOutputDir(options.outdir)
335
336    # update the system path with elements from the -p option
337    sys.path[0:0] = options.path
338
339    # set stats options
340    stats.addStatVisitor(options.stats_file)
341
342    # Disable listeners unless running interactively or explicitly
343    # enabled
344    if options.listener_mode == "off":
345        m5.disableAllListeners()
346    elif options.listener_mode == "auto":
347        if not isInteractive():
348            inform("Standard input is not a terminal, disabling listeners.")
349            m5.disableAllListeners()
350    elif options.listener_mode == "on":
351        pass
352    else:
353        panic("Unhandled listener mode: %s" % options.listener_mode)
354
355    # set debugging options
356    debug.setRemoteGDBPort(options.remote_gdb_port)
357    for when in options.debug_break:
358        debug.schedBreak(int(when))
359
360    if options.debug_flags:
361        check_tracing()
362
363        on_flags = []
364        off_flags = []
365        for flag in options.debug_flags:
366            off = False
367            if flag.startswith('-'):
368                flag = flag[1:]
369                off = True
370
371            if flag not in debug.flags:
372                print >>sys.stderr, "invalid debug flag '%s'" % flag
373                sys.exit(1)
374
375            if off:
376                debug.flags[flag].disable()
377            else:
378                debug.flags[flag].enable()
379
380    if options.debug_start:
381        check_tracing()
382        e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
383        event.mainq.schedule(e, options.debug_start)
384    else:
385        trace.enable()
386
387    if options.debug_end:
388        check_tracing()
389        e = event.create(trace.disable, event.Event.Debug_Enable_Pri)
390        event.mainq.schedule(e, options.debug_end)
391
392    trace.output(options.debug_file)
393
394    for ignore in options.debug_ignore:
395        check_tracing()
396        trace.ignore(ignore)
397
398    sys.argv = arguments
399    sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
400
401    filename = sys.argv[0]
402    filedata = file(filename, 'r').read()
403    filecode = compile(filedata, filename, 'exec')
404    scope = { '__file__' : filename,
405              '__name__' : '__m5_main__' }
406
407    # we want readline if we're doing anything interactive
408    if options.interactive or options.pdb:
409        exec "import readline" in scope
410
411    # if pdb was requested, execfile the thing under pdb, otherwise,
412    # just do the execfile normally
413    if options.pdb:
414        import pdb
415        import traceback
416
417        pdb = pdb.Pdb()
418        try:
419            pdb.run(filecode, scope)
420        except SystemExit:
421            print "The program exited via sys.exit(). Exit status: ",
422            print sys.exc_info()[1]
423        except:
424            traceback.print_exc()
425            print "Uncaught exception. Entering post mortem debugging"
426            t = sys.exc_info()[2]
427            while t.tb_next is not None:
428                t = t.tb_next
429                pdb.interaction(t.tb_frame,t)
430    else:
431        exec filecode in scope
432
433    # once the script is done
434    if options.interactive:
435        interact(scope)
436
437if __name__ == '__main__':
438    from pprint import pprint
439
440    options, arguments = parse_options()
441
442    print 'opts:'
443    pprint(options, indent=4)
444    print
445
446    print 'args:'
447    pprint(arguments, indent=4)
448