main.cc revision 4078:3f73f808bbd4
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/stats/output.hh" 57#include "base/str.hh" 58#include "base/time.hh" 59#include "config/pythonhome.hh" 60#include "cpu/base.hh" 61#include "cpu/smt.hh" 62#include "mem/mem_object.hh" 63#include "mem/port.hh" 64#include "python/swig/init.hh" 65#include "sim/async.hh" 66#include "sim/builder.hh" 67#include "sim/host.hh" 68#include "sim/serialize.hh" 69#include "sim/sim_events.hh" 70#include "sim/sim_exit.hh" 71#include "sim/sim_object.hh" 72#include "sim/system.hh" 73#include "sim/stat_control.hh" 74#include "sim/stats.hh" 75#include "sim/root.hh" 76 77using namespace std; 78 79// See async.h. 80volatile bool async_event = false; 81volatile bool async_dump = false; 82volatile bool async_dumpreset = false; 83volatile bool async_exit = false; 84volatile bool async_io = false; 85volatile bool async_alarm = false; 86volatile bool async_exception = false; 87 88/// Stats signal handler. 89void 90dumpStatsHandler(int sigtype) 91{ 92 async_event = true; 93 async_dump = true; 94} 95 96void 97dumprstStatsHandler(int sigtype) 98{ 99 async_event = true; 100 async_dumpreset = true; 101} 102 103/// Exit signal handler. 104void 105exitNowHandler(int sigtype) 106{ 107 async_event = true; 108 async_exit = true; 109} 110 111/// Abort signal handler. 112void 113abortHandler(int sigtype) 114{ 115 cerr << "Program aborted at cycle " << curTick << endl; 116} 117 118int 119main(int argc, char **argv) 120{ 121 signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 122 signal(SIGTRAP, SIG_IGN); 123 signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 124 signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 125 signal(SIGINT, exitNowHandler); // dump final stats and exit 126 signal(SIGABRT, abortHandler); 127 128 Py_SetProgramName(argv[0]); 129 130 // default path to m5 python code is the currently executing 131 // file... Python ZipImporter will find embedded zip archive. 132 // The M5_ARCHIVE environment variable can be used to override this. 133 char *m5_archive = getenv("M5_ARCHIVE"); 134 string pythonpath = m5_archive ? m5_archive : argv[0]; 135 136 char *oldpath = getenv("PYTHONPATH"); 137 if (oldpath != NULL) { 138 pythonpath += ":"; 139 pythonpath += oldpath; 140 } 141 142 if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1) 143 fatal("setenv: %s\n", strerror(errno)); 144 145 char *python_home = getenv("PYTHONHOME"); 146 if (!python_home) 147 python_home = PYTHONHOME; 148 Py_SetPythonHome(python_home); 149 150 // initialize embedded Python interpreter 151 Py_Initialize(); 152 PySys_SetArgv(argc, argv); 153 154 // initialize SWIG modules 155 init_swig(); 156 157 PyRun_SimpleString("import m5.main"); 158 PyRun_SimpleString("m5.main.main()"); 159 160 // clean up Python intepreter. 161 Py_Finalize(); 162} 163 164 165void 166setOutputDir(const string &dir) 167{ 168 simout.setDirectory(dir); 169} 170 171 172IniFile inifile; 173 174SimObject * 175createSimObject(const string &name) 176{ 177 return SimObjectClass::createObject(inifile, name); 178} 179 180 181/** 182 * Pointer to the Python function that maps names to SimObjects. 183 */ 184PyObject *resolveFunc = NULL; 185 186/** 187 * Convert a pointer to the Python object that SWIG wraps around a C++ 188 * SimObject pointer back to the actual C++ pointer. See main.i. 189 */ 190extern "C" SimObject *convertSwigSimObjectPtr(PyObject *); 191 192 193SimObject * 194resolveSimObject(const string &name) 195{ 196 PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str()); 197 if (pyPtr == NULL) { 198 PyErr_Print(); 199 panic("resolveSimObject: failure on call to Python for %s", name); 200 } 201 202 SimObject *simObj = convertSwigSimObjectPtr(pyPtr); 203 if (simObj == NULL) 204 panic("resolveSimObject: failure on pointer conversion for %s", name); 205 206 return simObj; 207} 208 209 210/** 211 * Load config.ini into C++ database. Exported to Python via SWIG; 212 * invoked from m5.instantiate(). 213 */ 214void 215loadIniFile(PyObject *_resolveFunc) 216{ 217 resolveFunc = _resolveFunc; 218 configStream = simout.find("config.out"); 219 220 // The configuration database is now complete; start processing it. 221 inifile.load(simout.resolve("config.ini")); 222 223 // Initialize statistics database 224 Stats::initSimStats(); 225} 226 227 228/** 229 * Look up a MemObject port. Helper function for connectPorts(). 230 */ 231Port * 232lookupPort(SimObject *so, const std::string &name, int i) 233{ 234 MemObject *mo = dynamic_cast<MemObject *>(so); 235 if (mo == NULL) { 236 warn("error casting SimObject %s to MemObject", so->name()); 237 return NULL; 238 } 239 240 Port *p = mo->getPort(name, i); 241 if (p == NULL) 242 warn("error looking up port %s on object %s", name, so->name()); 243 return p; 244} 245 246 247/** 248 * Connect the described MemObject ports. Called from Python via SWIG. 249 */ 250int 251connectPorts(SimObject *o1, const std::string &name1, int i1, 252 SimObject *o2, const std::string &name2, int i2) 253{ 254 Port *p1 = lookupPort(o1, name1, i1); 255 Port *p2 = lookupPort(o2, name2, i2); 256 257 if (p1 == NULL || p2 == NULL) { 258 warn("connectPorts: port lookup error"); 259 return 0; 260 } 261 262 p1->setPeer(p2); 263 p2->setPeer(p1); 264 265 return 1; 266} 267 268/** 269 * Do final initialization steps after object construction but before 270 * start of simulation. 271 */ 272void 273finalInit() 274{ 275 // Parse and check all non-config-hierarchy parameters. 276 ParamContext::parseAllContexts(inifile); 277 ParamContext::checkAllContexts(); 278 279 // Echo all parameter settings to stats file as well. 280 ParamContext::showAllContexts(*configStream); 281 282 // Do a second pass to finish initializing the sim objects 283 SimObject::initAll(); 284 285 // Restore checkpointed state, if any. 286#if 0 287 configHierarchy.unserializeSimObjects(); 288#endif 289 290 SimObject::regAllStats(); 291 292 // Check to make sure that the stats package is properly initialized 293 Stats::check(); 294 295 // Reset to put the stats in a consistent state. 296 Stats::reset(); 297 298 SimStartup(); 299} 300 301/** Simulate for num_cycles additional cycles. If num_cycles is -1 302 * (the default), do not limit simulation; some other event must 303 * terminate the loop. Exported to Python via SWIG. 304 * @return The SimLoopExitEvent that caused the loop to exit. 305 */ 306SimLoopExitEvent * 307simulate(Tick num_cycles = MaxTick) 308{ 309 warn("Entering event queue @ %d. Starting simulation...\n", curTick); 310 311 if (num_cycles < 0) 312 fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); 313 else if (curTick + num_cycles < 0) //Overflow 314 num_cycles = MaxTick; 315 else 316 num_cycles = curTick + num_cycles; 317 318 Event *limit_event = schedExitSimLoop("simulate() limit reached", 319 num_cycles); 320 321 while (1) { 322 // there should always be at least one event (the SimLoopExitEvent 323 // we just scheduled) in the queue 324 assert(!mainEventQueue.empty()); 325 assert(curTick <= mainEventQueue.nextTick() && 326 "event scheduled in the past"); 327 328 // forward current cycle to the time of the first event on the 329 // queue 330 curTick = mainEventQueue.nextTick(); 331 Event *exit_event = mainEventQueue.serviceOne(); 332 if (exit_event != NULL) { 333 // hit some kind of exit event; return to Python 334 // event must be subclass of SimLoopExitEvent... 335 SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); 336 if (se_event == NULL) 337 panic("Bogus exit event class!"); 338 339 // if we didn't hit limit_event, delete it 340 if (se_event != limit_event) { 341 assert(limit_event->scheduled()); 342 limit_event->deschedule(); 343 delete limit_event; 344 } 345 346 return se_event; 347 } 348 349 if (async_event) { 350 async_event = false; 351 if (async_dump) { 352 async_dump = false; 353 Stats::StatEvent(true, false); 354 } 355 356 if (async_dumpreset) { 357 async_dumpreset = false; 358 Stats::StatEvent(true, true); 359 } 360 361 if (async_exit) { 362 async_exit = false; 363 exitSimLoop("user interrupt received"); 364 } 365 366 if (async_io || async_alarm) { 367 async_io = false; 368 async_alarm = false; 369 pollQueue.service(); 370 } 371 372 if (async_exception) { 373 async_exception = false; 374 return NULL; 375 } 376 } 377 } 378 379 // not reached... only exit is return on SimLoopExitEvent 380} 381 382Event * 383createCountedDrain() 384{ 385 return new CountedDrainEvent(); 386} 387 388void 389cleanupCountedDrain(Event *counted_drain) 390{ 391 CountedDrainEvent *event = 392 dynamic_cast<CountedDrainEvent *>(counted_drain); 393 if (event == NULL) { 394 fatal("Called cleanupCountedDrain() on an event that was not " 395 "a CountedDrainEvent."); 396 } 397 assert(event->getCount() == 0); 398 delete event; 399} 400 401void 402serializeAll(const std::string &cpt_dir) 403{ 404 Serializable::serializeAll(cpt_dir); 405} 406 407void 408unserializeAll(const std::string &cpt_dir) 409{ 410 Serializable::unserializeAll(cpt_dir); 411} 412 413/** 414 * Queue of C++ callbacks to invoke on simulator exit. 415 */ 416CallbackQueue& 417exitCallbacks() 418{ 419 static CallbackQueue theQueue; 420 return theQueue; 421} 422 423/** 424 * Register an exit callback. 425 */ 426void 427registerExitCallback(Callback *callback) 428{ 429 exitCallbacks().add(callback); 430} 431 432BaseCPU * 433convertToBaseCPUPtr(SimObject *obj) 434{ 435 BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj); 436 437 if (ptr == NULL) 438 warn("Casting to BaseCPU pointer failed"); 439 return ptr; 440} 441 442System * 443convertToSystemPtr(SimObject *obj) 444{ 445 System *ptr = dynamic_cast<System *>(obj); 446 447 if (ptr == NULL) 448 warn("Casting to System pointer failed"); 449 return ptr; 450} 451 452 453/** 454 * Do C++ simulator exit processing. Exported to SWIG to be invoked 455 * when simulator terminates via Python's atexit mechanism. 456 */ 457void 458doExitCleanup() 459{ 460 exitCallbacks().process(); 461 exitCallbacks().clear(); 462 463 cout.flush(); 464 465 ParamContext::cleanupAllContexts(); 466 467 // print simulation stats 468 Stats::dump(); 469} 470