main.cc revision 3356
12929Sktlim@umich.edu/* 211504Sandreas.sandberg@arm.com * Copyright (c) 2000-2005 The Regents of The University of Michigan 311504Sandreas.sandberg@arm.com * All rights reserved. 411504Sandreas.sandberg@arm.com * 511504Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without 611504Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are 711504Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright 811504Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer; 911504Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright 1011504Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the 1111504Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution; 1211504Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its 1311504Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from 1411504Sandreas.sandberg@arm.com * this software without specific prior written permission. 152932Sktlim@umich.edu * 162929Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172929Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182929Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192929Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202929Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212929Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222929Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232929Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242929Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252929Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262929Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272929Sktlim@umich.edu * 282929Sktlim@umich.edu * Authors: Steve Raasch 292929Sktlim@umich.edu * Nathan Binkert 302929Sktlim@umich.edu * Steve Reinhardt 312929Sktlim@umich.edu */ 322929Sktlim@umich.edu 332929Sktlim@umich.edu/// 342929Sktlim@umich.edu/// @file sim/main.cc 352929Sktlim@umich.edu/// 362929Sktlim@umich.edu#include <Python.h> // must be before system headers... see Python docs 372929Sktlim@umich.edu 382929Sktlim@umich.edu#include <sys/types.h> 392929Sktlim@umich.edu#include <sys/stat.h> 402932Sktlim@umich.edu#include <errno.h> 412932Sktlim@umich.edu#include <libgen.h> 422932Sktlim@umich.edu#include <stdlib.h> 4311504Sandreas.sandberg@arm.com#include <signal.h> 442929Sktlim@umich.edu#include <getopt.h> 452929Sktlim@umich.edu 4611504Sandreas.sandberg@arm.com#include <list> 4711504Sandreas.sandberg@arm.com#include <string> 4811504Sandreas.sandberg@arm.com#include <vector> 4911504Sandreas.sandberg@arm.com 5011504Sandreas.sandberg@arm.com#include "base/callback.hh" 5111504Sandreas.sandberg@arm.com#include "base/inifile.hh" 5211504Sandreas.sandberg@arm.com#include "base/misc.hh" 5312246Sgabeblack@google.com#include "base/output.hh" 542929Sktlim@umich.edu#include "base/pollevent.hh" 552929Sktlim@umich.edu#include "base/statistics.hh" 562929Sktlim@umich.edu#include "base/str.hh" 578947Sandreas.hansson@arm.com#include "base/time.hh" 5812246Sgabeblack@google.com#include "config/pythonhome.hh" 598947Sandreas.hansson@arm.com#include "cpu/base.hh" 602929Sktlim@umich.edu#include "cpu/smt.hh" 612929Sktlim@umich.edu#include "mem/mem_object.hh" 6211504Sandreas.sandberg@arm.com#include "mem/port.hh" 6311504Sandreas.sandberg@arm.com#include "sim/async.hh" 6411504Sandreas.sandberg@arm.com#include "sim/builder.hh" 6511504Sandreas.sandberg@arm.com#include "sim/host.hh" 6611504Sandreas.sandberg@arm.com#include "sim/serialize.hh" 6711504Sandreas.sandberg@arm.com#include "sim/sim_events.hh" 6811504Sandreas.sandberg@arm.com#include "sim/sim_exit.hh" 692929Sktlim@umich.edu#include "sim/sim_object.hh" 7011504Sandreas.sandberg@arm.com#include "sim/system.hh" 7111504Sandreas.sandberg@arm.com#include "sim/stat_control.hh" 726007Ssteve.reinhardt@amd.com#include "sim/stats.hh" 736007Ssteve.reinhardt@amd.com#include "sim/root.hh" 7411504Sandreas.sandberg@arm.com 752929Sktlim@umich.eduusing namespace std; 762929Sktlim@umich.edu 7711504Sandreas.sandberg@arm.com// See async.h. 786007Ssteve.reinhardt@amd.comvolatile bool async_event = false; 796007Ssteve.reinhardt@amd.comvolatile bool async_dump = false; 809781Sandreas.hansson@arm.comvolatile bool async_dumpreset = false; 816007Ssteve.reinhardt@amd.comvolatile bool async_exit = false; 8211504Sandreas.sandberg@arm.comvolatile bool async_io = false; 832929Sktlim@umich.eduvolatile bool async_alarm = false; 842929Sktlim@umich.edu 8511504Sandreas.sandberg@arm.com/// Stats signal handler. 8611504Sandreas.sandberg@arm.comvoid 8711504Sandreas.sandberg@arm.comdumpStatsHandler(int sigtype) 8811504Sandreas.sandberg@arm.com{ 8911504Sandreas.sandberg@arm.com async_event = true; 906007Ssteve.reinhardt@amd.com async_dump = true; 9111504Sandreas.sandberg@arm.com} 9211504Sandreas.sandberg@arm.com 9311504Sandreas.sandberg@arm.comvoid 9411504Sandreas.sandberg@arm.comdumprstStatsHandler(int sigtype) 956007Ssteve.reinhardt@amd.com{ 9611504Sandreas.sandberg@arm.com async_event = true; 9711504Sandreas.sandberg@arm.com async_dumpreset = true; 9811504Sandreas.sandberg@arm.com} 996007Ssteve.reinhardt@amd.com 1002929Sktlim@umich.edu/// Exit signal handler. 1012929Sktlim@umich.eduvoid 1026007Ssteve.reinhardt@amd.comexitNowHandler(int sigtype) 1036007Ssteve.reinhardt@amd.com{ 1042929Sktlim@umich.edu async_event = true; 1052929Sktlim@umich.edu async_exit = true; 1066007Ssteve.reinhardt@amd.com} 1072929Sktlim@umich.edu 1082929Sktlim@umich.edu/// Abort signal handler. 10911504Sandreas.sandberg@arm.comvoid 1108947Sandreas.hansson@arm.comabortHandler(int sigtype) 11111504Sandreas.sandberg@arm.com{ 11211504Sandreas.sandberg@arm.com cerr << "Program aborted at cycle " << curTick << endl; 1138947Sandreas.hansson@arm.com 11411504Sandreas.sandberg@arm.com#if TRACING_ON 11511504Sandreas.sandberg@arm.com // dump trace buffer, if there is one 1168947Sandreas.hansson@arm.com Trace::theLog.dump(cerr); 11711504Sandreas.sandberg@arm.com#endif 11811504Sandreas.sandberg@arm.com} 11911504Sandreas.sandberg@arm.com 1208947Sandreas.hansson@arm.comextern "C" { void init_cc_main(); } 12111504Sandreas.sandberg@arm.com 12211504Sandreas.sandberg@arm.comint 12311504Sandreas.sandberg@arm.commain(int argc, char **argv) 12411504Sandreas.sandberg@arm.com{ 12511542Sandreas.sandberg@arm.com signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 12611542Sandreas.sandberg@arm.com signal(SIGTRAP, SIG_IGN); 12711542Sandreas.sandberg@arm.com signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 12811542Sandreas.sandberg@arm.com signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 12911504Sandreas.sandberg@arm.com signal(SIGINT, exitNowHandler); // dump final stats and exit 13011504Sandreas.sandberg@arm.com signal(SIGABRT, abortHandler); 13111504Sandreas.sandberg@arm.com 13211504Sandreas.sandberg@arm.com Py_SetProgramName(argv[0]); 13311542Sandreas.sandberg@arm.com 13411504Sandreas.sandberg@arm.com // default path to m5 python code is the currently executing 13511504Sandreas.sandberg@arm.com // file... Python ZipImporter will find embedded zip archive. 13611504Sandreas.sandberg@arm.com // The M5_ARCHIVE environment variable can be used to override this. 13711504Sandreas.sandberg@arm.com char *m5_archive = getenv("M5_ARCHIVE"); 13811504Sandreas.sandberg@arm.com string pythonpath = m5_archive ? m5_archive : argv[0]; 13911504Sandreas.sandberg@arm.com 1402929Sktlim@umich.edu char *oldpath = getenv("PYTHONPATH"); 1412929Sktlim@umich.edu if (oldpath != NULL) { 14211504Sandreas.sandberg@arm.com pythonpath += ":"; 1434937Sstever@gmail.com pythonpath += oldpath; 1442929Sktlim@umich.edu } 14511504Sandreas.sandberg@arm.com 1462929Sktlim@umich.edu if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1) 14711504Sandreas.sandberg@arm.com fatal("setenv: %s\n", strerror(errno)); 14811504Sandreas.sandberg@arm.com 1492929Sktlim@umich.edu char *python_home = getenv("PYTHONHOME"); 15011504Sandreas.sandberg@arm.com if (!python_home) 15111504Sandreas.sandberg@arm.com python_home = PYTHONHOME; 1522929Sktlim@umich.edu Py_SetPythonHome(python_home); 15311504Sandreas.sandberg@arm.com 15411504Sandreas.sandberg@arm.com // initialize embedded Python interpreter 15511504Sandreas.sandberg@arm.com Py_Initialize(); 15611504Sandreas.sandberg@arm.com PySys_SetArgv(argc, argv); 15711504Sandreas.sandberg@arm.com 15811504Sandreas.sandberg@arm.com // initialize SWIG 'cc_main' module 15911504Sandreas.sandberg@arm.com init_cc_main(); 16011504Sandreas.sandberg@arm.com 16111504Sandreas.sandberg@arm.com PyRun_SimpleString("import m5.main"); 16211504Sandreas.sandberg@arm.com PyRun_SimpleString("m5.main.main()"); 16311504Sandreas.sandberg@arm.com 16411504Sandreas.sandberg@arm.com // clean up Python intepreter. 16511542Sandreas.sandberg@arm.com Py_Finalize(); 16611504Sandreas.sandberg@arm.com} 16711504Sandreas.sandberg@arm.com 16811504Sandreas.sandberg@arm.com 16911504Sandreas.sandberg@arm.comvoid 17011504Sandreas.sandberg@arm.comsetOutputDir(const string &dir) 17111504Sandreas.sandberg@arm.com{ 17211504Sandreas.sandberg@arm.com simout.setDirectory(dir); 17311542Sandreas.sandberg@arm.com} 17411504Sandreas.sandberg@arm.com 17511504Sandreas.sandberg@arm.com 17611504Sandreas.sandberg@arm.comIniFile inifile; 17711504Sandreas.sandberg@arm.com 17811504Sandreas.sandberg@arm.comSimObject * 17911504Sandreas.sandberg@arm.comcreateSimObject(const string &name) 18011504Sandreas.sandberg@arm.com{ 1812929Sktlim@umich.edu return SimObjectClass::createObject(inifile, name); 1822929Sktlim@umich.edu} 1832929Sktlim@umich.edu 18411504Sandreas.sandberg@arm.com 1852929Sktlim@umich.edu/** 1862929Sktlim@umich.edu * Pointer to the Python function that maps names to SimObjects. 1872929Sktlim@umich.edu */ 1882929Sktlim@umich.eduPyObject *resolveFunc = NULL; 18911504Sandreas.sandberg@arm.com 1902997Sstever@eecs.umich.edu/** 1912929Sktlim@umich.edu * Convert a pointer to the Python object that SWIG wraps around a C++ 19211504Sandreas.sandberg@arm.com * SimObject pointer back to the actual C++ pointer. See main.i. 19311504Sandreas.sandberg@arm.com */ 19411504Sandreas.sandberg@arm.comextern "C" SimObject *convertSwigSimObjectPtr(PyObject *); 1952929Sktlim@umich.edu 19611504Sandreas.sandberg@arm.com 19711504Sandreas.sandberg@arm.comSimObject * 1982929Sktlim@umich.eduresolveSimObject(const string &name) 19911504Sandreas.sandberg@arm.com{ 20011504Sandreas.sandberg@arm.com PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str()); 2012997Sstever@eecs.umich.edu if (pyPtr == NULL) { 20211504Sandreas.sandberg@arm.com PyErr_Print(); 20311504Sandreas.sandberg@arm.com panic("resolveSimObject: failure on call to Python for %s", name); 20411504Sandreas.sandberg@arm.com } 20511504Sandreas.sandberg@arm.com 2062997Sstever@eecs.umich.edu SimObject *simObj = convertSwigSimObjectPtr(pyPtr); 20711504Sandreas.sandberg@arm.com if (simObj == NULL) 20811504Sandreas.sandberg@arm.com panic("resolveSimObject: failure on pointer conversion for %s", name); 20911504Sandreas.sandberg@arm.com 21011504Sandreas.sandberg@arm.com return simObj; 21111504Sandreas.sandberg@arm.com} 21211504Sandreas.sandberg@arm.com 2132929Sktlim@umich.edu 2142997Sstever@eecs.umich.edu/** 2158120Sgblack@eecs.umich.edu * Load config.ini into C++ database. Exported to Python via SWIG; 21611504Sandreas.sandberg@arm.com * invoked from m5.instantiate(). 2172997Sstever@eecs.umich.edu */ 21811504Sandreas.sandberg@arm.comvoid 2192929Sktlim@umich.eduloadIniFile(PyObject *_resolveFunc) 2202997Sstever@eecs.umich.edu{ 2212929Sktlim@umich.edu resolveFunc = _resolveFunc; 22211504Sandreas.sandberg@arm.com configStream = simout.find("config.out"); 22311504Sandreas.sandberg@arm.com 2242929Sktlim@umich.edu // The configuration database is now complete; start processing it. 22511504Sandreas.sandberg@arm.com inifile.load(simout.resolve("config.ini")); 22611504Sandreas.sandberg@arm.com 2273691Shsul@eecs.umich.edu // Initialize statistics database 22811504Sandreas.sandberg@arm.com Stats::InitSimStats(); 2293005Sstever@eecs.umich.edu} 23011504Sandreas.sandberg@arm.com 23111105Spower.jg@gmail.com 23211504Sandreas.sandberg@arm.com/** 23311504Sandreas.sandberg@arm.com * Look up a MemObject port. Helper function for connectPorts(). 23411504Sandreas.sandberg@arm.com */ 2356166Ssteve.reinhardt@amd.comPort * 23611504Sandreas.sandberg@arm.comlookupPort(SimObject *so, const std::string &name, int i) 23711504Sandreas.sandberg@arm.com{ 23811504Sandreas.sandberg@arm.com MemObject *mo = dynamic_cast<MemObject *>(so); 23911504Sandreas.sandberg@arm.com if (mo == NULL) { 24011504Sandreas.sandberg@arm.com warn("error casting SimObject %s to MemObject", so->name()); 24111504Sandreas.sandberg@arm.com return NULL; 24211504Sandreas.sandberg@arm.com } 24311504Sandreas.sandberg@arm.com 24411504Sandreas.sandberg@arm.com Port *p = mo->getPort(name, i); 24511504Sandreas.sandberg@arm.com if (p == NULL) 24611504Sandreas.sandberg@arm.com warn("error looking up port %s on object %s", name, so->name()); 24711504Sandreas.sandberg@arm.com return p; 24811504Sandreas.sandberg@arm.com} 24911504Sandreas.sandberg@arm.com 250 251/** 252 * Connect the described MemObject ports. Called from Python via SWIG. 253 */ 254int 255connectPorts(SimObject *o1, const std::string &name1, int i1, 256 SimObject *o2, const std::string &name2, int i2) 257{ 258 Port *p1 = lookupPort(o1, name1, i1); 259 Port *p2 = lookupPort(o2, name2, i2); 260 261 if (p1 == NULL || p2 == NULL) { 262 warn("connectPorts: port lookup error"); 263 return 0; 264 } 265 266 p1->setPeer(p2); 267 p2->setPeer(p1); 268 269 return 1; 270} 271 272/** 273 * Do final initialization steps after object construction but before 274 * start of simulation. 275 */ 276void 277finalInit() 278{ 279 // Parse and check all non-config-hierarchy parameters. 280 ParamContext::parseAllContexts(inifile); 281 ParamContext::checkAllContexts(); 282 283 // Echo all parameter settings to stats file as well. 284 ParamContext::showAllContexts(*configStream); 285 286 // Do a second pass to finish initializing the sim objects 287 SimObject::initAll(); 288 289 // Restore checkpointed state, if any. 290#if 0 291 configHierarchy.unserializeSimObjects(); 292#endif 293 294 SimObject::regAllStats(); 295 296 // Check to make sure that the stats package is properly initialized 297 Stats::check(); 298 299 // Reset to put the stats in a consistent state. 300 Stats::reset(); 301 302 SimStartup(); 303} 304 305 306/** Simulate for num_cycles additional cycles. If num_cycles is -1 307 * (the default), do not limit simulation; some other event must 308 * terminate the loop. Exported to Python via SWIG. 309 * @return The SimLoopExitEvent that caused the loop to exit. 310 */ 311SimLoopExitEvent * 312simulate(Tick num_cycles = -1) 313{ 314 warn("Entering event queue @ %d. Starting simulation...\n", curTick); 315 316 // Fix up num_cycles. Special default value -1 means simulate 317 // "forever"... schedule event at MaxTick just to be safe. 318 // Otherwise it's a delta for additional cycles to simulate past 319 // curTick, and thus must be non-negative. 320 if (num_cycles == -1) 321 num_cycles = MaxTick; 322 else if (num_cycles < 0) 323 fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); 324 else 325 num_cycles = curTick + num_cycles; 326 327 Event *limit_event = schedExitSimLoop("simulate() limit reached", 328 num_cycles); 329 330 while (1) { 331 // there should always be at least one event (the SimLoopExitEvent 332 // we just scheduled) in the queue 333 assert(!mainEventQueue.empty()); 334 assert(curTick <= mainEventQueue.nextTick() && 335 "event scheduled in the past"); 336 337 // forward current cycle to the time of the first event on the 338 // queue 339 curTick = mainEventQueue.nextTick(); 340 Event *exit_event = mainEventQueue.serviceOne(); 341 if (exit_event != NULL) { 342 // hit some kind of exit event; return to Python 343 // event must be subclass of SimLoopExitEvent... 344 SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); 345 if (se_event == NULL) 346 panic("Bogus exit event class!"); 347 348 // if we didn't hit limit_event, delete it 349 if (se_event != limit_event) { 350 assert(limit_event->scheduled()); 351 limit_event->deschedule(); 352 delete limit_event; 353 } 354 355 return se_event; 356 } 357 358 if (async_event) { 359 async_event = false; 360 if (async_dump) { 361 async_dump = false; 362 363 using namespace Stats; 364 SetupEvent(Dump, curTick); 365 } 366 367 if (async_dumpreset) { 368 async_dumpreset = false; 369 370 using namespace Stats; 371 SetupEvent(Dump | Reset, curTick); 372 } 373 374 if (async_exit) { 375 async_exit = false; 376 exitSimLoop("user interrupt received"); 377 } 378 379 if (async_io || async_alarm) { 380 async_io = false; 381 async_alarm = false; 382 pollQueue.service(); 383 } 384 } 385 } 386 387 // not reached... only exit is return on SimLoopExitEvent 388} 389 390Event * 391createCountedDrain() 392{ 393 return new CountedDrainEvent(); 394} 395 396void 397cleanupCountedDrain(Event *counted_drain) 398{ 399 CountedDrainEvent *event = 400 dynamic_cast<CountedDrainEvent *>(counted_drain); 401 if (event == NULL) { 402 fatal("Called cleanupCountedDrain() on an event that was not " 403 "a CountedDrainEvent."); 404 } 405 assert(event->getCount() == 0); 406 delete event; 407} 408 409void 410serializeAll(const std::string &cpt_dir) 411{ 412 Serializable::serializeAll(cpt_dir); 413} 414 415void 416unserializeAll(const std::string &cpt_dir) 417{ 418 Serializable::unserializeAll(cpt_dir); 419} 420 421/** 422 * Queue of C++ callbacks to invoke on simulator exit. 423 */ 424CallbackQueue& 425exitCallbacks() 426{ 427 static CallbackQueue theQueue; 428 return theQueue; 429} 430 431/** 432 * Register an exit callback. 433 */ 434void 435registerExitCallback(Callback *callback) 436{ 437 exitCallbacks().add(callback); 438} 439 440BaseCPU * 441convertToBaseCPUPtr(SimObject *obj) 442{ 443 BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj); 444 445 if (ptr == NULL) 446 warn("Casting to BaseCPU pointer failed"); 447 return ptr; 448} 449 450System * 451convertToSystemPtr(SimObject *obj) 452{ 453 System *ptr = dynamic_cast<System *>(obj); 454 455 if (ptr == NULL) 456 warn("Casting to System pointer failed"); 457 return ptr; 458} 459 460 461/** 462 * Do C++ simulator exit processing. Exported to SWIG to be invoked 463 * when simulator terminates via Python's atexit mechanism. 464 */ 465void 466doExitCleanup() 467{ 468 exitCallbacks().process(); 469 exitCallbacks().clear(); 470 471 cout.flush(); 472 473 ParamContext::cleanupAllContexts(); 474 475 // print simulation stats 476 Stats::DumpNow(); 477} 478