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