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