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