/* * Copyright (c) 2000-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Steve Raasch * Nathan Binkert * Steve Reinhardt */ /// /// @file sim/main.cc /// #include // must be before system headers... see Python docs #include #include #include #include #include #include #include #include #include #include #include "base/callback.hh" #include "base/inifile.hh" #include "base/misc.hh" #include "base/output.hh" #include "base/pollevent.hh" #include "base/statistics.hh" #include "base/str.hh" #include "base/time.hh" #include "cpu/base.hh" #include "cpu/smt.hh" #include "sim/async.hh" #include "sim/builder.hh" #include "sim/configfile.hh" #include "sim/host.hh" #include "sim/sim_events.hh" #include "sim/sim_exit.hh" #include "sim/sim_object.hh" #include "sim/stat_control.hh" #include "sim/stats.hh" #include "sim/root.hh" using namespace std; // See async.h. volatile bool async_event = false; volatile bool async_dump = false; volatile bool async_dumpreset = false; volatile bool async_exit = false; volatile bool async_io = false; volatile bool async_alarm = false; /// Stats signal handler. void dumpStatsHandler(int sigtype) { async_event = true; async_dump = true; } void dumprstStatsHandler(int sigtype) { async_event = true; async_dumpreset = true; } /// Exit signal handler. void exitNowHandler(int sigtype) { async_event = true; async_exit = true; } /// Abort signal handler. void abortHandler(int sigtype) { cerr << "Program aborted at cycle " << curTick << endl; #if TRACING_ON // dump trace buffer, if there is one Trace::theLog.dump(cerr); #endif } const char *briefCopyright = "Copyright (c) 2001-2006\n" "The Regents of The University of Michigan\n" "All Rights Reserved\n"; /// Print welcome message. void sayHello(ostream &out) { extern const char *compileDate; // from date.cc ccprintf(out, "M5 Simulator System\n"); // display copyright ccprintf(out, "%s\n", briefCopyright); ccprintf(out, "M5 compiled %d\n", compileDate); ccprintf(out, "M5 started %s\n", Time::start); char *host = getenv("HOSTNAME"); if (!host) host = getenv("HOST"); if (host) ccprintf(out, "M5 executing on %s\n", host); } extern "C" { void init_main(); } int main(int argc, char **argv) { sayHello(cerr); signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths signal(SIGTRAP, SIG_IGN); signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats signal(SIGINT, exitNowHandler); // dump final stats and exit signal(SIGABRT, abortHandler); Py_SetProgramName(argv[0]); // default path to m5 python code is the currently executing // file... Python ZipImporter will find embedded zip archive char *pythonpath = argv[0]; bool interactive = false; bool getopt_done = false; do { switch (getopt(argc, argv, "+p:i")) { // -p prepends to PYTHONPATH instead of // using built-in zip archive. Useful when // developing/debugging changes to built-in Python // libraries, as the new Python can be tested without // building a new m5 binary. case 'p': pythonpath = optarg; break; // -i forces entry into interactive mode after the // supplied script is executed (just like the -i option to // the Python interpreter). case 'i': interactive = true; break; case -1: getopt_done = true; break; default: fatal("Unrecognized option %c\n", optopt); } } while (!getopt_done); // Fix up argc & argv to hide arguments we just processed. // getopt() sets optind to the index of the first non-processed // argv element. argc -= optind; argv += optind; // Set up PYTHONPATH to make sure the m5 module is found string newpath(pythonpath); char *oldpath = getenv("PYTHONPATH"); if (oldpath != NULL) { newpath += ":"; newpath += oldpath; } if (setenv("PYTHONPATH", newpath.c_str(), true) == -1) fatal("setenv: %s\n", strerror(errno)); // initialize embedded Python interpreter Py_Initialize(); PySys_SetArgv(argc, argv); // initialize SWIG 'main' module init_main(); if (argc > 0) { // extra arg(s): first is script file, remaining ones are args // to script file char *filename = argv[0]; FILE *fp = fopen(filename, "r"); if (!fp) { fatal("cannot open file '%s'\n", filename); } PyRun_AnyFile(fp, filename); } else { // no script file argument... force interactive prompt interactive = true; } if (interactive) { // The following code to import readline was copied from Python // 2.4.3's Modules/main.c. // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 // Python Software Foundation; All Rights Reserved // We should only enable this if we're actually using an // interactive prompt. PyObject *v; v = PyImport_ImportModule("readline"); if (v == NULL) PyErr_Clear(); else Py_DECREF(v); PyRun_InteractiveLoop(stdin, "stdin"); } // clean up Python intepreter. Py_Finalize(); } /// Initialize C++ configuration. Exported to Python via SWIG; invoked /// from m5.instantiate(). void initialize() { configStream = simout.find("config.out"); // The configuration database is now complete; start processing it. IniFile inifile; inifile.load("config.ini"); // Initialize statistics database Stats::InitSimStats(); // Now process the configuration hierarchy and create the SimObjects. ConfigHierarchy configHierarchy(inifile); configHierarchy.build(); configHierarchy.createSimObjects(); // Parse and check all non-config-hierarchy parameters. ParamContext::parseAllContexts(inifile); ParamContext::checkAllContexts(); // Echo all parameter settings to stats file as well. ParamContext::showAllContexts(*configStream); // Any objects that can't connect themselves until after construction should // do so now SimObject::connectAll(); // Do a second pass to finish initializing the sim objects SimObject::initAll(); // Restore checkpointed state, if any. configHierarchy.unserializeSimObjects(); // Done processing the configuration database. // Check for unreferenced entries. if (inifile.printUnreferenced()) panic("unreferenced sections/entries in the intermediate ini file"); SimObject::regAllStats(); // uncomment the following to get PC-based execution-time profile #ifdef DO_PROFILE init_profile((char *)&_init, (char *)&_fini); #endif // Check to make sure that the stats package is properly initialized Stats::check(); // Reset to put the stats in a consistent state. Stats::reset(); SimStartup(); } /** Simulate for num_cycles additional cycles. If num_cycles is -1 * (the default), do not limit simulation; some other event must * terminate the loop. Exported to Python via SWIG. * @return The SimLoopExitEvent that caused the loop to exit. */ SimLoopExitEvent * simulate(Tick num_cycles = -1) { warn("Entering event queue @ %d. Starting simulation...\n", curTick); // Fix up num_cycles. Special default value -1 means simulate // "forever"... schedule event at MaxTick just to be safe. // Otherwise it's a delta for additional cycles to simulate past // curTick, and thus must be non-negative. if (num_cycles == -1) num_cycles = MaxTick; else if (num_cycles < 0) fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); else num_cycles = curTick + num_cycles; Event *limit_event = new SimLoopExitEvent(num_cycles, "simulate() limit reached"); while (1) { // there should always be at least one event (the SimLoopExitEvent // we just scheduled) in the queue assert(!mainEventQueue.empty()); assert(curTick <= mainEventQueue.nextTick() && "event scheduled in the past"); // forward current cycle to the time of the first event on the // queue curTick = mainEventQueue.nextTick(); Event *exit_event = mainEventQueue.serviceOne(); if (exit_event != NULL) { // hit some kind of exit event; return to Python // event must be subclass of SimLoopExitEvent... SimLoopExitEvent *se_event = dynamic_cast(exit_event); if (se_event == NULL) panic("Bogus exit event class!"); // if we didn't hit limit_event, delete it if (se_event != limit_event) { assert(limit_event->scheduled()); limit_event->deschedule(); delete limit_event; } return se_event; } if (async_event) { async_event = false; if (async_dump) { async_dump = false; using namespace Stats; SetupEvent(Dump, curTick); } if (async_dumpreset) { async_dumpreset = false; using namespace Stats; SetupEvent(Dump | Reset, curTick); } if (async_exit) { async_exit = false; exitSimLoop("user interrupt received"); } if (async_io || async_alarm) { async_io = false; async_alarm = false; pollQueue.service(); } } } // not reached... only exit is return on SimLoopExitEvent } /** * Queue of C++ callbacks to invoke on simulator exit. */ CallbackQueue exitCallbacks; /** * Register an exit callback. */ void registerExitCallback(Callback *callback) { exitCallbacks.add(callback); } /** * Do C++ simulator exit processing. Exported to SWIG to be invoked * when simulator terminates via Python's atexit mechanism. */ void doExitCleanup() { exitCallbacks.process(); exitCallbacks.clear(); cout.flush(); ParamContext::cleanupAllContexts(); // print simulation stats Stats::DumpNow(); }