blob: 458e143a538dc317e8ecc4fc04fec1194a7a2c3d [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"
)
# To make gem5 mimic python better. After `-c` we should consume all other
# arguments and add those to argv.
def collect_args(option, opt_str, value, parser):
extra_args = parser.rargs[:]
del parser.rargs[:]
setattr(parser.values, option.dest, (value, extra_args))
option(
"-c",
type=str,
help="program passed in as string (terminates option list)",
default="",
metavar="cmd",
action="callback",
callback=collect_args,
)
# 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.
import readline # if this is imported, then the up arrow works
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 options.c and (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()
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
if options.c:
filedata = options.c[0]
filecode = compile(filedata, "<string>", "exec")
sys.argv = ["-c"] + options.c[1]
scope = {"__name__": "__m5_main__"}
else:
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)