main.py revision 12033:2e805c6168ce
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("--listener-loopback-only", action="store_true", default=False,
89        help="Port listeners will only accept connections over the " \
90        "loopback device")
91    option('-i', "--interactive", action="store_true", default=False,
92        help="Invoke the interactive interpreter after running the script")
93    option("--pdb", action="store_true", default=False,
94        help="Invoke the python debugger before running the script")
95    option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
96        help="Prepend PATH to the system path when invoking the script")
97    option('-q', "--quiet", action="count", default=0,
98        help="Reduce verbosity")
99    option('-v', "--verbose", action="count", default=0,
100        help="Increase verbosity")
101
102    # Statistics options
103    group("Statistics Options")
104    option("--stats-file", metavar="FILE", default="stats.txt",
105        help="Sets the output file for statistics [Default: %default]")
106
107    # Configuration Options
108    group("Configuration Options")
109    option("--dump-config", metavar="FILE", default="config.ini",
110        help="Dump configuration output file [Default: %default]")
111    option("--json-config", metavar="FILE", default="config.json",
112        help="Create JSON output of the configuration [Default: %default]")
113    option("--dot-config", metavar="FILE", default="config.dot",
114        help="Create DOT & pdf outputs of the configuration [Default: %default]")
115    option("--dot-dvfs-config", metavar="FILE", default=None,
116        help="Create DOT & pdf outputs of the DVFS configuration" + \
117             " [Default: %default]")
118
119    # Debugging options
120    group("Debugging Options")
121    option("--debug-break", metavar="TICK[,TICK]", action='append', split=',',
122        help="Create breakpoint(s) at TICK(s) " \
123             "(kills process if no debugger attached)")
124    option("--debug-help", action='store_true',
125        help="Print help on debug flags")
126    option("--debug-flags", metavar="FLAG[,FLAG]", action='append', split=',',
127        help="Sets the flags for debug output (-FLAG disables a flag)")
128    option("--debug-start", metavar="TICK", type='int',
129        help="Start debug output at TICK")
130    option("--debug-end", metavar="TICK", type='int',
131        help="End debug output at TICK")
132    option("--debug-file", metavar="FILE", default="cout",
133        help="Sets the output file for debug [Default: %default]")
134    option("--debug-ignore", metavar="EXPR", action='append', split=':',
135        help="Ignore EXPR sim objects")
136    option("--remote-gdb-port", type='int', default=7000,
137        help="Remote gdb base port (set to 0 to disable listening)")
138
139    # Help options
140    group("Help Options")
141    option("--list-sim-objects", action='store_true', default=False,
142        help="List all built-in SimObjects, their params and default values")
143
144    # load the options.py config file to allow people to set their own
145    # default options
146    options_file = config.get('options.py')
147    if options_file:
148        scope = { 'options' : options }
149        execfile(options_file, scope)
150
151    arguments = options.parse_args()
152    return options,arguments
153
154def interact(scope):
155    banner = "gem5 Interactive Console"
156
157    ipshell = None
158    prompt_in1 = "gem5 \\#> "
159    prompt_out = "gem5 \\#: "
160
161    # Is IPython version 0.10 or earlier available?
162    try:
163        from IPython.Shell import IPShellEmbed
164        ipshell = IPShellEmbed(argv=["-prompt_in1", prompt_in1,
165                                     "-prompt_out", prompt_out],
166                               banner=banner, user_ns=scope)
167    except ImportError:
168        pass
169
170    # Is IPython version 0.11 or later available?
171    if not ipshell:
172        try:
173            import IPython
174            from IPython.config.loader import Config
175            from IPython.terminal.embed import InteractiveShellEmbed
176
177            cfg = Config()
178            cfg.PromptManager.in_template = prompt_in1
179            cfg.PromptManager.out_template = prompt_out
180            ipshell = InteractiveShellEmbed(config=cfg, user_ns=scope,
181                                            banner1=banner)
182        except ImportError:
183            pass
184
185    if ipshell:
186        ipshell()
187    else:
188        # Use the Python shell in the standard library if IPython
189        # isn't available.
190        code.InteractiveConsole(scope).interact(banner)
191
192def main(*args):
193    import m5
194
195    import core
196    import debug
197    import defines
198    import event
199    import info
200    import stats
201    import trace
202
203    from util import inform, fatal, panic, isInteractive
204
205    if len(args) == 0:
206        options, arguments = parse_options()
207    elif len(args) == 2:
208        options, arguments = args
209    else:
210        raise TypeError, "main() takes 0 or 2 arguments (%d given)" % len(args)
211
212    m5.options = options
213
214    def check_tracing():
215        if defines.TRACING_ON:
216            return
217
218        fatal("Tracing is not enabled.  Compile with TRACING_ON")
219
220    # Set the main event queue for the main thread.
221    event.mainq = event.getEventQueue(0)
222    event.setEventQueue(event.mainq)
223
224    if not os.path.isdir(options.outdir):
225        os.makedirs(options.outdir)
226
227    # These filenames are used only if the redirect_std* options are set
228    stdout_file = os.path.join(options.outdir, options.stdout_file)
229    stderr_file = os.path.join(options.outdir, options.stderr_file)
230
231    # Print redirection notices here before doing any redirection
232    if options.redirect_stdout and not options.redirect_stderr:
233        print "Redirecting stdout and stderr to", stdout_file
234    else:
235        if options.redirect_stdout:
236            print "Redirecting stdout to", stdout_file
237        if options.redirect_stderr:
238            print "Redirecting stderr to", stderr_file
239
240    # Now redirect stdout/stderr as desired
241    if options.redirect_stdout:
242        redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
243        os.dup2(redir_fd, sys.stdout.fileno())
244        if not options.redirect_stderr:
245            os.dup2(redir_fd, sys.stderr.fileno())
246
247    if options.redirect_stderr:
248        redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
249        os.dup2(redir_fd, sys.stderr.fileno())
250
251    done = False
252
253    if options.build_info:
254        done = True
255        print 'Build information:'
256        print
257        print 'compiled %s' % defines.compileDate;
258        print 'build options:'
259        keys = defines.buildEnv.keys()
260        keys.sort()
261        for key in keys:
262            val = defines.buildEnv[key]
263            print '    %s = %s' % (key, val)
264        print
265
266    if options.copyright:
267        done = True
268        print info.COPYING
269        print
270
271    if options.readme:
272        done = True
273        print 'Readme:'
274        print
275        print info.README
276        print
277
278    if options.debug_help:
279        done = True
280        check_tracing()
281        debug.help()
282
283    if options.list_sim_objects:
284        import SimObject
285        done = True
286        print "SimObjects:"
287        objects = SimObject.allClasses.keys()
288        objects.sort()
289        for name in objects:
290            obj = SimObject.allClasses[name]
291            print "    %s" % obj
292            params = obj._params.keys()
293            params.sort()
294            for pname in params:
295                param = obj._params[pname]
296                default = getattr(param, 'default', '')
297                print "        %s" % pname
298                if default:
299                    print "            default: %s" % default
300                print "            desc: %s" % param.desc
301                print
302            print
303
304    if done:
305        sys.exit(0)
306
307    # setting verbose and quiet at the same time doesn't make sense
308    if options.verbose > 0 and options.quiet > 0:
309        options.usage(2)
310
311    verbose = options.verbose - options.quiet
312    if verbose >= 0:
313        print "gem5 Simulator System.  http://gem5.org"
314        print brief_copyright
315        print
316
317        print "gem5 compiled %s" % defines.compileDate;
318
319        print "gem5 started %s" % \
320            datetime.datetime.now().strftime("%b %e %Y %X")
321        print "gem5 executing on %s, pid %d" % \
322            (socket.gethostname(), os.getpid())
323
324        # in Python 3 pipes.quote() is moved to shlex.quote()
325        import pipes
326        print "command line:", " ".join(map(pipes.quote, sys.argv))
327        print
328
329    # check to make sure we can find the listed script
330    if not arguments or not os.path.isfile(arguments[0]):
331        if arguments and not os.path.isfile(arguments[0]):
332            print "Script %s not found" % arguments[0]
333
334        options.usage(2)
335
336    # tell C++ about output directory
337    core.setOutputDir(options.outdir)
338
339    # update the system path with elements from the -p option
340    sys.path[0:0] = options.path
341
342    # set stats options
343    stats.addStatVisitor(options.stats_file)
344
345    # Disable listeners unless running interactively or explicitly
346    # enabled
347    if options.listener_mode == "off":
348        m5.disableAllListeners()
349    elif options.listener_mode == "auto":
350        if not isInteractive():
351            inform("Standard input is not a terminal, disabling listeners.")
352            m5.disableAllListeners()
353    elif options.listener_mode == "on":
354        pass
355    else:
356        panic("Unhandled listener mode: %s" % options.listener_mode)
357
358    if options.listener_loopback_only:
359        m5.listenersLoopbackOnly()
360
361    # set debugging options
362    debug.setRemoteGDBPort(options.remote_gdb_port)
363    for when in options.debug_break:
364        debug.schedBreak(int(when))
365
366    if options.debug_flags:
367        check_tracing()
368
369        on_flags = []
370        off_flags = []
371        for flag in options.debug_flags:
372            off = False
373            if flag.startswith('-'):
374                flag = flag[1:]
375                off = True
376
377            if flag not in debug.flags:
378                print >>sys.stderr, "invalid debug flag '%s'" % flag
379                sys.exit(1)
380
381            if off:
382                debug.flags[flag].disable()
383            else:
384                debug.flags[flag].enable()
385
386    if options.debug_start:
387        check_tracing()
388        e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
389        event.mainq.schedule(e, options.debug_start)
390    else:
391        trace.enable()
392
393    if options.debug_end:
394        check_tracing()
395        e = event.create(trace.disable, event.Event.Debug_Enable_Pri)
396        event.mainq.schedule(e, options.debug_end)
397
398    trace.output(options.debug_file)
399
400    for ignore in options.debug_ignore:
401        check_tracing()
402        trace.ignore(ignore)
403
404    sys.argv = arguments
405    sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
406
407    filename = sys.argv[0]
408    filedata = file(filename, 'r').read()
409    filecode = compile(filedata, filename, 'exec')
410    scope = { '__file__' : filename,
411              '__name__' : '__m5_main__' }
412
413    # if pdb was requested, execfile the thing under pdb, otherwise,
414    # just do the execfile normally
415    if options.pdb:
416        import pdb
417        import traceback
418
419        pdb = pdb.Pdb()
420        try:
421            pdb.run(filecode, scope)
422        except SystemExit:
423            print "The program exited via sys.exit(). Exit status: ",
424            print sys.exc_info()[1]
425        except:
426            traceback.print_exc()
427            print "Uncaught exception. Entering post mortem debugging"
428            t = sys.exc_info()[2]
429            while t.tb_next is not None:
430                t = t.tb_next
431                pdb.interaction(t.tb_frame,t)
432    else:
433        exec filecode in scope
434
435    # once the script is done
436    if options.interactive:
437        interact(scope)
438
439if __name__ == '__main__':
440    from pprint import pprint
441
442    options, arguments = parse_options()
443
444    print 'opts:'
445    pprint(options, indent=4)
446    print
447
448    print 'args:'
449    pprint(arguments, indent=4)
450