main.py revision 13714
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    from . 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    from . import core
207    from . import debug
208    from . import defines
209    from . import event
210    from . import info
211    from . import stats
212    from . 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        from . 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