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