main.cc revision 2737
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 "sim/async.hh" 61#include "sim/builder.hh" 62#include "sim/configfile.hh" 63#include "sim/host.hh" 64#include "sim/sim_events.hh" 65#include "sim/sim_exit.hh" 66#include "sim/sim_object.hh" 67#include "sim/stat_control.hh" 68#include "sim/stats.hh" 69#include "sim/root.hh" 70 71using namespace std; 72 73// See async.h. 74volatile bool async_event = false; 75volatile bool async_dump = false; 76volatile bool async_dumpreset = false; 77volatile bool async_exit = false; 78volatile bool async_io = false; 79volatile bool async_alarm = false; 80 81/// Stats signal handler. 82void 83dumpStatsHandler(int sigtype) 84{ 85 async_event = true; 86 async_dump = true; 87} 88 89void 90dumprstStatsHandler(int sigtype) 91{ 92 async_event = true; 93 async_dumpreset = true; 94} 95 96/// Exit signal handler. 97void 98exitNowHandler(int sigtype) 99{ 100 async_event = true; 101 async_exit = true; 102} 103 104/// Abort signal handler. 105void 106abortHandler(int sigtype) 107{ 108 cerr << "Program aborted at cycle " << curTick << endl; 109 110#if TRACING_ON 111 // dump trace buffer, if there is one 112 Trace::theLog.dump(cerr); 113#endif 114} 115 116/// Simulator executable name 117char *myProgName = ""; 118 119/// Show brief help message. 120void 121showBriefHelp(ostream &out) 122{ 123 char *prog = basename(myProgName); 124 125 ccprintf(out, "Usage:\n"); 126 ccprintf(out, 127"%s [-p <path>] [-i ] [-h] <config file>\n" 128"\n" 129" -p, --path <path> prepends <path> to PYTHONPATH instead of using\n" 130" built-in zip archive. Useful when developing/debugging\n" 131" changes to built-in Python libraries, as the new Python\n" 132" can be tested without building a new m5 binary.\n\n" 133" -i, --interactive forces entry into interactive mode after the supplied\n" 134" script is executed (just like the -i option to the\n" 135" Python interpreter).\n\n" 136" -h Prints this help\n\n" 137" <configfile> config file name which ends in .py. (Normally you can\n" 138" run <configfile> --help to get help on that config files\n" 139" parameters.\n\n", 140 prog); 141 142} 143 144const char *briefCopyright = 145"Copyright (c) 2001-2006\n" 146"The Regents of The University of Michigan\n" 147"All Rights Reserved\n"; 148 149/// Print welcome message. 150void 151sayHello(ostream &out) 152{ 153 extern const char *compileDate; // from date.cc 154 155 ccprintf(out, "M5 Simulator System\n"); 156 // display copyright 157 ccprintf(out, "%s\n", briefCopyright); 158 ccprintf(out, "M5 compiled %d\n", compileDate); 159 ccprintf(out, "M5 started %s\n", Time::start); 160 161 char *host = getenv("HOSTNAME"); 162 if (!host) 163 host = getenv("HOST"); 164 165 if (host) 166 ccprintf(out, "M5 executing on %s\n", host); 167} 168 169 170extern "C" { void init_main(); } 171 172int 173main(int argc, char **argv) 174{ 175 // Saze off program name 176 myProgName = argv[0]; 177 178 sayHello(cerr); 179 180 signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 181 signal(SIGTRAP, SIG_IGN); 182 signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 183 signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 184 signal(SIGINT, exitNowHandler); // dump final stats and exit 185 signal(SIGABRT, abortHandler); 186 187 Py_SetProgramName(argv[0]); 188 189 // default path to m5 python code is the currently executing 190 // file... Python ZipImporter will find embedded zip archive 191 char *pythonpath = argv[0]; 192 193 bool interactive = false; 194 bool show_help = false; 195 bool getopt_done = false; 196 int opt_index = 0; 197 198 static struct option long_options[] = { 199 {"python", 1, 0, 'p'}, 200 {"interactive", 0, 0, 'i'}, 201 {"help", 0, 0, 'h'}, 202 {0,0,0,0} 203 }; 204 205 do { 206 switch (getopt_long(argc, argv, "+p:ih", long_options, &opt_index)) { 207 // -p <path> prepends <path> to PYTHONPATH instead of 208 // using built-in zip archive. Useful when 209 // developing/debugging changes to built-in Python 210 // libraries, as the new Python can be tested without 211 // building a new m5 binary. 212 case 'p': 213 pythonpath = optarg; 214 break; 215 216 // -i forces entry into interactive mode after the 217 // supplied script is executed (just like the -i option to 218 // the Python interpreter). 219 case 'i': 220 interactive = true; 221 break; 222 223 case 'h': 224 show_help = true; 225 break; 226 case -1: 227 getopt_done = true; 228 break; 229 230 default: 231 fatal("Unrecognized option %c\n", optopt); 232 } 233 } while (!getopt_done); 234 235 if (show_help) { 236 showBriefHelp(cerr); 237 exit(1); 238 } 239 240 // Fix up argc & argv to hide arguments we just processed. 241 // getopt() sets optind to the index of the first non-processed 242 // argv element. 243 argc -= optind; 244 argv += optind; 245 246 // Set up PYTHONPATH to make sure the m5 module is found 247 string newpath(pythonpath); 248 249 char *oldpath = getenv("PYTHONPATH"); 250 if (oldpath != NULL) { 251 newpath += ":"; 252 newpath += oldpath; 253 } 254 255 if (setenv("PYTHONPATH", newpath.c_str(), true) == -1) 256 fatal("setenv: %s\n", strerror(errno)); 257 258 // initialize embedded Python interpreter 259 Py_Initialize(); 260 PySys_SetArgv(argc, argv); 261 262 // initialize SWIG 'main' module 263 init_main(); 264 265 if (argc > 0) { 266 // extra arg(s): first is script file, remaining ones are args 267 // to script file 268 char *filename = argv[0]; 269 FILE *fp = fopen(filename, "r"); 270 if (!fp) { 271 fatal("cannot open file '%s'\n", filename); 272 } 273 274 PyRun_AnyFile(fp, filename); 275 } else { 276 // no script file argument... force interactive prompt 277 interactive = true; 278 } 279 280 if (interactive) { 281 // The following code to import readline was copied from Python 282 // 2.4.3's Modules/main.c. 283 // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 284 // Python Software Foundation; All Rights Reserved 285 // We should only enable this if we're actually using an 286 // interactive prompt. 287 PyObject *v; 288 v = PyImport_ImportModule("readline"); 289 if (v == NULL) 290 PyErr_Clear(); 291 else 292 Py_DECREF(v); 293 294 PyRun_InteractiveLoop(stdin, "stdin"); 295 } 296 297 // clean up Python intepreter. 298 Py_Finalize(); 299} 300 301 302/// Initialize C++ configuration. Exported to Python via SWIG; invoked 303/// from m5.instantiate(). 304void 305initialize() 306{ 307 configStream = simout.find("config.out"); 308 309 // The configuration database is now complete; start processing it. 310 IniFile inifile; 311 inifile.load("config.ini"); 312 313 // Initialize statistics database 314 Stats::InitSimStats(); 315 316 // Now process the configuration hierarchy and create the SimObjects. 317 ConfigHierarchy configHierarchy(inifile); 318 configHierarchy.build(); 319 configHierarchy.createSimObjects(); 320 321 // Parse and check all non-config-hierarchy parameters. 322 ParamContext::parseAllContexts(inifile); 323 ParamContext::checkAllContexts(); 324 325 // Echo all parameter settings to stats file as well. 326 ParamContext::showAllContexts(*configStream); 327 328 // Any objects that can't connect themselves until after construction should 329 // do so now 330 SimObject::connectAll(); 331 332 // Do a second pass to finish initializing the sim objects 333 SimObject::initAll(); 334 335 // Restore checkpointed state, if any. 336 configHierarchy.unserializeSimObjects(); 337 338 // Done processing the configuration database. 339 // Check for unreferenced entries. 340 if (inifile.printUnreferenced()) 341 panic("unreferenced sections/entries in the intermediate ini file"); 342 343 SimObject::regAllStats(); 344 345 // uncomment the following to get PC-based execution-time profile 346#ifdef DO_PROFILE 347 init_profile((char *)&_init, (char *)&_fini); 348#endif 349 350 // Check to make sure that the stats package is properly initialized 351 Stats::check(); 352 353 // Reset to put the stats in a consistent state. 354 Stats::reset(); 355 356 SimStartup(); 357} 358 359 360/** Simulate for num_cycles additional cycles. If num_cycles is -1 361 * (the default), do not limit simulation; some other event must 362 * terminate the loop. Exported to Python via SWIG. 363 * @return The SimLoopExitEvent that caused the loop to exit. 364 */ 365SimLoopExitEvent * 366simulate(Tick num_cycles = -1) 367{ 368 warn("Entering event queue @ %d. Starting simulation...\n", curTick); 369 370 // Fix up num_cycles. Special default value -1 means simulate 371 // "forever"... schedule event at MaxTick just to be safe. 372 // Otherwise it's a delta for additional cycles to simulate past 373 // curTick, and thus must be non-negative. 374 if (num_cycles == -1) 375 num_cycles = MaxTick; 376 else if (num_cycles < 0) 377 fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); 378 else 379 num_cycles = curTick + num_cycles; 380 381 Event *limit_event = new SimLoopExitEvent(num_cycles, 382 "simulate() limit reached"); 383 384 while (1) { 385 // there should always be at least one event (the SimLoopExitEvent 386 // we just scheduled) in the queue 387 assert(!mainEventQueue.empty()); 388 assert(curTick <= mainEventQueue.nextTick() && 389 "event scheduled in the past"); 390 391 // forward current cycle to the time of the first event on the 392 // queue 393 curTick = mainEventQueue.nextTick(); 394 Event *exit_event = mainEventQueue.serviceOne(); 395 if (exit_event != NULL) { 396 // hit some kind of exit event; return to Python 397 // event must be subclass of SimLoopExitEvent... 398 SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); 399 if (se_event == NULL) 400 panic("Bogus exit event class!"); 401 402 // if we didn't hit limit_event, delete it 403 if (se_event != limit_event) { 404 assert(limit_event->scheduled()); 405 limit_event->deschedule(); 406 delete limit_event; 407 } 408 409 return se_event; 410 } 411 412 if (async_event) { 413 async_event = false; 414 if (async_dump) { 415 async_dump = false; 416 417 using namespace Stats; 418 SetupEvent(Dump, curTick); 419 } 420 421 if (async_dumpreset) { 422 async_dumpreset = false; 423 424 using namespace Stats; 425 SetupEvent(Dump | Reset, curTick); 426 } 427 428 if (async_exit) { 429 async_exit = false; 430 exitSimLoop("user interrupt received"); 431 } 432 433 if (async_io || async_alarm) { 434 async_io = false; 435 async_alarm = false; 436 pollQueue.service(); 437 } 438 } 439 } 440 441 // not reached... only exit is return on SimLoopExitEvent 442} 443 444/** 445 * Queue of C++ callbacks to invoke on simulator exit. 446 */ 447CallbackQueue exitCallbacks; 448 449/** 450 * Register an exit callback. 451 */ 452void 453registerExitCallback(Callback *callback) 454{ 455 exitCallbacks.add(callback); 456} 457 458/** 459 * Do C++ simulator exit processing. Exported to SWIG to be invoked 460 * when simulator terminates via Python's atexit mechanism. 461 */ 462void 463doExitCleanup() 464{ 465 exitCallbacks.process(); 466 exitCallbacks.clear(); 467 468 cout.flush(); 469 470 ParamContext::cleanupAllContexts(); 471 472 // print simulation stats 473 Stats::DumpNow(); 474} 475