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