1/* 2 * Copyright (c) 2000-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Raasch 29 * Nathan Binkert 30 * Steve Reinhardt 31 */ 32 33/// 34/// @file sim/main.cc 35/// 36#include <Python.h> // must be before system headers... see Python docs 37 38#include <sys/types.h> 39#include <sys/stat.h> 40#include <errno.h> 41#include <libgen.h> 42#include <stdlib.h> 43#include <signal.h> 44#include <getopt.h> 45 46#include <list> 47#include <string> 48#include <vector> 49 50#include "base/callback.hh" 51#include "base/inifile.hh" 52#include "base/misc.hh" 53#include "base/output.hh" 54#include "base/pollevent.hh" 55#include "base/statistics.hh" 56#include "base/str.hh" 57#include "base/time.hh" 58#include "cpu/base.hh" 59#include "cpu/smt.hh" 60#include "mem/mem_object.hh" 61#include "mem/port.hh" 62#include "sim/async.hh" 63#include "sim/builder.hh" 64#include "sim/host.hh" 65#include "sim/sim_events.hh" 66#include "sim/sim_exit.hh" 67#include "sim/sim_object.hh" 68#include "sim/stat_control.hh" 69#include "sim/stats.hh" 70#include "sim/root.hh" 71 72using namespace std; 73 74// See async.h. 75volatile bool async_event = false; 76volatile bool async_dump = false; 77volatile bool async_dumpreset = false; 78volatile bool async_exit = false; 79volatile bool async_io = false; 80volatile bool async_alarm = false; 81 82/// Stats signal handler. 83void 84dumpStatsHandler(int sigtype) 85{ 86 async_event = true; 87 async_dump = true; 88} 89 90void 91dumprstStatsHandler(int sigtype) 92{ 93 async_event = true; 94 async_dumpreset = true; 95} 96 97/// Exit signal handler. 98void 99exitNowHandler(int sigtype) 100{ 101 async_event = true; 102 async_exit = true; 103} 104 105/// Abort signal handler. 106void 107abortHandler(int sigtype) 108{ 109 cerr << "Program aborted at cycle " << curTick << endl; 110 111#if TRACING_ON 112 // dump trace buffer, if there is one 113 Trace::theLog.dump(cerr); 114#endif 115} 116 117/// Simulator executable name 118char *myProgName = ""; 119 120/// Show brief help message. 121void 122showBriefHelp(ostream &out) 123{ 124 char *prog = basename(myProgName); 125 126 ccprintf(out, "Usage:\n"); 127 ccprintf(out, 128"%s [-p <path>] [-i ] [-h] <config file>\n" 129"\n" 130" -p, --path <path> prepends <path> to PYTHONPATH instead of using\n" 131" built-in zip archive. Useful when developing/debugging\n" 132" changes to built-in Python libraries, as the new Python\n" 133" can be tested without building a new m5 binary.\n\n" 134" -i, --interactive forces entry into interactive mode after the supplied\n" 135" script is executed (just like the -i option to the\n" 136" Python interpreter).\n\n" 137" -h Prints this help\n\n" 138" <configfile> config file name (ends in .py)\n\n", 139 prog); 140 141} 142 143const char *briefCopyright = 144"Copyright (c) 2001-2006\n" 145"The Regents of The University of Michigan\n" 146"All Rights Reserved\n"; 147 148/// Print welcome message. 149void 150sayHello(ostream &out) 151{ 152 extern const char *compileDate; // from date.cc 153 154 ccprintf(out, "M5 Simulator System\n"); 155 // display copyright 156 ccprintf(out, "%s\n", briefCopyright); 157 ccprintf(out, "M5 compiled %d\n", compileDate); 158 ccprintf(out, "M5 started %s\n", Time::start); 159 160 char *host = getenv("HOSTNAME"); 161 if (!host) 162 host = getenv("HOST"); 163 164 if (host) 165 ccprintf(out, "M5 executing on %s\n", host); 166} 167 168
|
169extern "C" { void init_main(); }
|
169extern "C" { void init_cc_main(); } |
170 171int 172main(int argc, char **argv) 173{ 174 // Saze off program name 175 myProgName = argv[0]; 176 177 sayHello(cerr); 178 179 signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 180 signal(SIGTRAP, SIG_IGN); 181 signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 182 signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 183 signal(SIGINT, exitNowHandler); // dump final stats and exit 184 signal(SIGABRT, abortHandler); 185 186 Py_SetProgramName(argv[0]); 187 188 // default path to m5 python code is the currently executing 189 // file... Python ZipImporter will find embedded zip archive 190 char *pythonpath = argv[0]; 191 192 bool interactive = false; 193 bool show_help = false; 194 bool getopt_done = false; 195 int opt_index = 0; 196 197 static struct option long_options[] = { 198 {"python", 1, 0, 'p'}, 199 {"interactive", 0, 0, 'i'}, 200 {"help", 0, 0, 'h'}, 201 {0,0,0,0} 202 }; 203 204 do { 205 switch (getopt_long(argc, argv, "+p:ih", long_options, &opt_index)) { 206 // -p <path> prepends <path> to PYTHONPATH instead of 207 // using built-in zip archive. Useful when 208 // developing/debugging changes to built-in Python 209 // libraries, as the new Python can be tested without 210 // building a new m5 binary. 211 case 'p': 212 pythonpath = optarg; 213 break; 214 215 // -i forces entry into interactive mode after the 216 // supplied script is executed (just like the -i option to 217 // the Python interpreter). 218 case 'i': 219 interactive = true; 220 break; 221 222 case 'h': 223 show_help = true; 224 break; 225 case -1: 226 getopt_done = true; 227 break; 228 229 default: 230 fatal("Unrecognized option %c\n", optopt); 231 } 232 } while (!getopt_done); 233 234 if (show_help) { 235 showBriefHelp(cerr); 236 exit(1); 237 } 238 239 // Fix up argc & argv to hide arguments we just processed. 240 // getopt() sets optind to the index of the first non-processed 241 // argv element. 242 argc -= optind; 243 argv += optind; 244 245 // Set up PYTHONPATH to make sure the m5 module is found 246 string newpath(pythonpath); 247 248 char *oldpath = getenv("PYTHONPATH"); 249 if (oldpath != NULL) { 250 newpath += ":"; 251 newpath += oldpath; 252 } 253 254 if (setenv("PYTHONPATH", newpath.c_str(), true) == -1) 255 fatal("setenv: %s\n", strerror(errno)); 256 257 // initialize embedded Python interpreter 258 Py_Initialize(); 259 PySys_SetArgv(argc, argv); 260
|
261 // initialize SWIG 'main' module
262 init_main();
|
261 // initialize SWIG 'cc_main' module 262 init_cc_main(); |
263 264 if (argc > 0) { 265 // extra arg(s): first is script file, remaining ones are args 266 // to script file 267 char *filename = argv[0]; 268 FILE *fp = fopen(filename, "r"); 269 if (!fp) { 270 fatal("cannot open file '%s'\n", filename); 271 } 272 273 PyRun_AnyFile(fp, filename); 274 } else { 275 // no script file argument... force interactive prompt 276 interactive = true; 277 } 278 279 if (interactive) { 280 // The following code to import readline was copied from Python 281 // 2.4.3's Modules/main.c. 282 // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 283 // Python Software Foundation; All Rights Reserved 284 // We should only enable this if we're actually using an 285 // interactive prompt. 286 PyObject *v; 287 v = PyImport_ImportModule("readline"); 288 if (v == NULL) 289 PyErr_Clear(); 290 else 291 Py_DECREF(v); 292 293 PyRun_InteractiveLoop(stdin, "stdin"); 294 } 295 296 // clean up Python intepreter. 297 Py_Finalize(); 298} 299 300 301void 302setOutputDir(const string &dir) 303{ 304 simout.setDirectory(dir); 305} 306 307 308IniFile inifile; 309 310SimObject * 311createSimObject(const string &name) 312{ 313 return SimObjectClass::createObject(inifile, name); 314} 315 316 317/** 318 * Pointer to the Python function that maps names to SimObjects. 319 */ 320PyObject *resolveFunc = NULL; 321 322/** 323 * Convert a pointer to the Python object that SWIG wraps around a C++ 324 * SimObject pointer back to the actual C++ pointer. See main.i. 325 */ 326extern "C" SimObject *convertSwigSimObjectPtr(PyObject *); 327 328 329SimObject * 330resolveSimObject(const string &name) 331{ 332 PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str()); 333 if (pyPtr == NULL) { 334 PyErr_Print(); 335 panic("resolveSimObject: failure on call to Python for %s", name); 336 } 337 338 SimObject *simObj = convertSwigSimObjectPtr(pyPtr); 339 if (simObj == NULL) 340 panic("resolveSimObject: failure on pointer conversion for %s", name); 341 342 return simObj; 343} 344 345 346/** 347 * Load config.ini into C++ database. Exported to Python via SWIG; 348 * invoked from m5.instantiate(). 349 */ 350void 351loadIniFile(PyObject *_resolveFunc) 352{ 353 resolveFunc = _resolveFunc; 354 configStream = simout.find("config.out"); 355 356 // The configuration database is now complete; start processing it. 357 inifile.load("config.ini"); 358 359 // Initialize statistics database 360 Stats::InitSimStats(); 361} 362 363 364/** 365 * Look up a MemObject port. Helper function for connectPorts(). 366 */ 367Port * 368lookupPort(SimObject *so, const std::string &name, int i) 369{ 370 MemObject *mo = dynamic_cast<MemObject *>(so); 371 if (mo == NULL) { 372 warn("error casting SimObject %s to MemObject", so->name()); 373 return NULL; 374 } 375 376 Port *p = mo->getPort(name, i); 377 if (p == NULL) 378 warn("error looking up port %s on object %s", name, so->name()); 379 return p; 380} 381 382 383/** 384 * Connect the described MemObject ports. Called from Python via SWIG. 385 */ 386int 387connectPorts(SimObject *o1, const std::string &name1, int i1, 388 SimObject *o2, const std::string &name2, int i2) 389{ 390 Port *p1 = lookupPort(o1, name1, i1); 391 Port *p2 = lookupPort(o2, name2, i2); 392 393 if (p1 == NULL || p2 == NULL) { 394 warn("connectPorts: port lookup error"); 395 return 0; 396 } 397 398 p1->setPeer(p2); 399 p2->setPeer(p1); 400 401 return 1; 402} 403 404/** 405 * Do final initialization steps after object construction but before 406 * start of simulation. 407 */ 408void 409finalInit() 410{ 411 // Parse and check all non-config-hierarchy parameters. 412 ParamContext::parseAllContexts(inifile); 413 ParamContext::checkAllContexts(); 414 415 // Echo all parameter settings to stats file as well. 416 ParamContext::showAllContexts(*configStream); 417 418 // Do a second pass to finish initializing the sim objects 419 SimObject::initAll(); 420 421 // Restore checkpointed state, if any. 422#if 0 423 configHierarchy.unserializeSimObjects(); 424#endif 425 426 SimObject::regAllStats(); 427 428 // uncomment the following to get PC-based execution-time profile 429#ifdef DO_PROFILE 430 init_profile((char *)&_init, (char *)&_fini); 431#endif 432 433 // Check to make sure that the stats package is properly initialized 434 Stats::check(); 435 436 // Reset to put the stats in a consistent state. 437 Stats::reset(); 438 439 SimStartup(); 440} 441 442 443/** Simulate for num_cycles additional cycles. If num_cycles is -1 444 * (the default), do not limit simulation; some other event must 445 * terminate the loop. Exported to Python via SWIG. 446 * @return The SimLoopExitEvent that caused the loop to exit. 447 */ 448SimLoopExitEvent * 449simulate(Tick num_cycles = -1) 450{ 451 warn("Entering event queue @ %d. Starting simulation...\n", curTick); 452 453 // Fix up num_cycles. Special default value -1 means simulate 454 // "forever"... schedule event at MaxTick just to be safe. 455 // Otherwise it's a delta for additional cycles to simulate past 456 // curTick, and thus must be non-negative. 457 if (num_cycles == -1) 458 num_cycles = MaxTick; 459 else if (num_cycles < 0) 460 fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); 461 else 462 num_cycles = curTick + num_cycles; 463 464 Event *limit_event = new SimLoopExitEvent(num_cycles, 465 "simulate() limit reached"); 466 467 while (1) { 468 // there should always be at least one event (the SimLoopExitEvent 469 // we just scheduled) in the queue 470 assert(!mainEventQueue.empty()); 471 assert(curTick <= mainEventQueue.nextTick() && 472 "event scheduled in the past"); 473 474 // forward current cycle to the time of the first event on the 475 // queue 476 curTick = mainEventQueue.nextTick(); 477 Event *exit_event = mainEventQueue.serviceOne(); 478 if (exit_event != NULL) { 479 // hit some kind of exit event; return to Python 480 // event must be subclass of SimLoopExitEvent... 481 SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); 482 if (se_event == NULL) 483 panic("Bogus exit event class!"); 484 485 // if we didn't hit limit_event, delete it 486 if (se_event != limit_event) { 487 assert(limit_event->scheduled()); 488 limit_event->deschedule(); 489 delete limit_event; 490 } 491 492 return se_event; 493 } 494 495 if (async_event) { 496 async_event = false; 497 if (async_dump) { 498 async_dump = false; 499 500 using namespace Stats; 501 SetupEvent(Dump, curTick); 502 } 503 504 if (async_dumpreset) { 505 async_dumpreset = false; 506 507 using namespace Stats; 508 SetupEvent(Dump | Reset, curTick); 509 } 510 511 if (async_exit) { 512 async_exit = false; 513 exitSimLoop("user interrupt received"); 514 } 515 516 if (async_io || async_alarm) { 517 async_io = false; 518 async_alarm = false; 519 pollQueue.service(); 520 } 521 } 522 } 523 524 // not reached... only exit is return on SimLoopExitEvent 525} 526 527/** 528 * Queue of C++ callbacks to invoke on simulator exit. 529 */ 530CallbackQueue exitCallbacks; 531 532/** 533 * Register an exit callback. 534 */ 535void 536registerExitCallback(Callback *callback) 537{ 538 exitCallbacks.add(callback); 539} 540 541/** 542 * Do C++ simulator exit processing. Exported to SWIG to be invoked 543 * when simulator terminates via Python's atexit mechanism. 544 */ 545void 546doExitCleanup() 547{ 548 exitCallbacks.process(); 549 exitCallbacks.clear(); 550 551 cout.flush(); 552 553 ParamContext::cleanupAllContexts(); 554 555 // print simulation stats 556 Stats::DumpNow(); 557}
|