blob: b216840df709ff0986755bcb2e8f8f2fc3f36989 [file] [log] [blame]
# Copyright (c) 2016, 2019 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2005 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import code
import datetime
import os
import socket
import sys
__all__ = [ 'options', 'arguments', 'main' ]
usage="%prog [gem5 options] script.py [script options]"
brief_copyright=\
"gem5 is copyrighted software; use the --copyright option for details."
def _stats_help(option, opt, value, parser):
import m5
print("A stat file can either be specified as a URI or a plain")
print("path. When specified as a path, gem5 uses the default text ")
print("format.")
print()
print("The following stat formats are supported:")
print()
m5.stats.printStatVisitorTypes()
sys.exit(0)
def parse_options():
from .options import OptionParser
options = OptionParser(usage=usage, description=brief_copyright)
option = options.add_option
group = options.set_group
listener_modes = ( "on", "off", "auto" )
# Help options
option('-B', "--build-info", action="store_true", default=False,
help="Show build information")
option('-C', "--copyright", action="store_true", default=False,
help="Show full copyright information")
option('-R', "--readme", action="store_true", default=False,
help="Show the readme")
# Options for configuring the base simulator
option('-d', "--outdir", metavar="DIR", default="m5out",
help="Set the output directory to DIR [Default: %default]")
option('-r', "--redirect-stdout", action="store_true", default=False,
help="Redirect stdout (& stderr, without -e) to file")
option('-e', "--redirect-stderr", action="store_true", default=False,
help="Redirect stderr to file")
option("--silent-redirect", action="store_true", default=False,
help="Suppress printing a message when redirecting stdout or stderr")
option("--stdout-file", metavar="FILE", default="simout",
help="Filename for -r redirection [Default: %default]")
option("--stderr-file", metavar="FILE", default="simerr",
help="Filename for -e redirection [Default: %default]")
option("--listener-mode", metavar="{on,off,auto}",
choices=listener_modes, default="auto",
help="Port (e.g., gdb) listener mode (auto: Enable if running " \
"interactively) [Default: %default]")
option("--allow-remote-connections", action="store_true", default=False,
help="Port listeners will accept connections from anywhere (0.0.0.0). "
"Default is only localhost.")
option('-i', "--interactive", action="store_true", default=False,
help="Invoke the interactive interpreter after running the script")
option("--pdb", action="store_true", default=False,
help="Invoke the python debugger before running the script")
option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
help="Prepend PATH to the system path when invoking the script")
option('-q', "--quiet", action="count", default=0,
help="Reduce verbosity")
option('-v', "--verbose", action="count", default=0,
help="Increase verbosity")
# Statistics options
group("Statistics Options")
option("--stats-file", metavar="FILE", default="stats.txt",
help="Sets the output file for statistics [Default: %default]")
option("--stats-help",
action="callback", callback=_stats_help,
help="Display documentation for available stat visitors")
# Configuration Options
group("Configuration Options")
option("--dump-config", metavar="FILE", default="config.ini",
help="Dump configuration output file [Default: %default]")
option("--json-config", metavar="FILE", default="config.json",
help="Create JSON output of the configuration [Default: %default]")
option("--dot-config", metavar="FILE", default="config.dot",
help="Create DOT & pdf outputs of the configuration [Default: %default]")
option("--dot-dvfs-config", metavar="FILE", default=None,
help="Create DOT & pdf outputs of the DVFS configuration" + \
" [Default: %default]")
# Debugging options
group("Debugging Options")
option("--debug-break", metavar="TICK[,TICK]", action='append', split=',',
help="Create breakpoint(s) at TICK(s) " \
"(kills process if no debugger attached)")
option("--debug-help", action='store_true',
help="Print help on debug flags")
option("--debug-flags", metavar="FLAG[,FLAG]", action='append', split=',',
help="Sets the flags for debug output (-FLAG disables a flag)")
option("--debug-start", metavar="TICK", type='int',
help="Start debug output at TICK")
option("--debug-end", metavar="TICK", type='int',
help="End debug output at TICK")
option("--debug-file", metavar="FILE", default="cout",
help="Sets the output file for debug. Append '.gz' to the name for it"
" to be compressed automatically [Default: %default]")
option("--debug-ignore", metavar="EXPR", action='append', split=':',
help="Ignore EXPR sim objects")
option("--remote-gdb-port", type='int', default=7000,
help="Remote gdb base port (set to 0 to disable listening)")
# Help options
group("Help Options")
option("--list-sim-objects", action='store_true', default=False,
help="List all built-in SimObjects, their params and default values")
arguments = options.parse_args()
return options,arguments
def interact(scope):
banner = "gem5 Interactive Console"
ipshell = None
prompt_in1 = "gem5 \\#> "
prompt_out = "gem5 \\#: "
try:
import IPython
from IPython.config.loader import Config
from IPython.terminal.embed import InteractiveShellEmbed
cfg = Config()
cfg.PromptManager.in_template = prompt_in1
cfg.PromptManager.out_template = prompt_out
ipshell = InteractiveShellEmbed(config=cfg, user_ns=scope,
banner1=banner)
except ImportError:
pass
if ipshell:
ipshell()
else:
# Use the Python shell in the standard library if IPython
# isn't available.
code.InteractiveConsole(scope).interact(banner)
def _check_tracing():
import _m5.core
if _m5.core.TRACING_ON:
return
fatal("Tracing is not enabled. Compile with TRACING_ON")
def main():
import m5
import _m5.core
from . import core
from . import debug
from . import defines
from . import event
from . import info
from . import stats
from . import trace
from .util import inform, fatal, panic, isInteractive
from m5.util.terminal_formatter import TerminalFormatter
options, arguments = parse_options()
m5.options = options
# Set the main event queue for the main thread.
event.mainq = event.getEventQueue(0)
event.setEventQueue(event.mainq)
if not os.path.isdir(options.outdir):
os.makedirs(options.outdir)
# These filenames are used only if the redirect_std* options are set
stdout_file = os.path.join(options.outdir, options.stdout_file)
stderr_file = os.path.join(options.outdir, options.stderr_file)
if not options.silent_redirect:
# Print redirection notices here before doing any redirection
if options.redirect_stdout and not options.redirect_stderr:
print("Redirecting stdout and stderr to", stdout_file)
else:
if options.redirect_stdout:
print("Redirecting stdout to", stdout_file)
if options.redirect_stderr:
print("Redirecting stderr to", stderr_file)
# Now redirect stdout/stderr as desired
if options.redirect_stdout:
redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
os.dup2(redir_fd, sys.stdout.fileno())
if not options.redirect_stderr:
os.dup2(redir_fd, sys.stderr.fileno())
if options.redirect_stderr:
redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
os.dup2(redir_fd, sys.stderr.fileno())
done = False
if options.build_info:
done = True
print('Build information:')
print()
print('gem5 version %s' % defines.gem5Version)
print('compiled %s' % defines.compileDate)
print('build options:')
keys = list(defines.buildEnv.keys())
keys.sort()
for key in keys:
val = defines.buildEnv[key]
print(' %s = %s' % (key, val))
print()
if options.copyright:
done = True
print(info.COPYING)
print()
if options.readme:
done = True
print('Readme:')
print()
print(info.README)
print()
if options.debug_help:
done = True
_check_tracing()
debug.help()
if options.list_sim_objects:
from . import SimObject
done = True
print("SimObjects:")
objects = list(SimObject.allClasses.keys())
objects.sort()
terminal_formatter = TerminalFormatter()
for name in objects:
obj = SimObject.allClasses[name]
print(terminal_formatter.format_output(str(obj), indent=4))
params = list(obj._params.keys())
params.sort()
for pname in params:
param = obj._params[pname]
default = getattr(param, 'default', '')
print(terminal_formatter.format_output(pname, indent=8))
if default:
print(terminal_formatter.format_output(
str(default), label="default: ", indent=21))
print(terminal_formatter.format_output(
param.desc, label="desc: ", indent=21))
print()
print()
if done:
sys.exit(0)
# setting verbose and quiet at the same time doesn't make sense
if options.verbose > 0 and options.quiet > 0:
options.usage(2)
verbose = options.verbose - options.quiet
if verbose >= 0:
print("gem5 Simulator System. https://www.gem5.org")
print(brief_copyright)
print()
print("gem5 version %s" % _m5.core.gem5Version)
print("gem5 compiled %s" % _m5.core.compileDate)
print("gem5 started %s" %
datetime.datetime.now().strftime("%b %e %Y %X"))
print("gem5 executing on %s, pid %d" %
(socket.gethostname(), os.getpid()))
# in Python 3 pipes.quote() is moved to shlex.quote()
import pipes
print("command line:", " ".join(map(pipes.quote, sys.argv)))
print()
# check to make sure we can find the listed script
if not arguments or not os.path.isfile(arguments[0]):
if arguments and not os.path.isfile(arguments[0]):
print("Script %s not found" % arguments[0])
options.usage(2)
# tell C++ about output directory
core.setOutputDir(options.outdir)
# update the system path with elements from the -p option
sys.path[0:0] = options.path
# set stats options
stats.addStatVisitor(options.stats_file)
# Disable listeners unless running interactively or explicitly
# enabled
if options.listener_mode == "off":
m5.disableAllListeners()
elif options.listener_mode == "auto":
if not isInteractive():
inform("Standard input is not a terminal, disabling listeners.")
m5.disableAllListeners()
elif options.listener_mode == "on":
pass
else:
panic("Unhandled listener mode: %s" % options.listener_mode)
if not options.allow_remote_connections:
m5.listenersLoopbackOnly()
# set debugging options
debug.setRemoteGDBPort(options.remote_gdb_port)
for when in options.debug_break:
debug.schedBreak(int(when))
if options.debug_flags:
_check_tracing()
on_flags = []
off_flags = []
for flag in options.debug_flags:
off = False
if flag.startswith('-'):
flag = flag[1:]
off = True
if flag not in debug.flags:
print("invalid debug flag '%s'" % flag, file=sys.stderr)
sys.exit(1)
if off:
debug.flags[flag].disable()
else:
debug.flags[flag].enable()
if options.debug_start:
_check_tracing()
e = event.create(trace.enable, event.Event.Debug_Enable_Pri)
event.mainq.schedule(e, options.debug_start)
else:
trace.enable()
if options.debug_end:
_check_tracing()
e = event.create(trace.disable, event.Event.Debug_Enable_Pri)
event.mainq.schedule(e, options.debug_end)
trace.output(options.debug_file)
for ignore in options.debug_ignore:
_check_tracing()
trace.ignore(ignore)
sys.argv = arguments
sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
filename = sys.argv[0]
filedata = open(filename, 'r').read()
filecode = compile(filedata, filename, 'exec')
scope = { '__file__' : filename,
'__name__' : '__m5_main__' }
# if pdb was requested, execfile the thing under pdb, otherwise,
# just do the execfile normally
if options.pdb:
import pdb
import traceback
pdb = pdb.Pdb()
try:
pdb.run(filecode, scope)
except SystemExit:
print("The program exited via sys.exit(). Exit status: ", end=' ')
print(sys.exc_info()[1])
except:
traceback.print_exc()
print("Uncaught exception. Entering post mortem debugging")
t = sys.exc_info()[2]
while t.tb_next is not None:
t = t.tb_next
pdb.interaction(t.tb_frame,t)
else:
exec(filecode, scope)
# once the script is done
if options.interactive:
interact(scope)