main.py revision 13709
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    import defines
197
198    if defines.TRACING_ON:
199        return
200
201    fatal("Tracing is not enabled.  Compile with TRACING_ON")
202
203def main(*args):
204    import m5
205
206    import core
207    import debug
208    import defines
209    import event
210    import info
211    import stats
212    import trace
213
214    from util import inform, fatal, panic, isInteractive
215
216    if len(args) == 0:
217        options, arguments = parse_options()
218    elif len(args) == 2:
219        options, arguments = args
220    else:
221        raise TypeError("main() takes 0 or 2 arguments (%d given)" % len(args))
222
223    m5.options = options
224
225    # Set the main event queue for the main thread.
226    event.mainq = event.getEventQueue(0)
227    event.setEventQueue(event.mainq)
228
229    if not os.path.isdir(options.outdir):
230        os.makedirs(options.outdir)
231
232    # These filenames are used only if the redirect_std* options are set
233    stdout_file = os.path.join(options.outdir, options.stdout_file)
234    stderr_file = os.path.join(options.outdir, options.stderr_file)
235
236    # Print redirection notices here before doing any redirection
237    if options.redirect_stdout and not options.redirect_stderr:
238        print("Redirecting stdout and stderr to", stdout_file)
239    else:
240        if options.redirect_stdout:
241            print("Redirecting stdout to", stdout_file)
242        if options.redirect_stderr:
243            print("Redirecting stderr to", stderr_file)
244
245    # Now redirect stdout/stderr as desired
246    if options.redirect_stdout:
247        redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
248        os.dup2(redir_fd, sys.stdout.fileno())
249        if not options.redirect_stderr:
250            os.dup2(redir_fd, sys.stderr.fileno())
251
252    if options.redirect_stderr:
253        redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
254        os.dup2(redir_fd, sys.stderr.fileno())
255
256    done = False
257
258    if options.build_info:
259        done = True
260        print('Build information:')
261        print()
262        print('compiled %s' % defines.compileDate)
263        print('build options:')
264        keys = list(defines.buildEnv.keys())
265        keys.sort()
266        for key in keys:
267            val = defines.buildEnv[key]
268            print('    %s = %s' % (key, val))
269        print()
270
271    if options.copyright:
272        done = True
273        print(info.COPYING)
274        print()
275
276    if options.readme:
277        done = True
278        print('Readme:')
279        print()
280        print(info.README)
281        print()
282
283    if options.debug_help:
284        done = True
285        _check_tracing()
286        debug.help()
287
288    if options.list_sim_objects:
289        import SimObject
290        done = True
291        print("SimObjects:")
292        objects = list(SimObject.allClasses.keys())
293        objects.sort()
294        for name in objects:
295            obj = SimObject.allClasses[name]
296            print("    %s" % obj)
297            params = list(obj._params.keys())
298            params.sort()
299            for pname in params:
300                param = obj._params[pname]
301                default = getattr(param, 'default', '')
302                print("        %s" % pname)
303                if default:
304                    print("            default: %s" % default)
305                print("            desc: %s" % param.desc)
306                print()
307            print()
308
309    if done:
310        sys.exit(0)
311
312    # setting verbose and quiet at the same time doesn't make sense
313    if options.verbose > 0 and options.quiet > 0:
314        options.usage(2)
315
316    verbose = options.verbose - options.quiet
317    if verbose >= 0:
318        print("gem5 Simulator System.  http://gem5.org")
319        print(brief_copyright)
320        print()
321
322        print("gem5 compiled %s" % defines.compileDate)
323
324        print("gem5 started %s" %
325              datetime.datetime.now().strftime("%b %e %Y %X"))
326        print("gem5 executing on %s, pid %d" %
327              (socket.gethostname(), os.getpid()))
328
329        # in Python 3 pipes.quote() is moved to shlex.quote()
330        import pipes
331        print("command line:", " ".join(map(pipes.quote, sys.argv)))
332        print()
333
334    # check to make sure we can find the listed script
335    if not arguments or not os.path.isfile(arguments[0]):
336        if arguments and not os.path.isfile(arguments[0]):
337            print("Script %s not found" % arguments[0])
338
339        options.usage(2)
340
341    # tell C++ about output directory
342    core.setOutputDir(options.outdir)
343
344    # update the system path with elements from the -p option
345    sys.path[0:0] = options.path
346
347    # set stats options
348    stats.addStatVisitor(options.stats_file)
349
350    # Disable listeners unless running interactively or explicitly
351    # enabled
352    if options.listener_mode == "off":
353        m5.disableAllListeners()
354    elif options.listener_mode == "auto":
355        if not isInteractive():
356            inform("Standard input is not a terminal, disabling listeners.")
357            m5.disableAllListeners()
358    elif options.listener_mode == "on":
359        pass
360    else:
361        panic("Unhandled listener mode: %s" % options.listener_mode)
362
363    if options.listener_loopback_only:
364        m5.listenersLoopbackOnly()
365
366    # set debugging options
367    debug.setRemoteGDBPort(options.remote_gdb_port)
368    for when in options.debug_break:
369        debug.schedBreak(int(when))
370
371    if options.debug_flags:
372        _check_tracing()
373
374        on_flags = []
375        off_flags = []
376        for flag in options.debug_flags:
377            off = False
378            if flag.startswith('-'):
379                flag = flag[1:]
380                off = True
381
382            if flag not in debug.flags:
383                print("invalid debug flag '%s'" % flag, file=sys.stderr)
384                sys.exit(1)
385
386            if off:
387                debug.flags[flag].disable()
388            else:
389                debug.flags[flag].enable()
390
391    if options.debug_start:
392        _check_tracing()
393        e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
394        event.mainq.schedule(e, options.debug_start)
395    else:
396        trace.enable()
397
398    if options.debug_end:
399        _check_tracing()
400        e = event.create(trace.disable, event.Event.Debug_Enable_Pri)
401        event.mainq.schedule(e, options.debug_end)
402
403    trace.output(options.debug_file)
404
405    for ignore in options.debug_ignore:
406        _check_tracing()
407        trace.ignore(ignore)
408
409    sys.argv = arguments
410    sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
411
412    filename = sys.argv[0]
413    filedata = open(filename, 'r').read()
414    filecode = compile(filedata, filename, 'exec')
415    scope = { '__file__' : filename,
416              '__name__' : '__m5_main__' }
417
418    # if pdb was requested, execfile the thing under pdb, otherwise,
419    # just do the execfile normally
420    if options.pdb:
421        import pdb
422        import traceback
423
424        pdb = pdb.Pdb()
425        try:
426            pdb.run(filecode, scope)
427        except SystemExit:
428            print("The program exited via sys.exit(). Exit status: ", end=' ')
429            print(sys.exc_info()[1])
430        except:
431            traceback.print_exc()
432            print("Uncaught exception. Entering post mortem debugging")
433            t = sys.exc_info()[2]
434            while t.tb_next is not None:
435                t = t.tb_next
436                pdb.interaction(t.tb_frame,t)
437    else:
438        exec(filecode, scope)
439
440    # once the script is done
441    if options.interactive:
442        interact(scope)
443
444if __name__ == '__main__':
445    from pprint import pprint
446
447    options, arguments = parse_options()
448
449    print('opts:')
450    pprint(options, indent=4)
451    print()
452
453    print('args:')
454    pprint(arguments, indent=4)
455