main.cc revision 1104
1/* 2 * Copyright (c) 2000-2004 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 29/// 30/// @file sim/main.cc 31/// 32#include <sys/types.h> 33#include <sys/stat.h> 34#include <stdlib.h> 35#include <signal.h> 36 37#include <string> 38#include <vector> 39 40#include "base/copyright.hh" 41#include "base/inifile.hh" 42#include "base/misc.hh" 43#include "base/pollevent.hh" 44#include "base/statistics.hh" 45#include "base/time.hh" 46#include "cpu/base_cpu.hh" 47#include "cpu/full_cpu/smt.hh" 48#include "sim/async.hh" 49#include "sim/builder.hh" 50#include "sim/configfile.hh" 51#include "sim/host.hh" 52#include "sim/sim_events.hh" 53#include "sim/sim_exit.hh" 54#include "sim/sim_init.hh" 55#include "sim/sim_object.hh" 56#include "sim/stat_control.hh" 57#include "sim/stats.hh" 58#include "sim/universe.hh" 59#include "sim/pyconfig/pyconfig.hh" 60 61using namespace std; 62 63// See async.h. 64volatile bool async_event = false; 65volatile bool async_dump = false; 66volatile bool async_dumpreset = false; 67volatile bool async_exit = false; 68volatile bool async_io = false; 69volatile bool async_alarm = false; 70 71/// Stats signal handler. 72void 73dumpStatsHandler(int sigtype) 74{ 75 async_event = true; 76 async_dump = true; 77} 78 79void 80dumprstStatsHandler(int sigtype) 81{ 82 async_event = true; 83 async_dumpreset = true; 84} 85 86/// Exit signal handler. 87void 88exitNowHandler(int sigtype) 89{ 90 async_event = true; 91 async_exit = true; 92} 93 94/// Abort signal handler. 95void 96abortHandler(int sigtype) 97{ 98 cerr << "Program aborted at cycle " << curTick << endl; 99 100#if TRACING_ON 101 // dump trace buffer, if there is one 102 Trace::theLog.dump(cerr); 103#endif 104} 105 106/// Simulator executable name 107const char *myProgName = ""; 108 109/// Show brief help message. 110static void 111showBriefHelp(ostream &out) 112{ 113 out << "Usage: " << myProgName 114 << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] " 115 << "[--<section>:<param>=<value>] [<config file> ...]" << endl 116 << " -h: print long help (including parameter listing)" << endl 117 << " -n: don't load default.ini" << endl 118 << " -u: don't quit on unreferenced parameters" << endl 119 << " -D,-U,-I: passed to cpp for preprocessing .ini files" << endl; 120} 121 122/// Show verbose help message. Includes parameter listing from 123/// showBriefHelp(), plus an exhaustive list of ini-file parameters 124/// and SimObjects (with their parameters). 125static void 126showLongHelp(ostream &out) 127{ 128 showBriefHelp(out); 129 130 out << endl 131 << endl 132 << "-----------------" << endl 133 << "Global Parameters" << endl 134 << "-----------------" << endl 135 << endl; 136 137 ParamContext::describeAllContexts(out); 138 139 out << endl 140 << endl 141 << "-----------------" << endl 142 << "Simulator Objects" << endl 143 << "-----------------" << endl 144 << endl; 145 146 SimObjectClass::describeAllClasses(out); 147} 148 149/// Print welcome message. 150static void 151sayHello(ostream &out) 152{ 153 extern const char *compileDate; // from date.cc 154 155 ccprintf(out, "M5 Simulator System\n"); 156 // display copyright 157 ccprintf(out, "%s\n", briefCopyright); 158 ccprintf(out, "M5 compiled on %d\n", compileDate); 159 160 char *host = getenv("HOSTNAME"); 161 if (!host) 162 host = getenv("HOST"); 163 164 if (host) 165 ccprintf(out, "M5 executing on %s\n", host); 166 167 ccprintf(out, "M5 simulation started %s\n", Time::start); 168} 169 170/// 171/// Echo the command line for posterity in such a way that it can be 172/// used to rerun the same simulation (given the same .ini files). 173/// 174static void 175echoCommandLine(int argc, char **argv, ostream &out) 176{ 177 out << "command line: " << argv[0]; 178 for (int i = 1; i < argc; i++) { 179 string arg(argv[i]); 180 181 out << ' '; 182 183 // If the arg contains spaces, we need to quote it. 184 // The rest of this is overkill to make it look purty. 185 186 // print dashes first outside quotes 187 int non_dash_pos = arg.find_first_not_of("-"); 188 out << arg.substr(0, non_dash_pos); // print dashes 189 string body = arg.substr(non_dash_pos); // the rest 190 191 // if it's an assignment, handle the lhs & rhs separately 192 int eq_pos = body.find("="); 193 if (eq_pos == string::npos) { 194 out << quote(body); 195 } 196 else { 197 string lhs(body.substr(0, eq_pos)); 198 string rhs(body.substr(eq_pos + 1)); 199 200 out << quote(lhs) << "=" << quote(rhs); 201 } 202 } 203 out << endl << endl; 204} 205 206 207/// 208/// The simulator configuration database. This is the union of all 209/// specified .ini files. This shouldn't need to be visible outside 210/// this file, as it is passed as a parameter to all the param-parsing 211/// routines. 212/// 213static IniFile simConfigDB; 214 215/// Check for a default.ini file and load it if necessary. 216static void 217handleDefaultIni(bool &loadIt, vector<char *> &cppArgs) 218{ 219 struct stat sb; 220 221 if (loadIt) { 222 if (stat("default.ini", &sb) == 0) { 223 if (!simConfigDB.loadCPP("default.ini", cppArgs)) { 224 cout << "Error processing file default.ini" << endl; 225 exit(1); 226 } 227 } 228 229 // set this whether it actually was found or not, so we don't 230 // bother to check again next time 231 loadIt = false; 232 } 233} 234 235 236/// M5 entry point. 237int 238main(int argc, char **argv) 239{ 240 // Save off program name 241 myProgName = argv[0]; 242 243 signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths 244 signal(SIGTRAP, SIG_IGN); 245 signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats 246 signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats 247 signal(SIGINT, exitNowHandler); // dump final stats and exit 248 signal(SIGABRT, abortHandler); 249 250 sayHello(cerr); 251 252 // Initialize statistics database 253 Stats::InitSimStats(); 254 255 vector<char *> cppArgs; 256 257 // Should we use default.ini if it exists? By default, yes. (Use 258 // -n to override.) 259 bool loadDefaultIni = true; 260 261 // Should we quit if there are unreferenced parameters? By 262 // default, yes... it's a good way of catching typos in 263 // section/parameter names (which otherwise go by silently). Use 264 // -u to override. 265 bool quitOnUnreferenced = true; 266 267 // Parse command-line options. The tricky part here is figuring 268 // out whether to look for & load default.ini, and if needed, 269 // doing so at the right time w.r.t. processing the other 270 // parameters. 271 // 272 // Since most of the complex options are handled through the 273 // config database, we don't mess with getopts, and just parse 274 // manually. 275 for (int i = 1; i < argc; ++i) { 276 char *arg_str = argv[i]; 277 278 // if arg starts with '-', parse as option, 279 // else treat it as a configuration file name and load it 280 if (arg_str[0] == '-') { 281 282 // switch on second char 283 switch (arg_str[1]) { 284 case 'h': 285 // -h: show help 286 showLongHelp(cerr); 287 exit(1); 288 289 case 'n': 290 // -n: don't load default.ini 291 if (!loadDefaultIni) { 292 cerr << "Warning: -n option needs to precede any " 293 << "explicit configuration file name " << endl 294 << " or command-line configuration parameter." 295 << endl; 296 } 297 loadDefaultIni = false; 298 break; 299 300 case 'u': 301 // -u: don't quit on unreferenced parameters 302 quitOnUnreferenced = false; 303 break; 304 305 case 'D': 306 case 'U': 307 case 'I': 308 // cpp options: record & pass to cpp. Note that these 309 // cannot have spaces, i.e., '-Dname=val' is OK, but 310 // '-D name=val' is not. I don't consider this a 311 // problem, since even though gnu cpp accepts the 312 // latter, other cpp implementations do not (Tru64, 313 // for one). 314 cppArgs.push_back(arg_str); 315 break; 316 317 case '-': 318 // command-line configuration parameter: 319 // '--<section>:<parameter>=<value>' 320 321 // Load default.ini if necessary -- see comment in 322 // else clause below. 323 handleDefaultIni(loadDefaultIni, cppArgs); 324 325 if (!simConfigDB.add(arg_str + 2)) { 326 // parse error 327 ccprintf(cerr, 328 "Could not parse configuration argument '%s'\n" 329 "Expecting --<section>:<parameter>=<value>\n", 330 arg_str); 331 exit(0); 332 } 333 break; 334 335 default: 336 showBriefHelp(cerr); 337 ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str); 338 exit(0); 339 } 340 } 341 else { 342 // no '-', treat as config file name 343 344 // make STL string out of file name 345 string filename(arg_str); 346 347 int ext_loc = filename.rfind("."); 348 349 string ext = 350 (ext_loc != string::npos) ? filename.substr(ext_loc) : ""; 351 352 if (ext == ".ini") { 353 // If we haven't loaded default.ini yet, and we want to, 354 // now is the time. Can't do it sooner because we need to 355 // look for '-n', can't do it later since we want 356 // default.ini loaded first (so that any other settings 357 // override it). 358 handleDefaultIni(loadDefaultIni, cppArgs); 359 360 if (!simConfigDB.loadCPP(filename, cppArgs)) { 361 cprintf("Error processing file %s\n", filename); 362 exit(1); 363 } 364 } else if (ext == ".py") { 365 if (!loadPythonConfig(filename, &simConfigDB)) { 366 cprintf("Error processing file %s\n", filename); 367 exit(1); 368 } 369 } 370 else { 371 cprintf("Config file name '%s' must end in '.py' or '.ini'.\n", 372 filename); 373 exit(1); 374 } 375 } 376 } 377 378 // Final check for default.ini, in case no config files or 379 // command-line config parameters were given. 380 handleDefaultIni(loadDefaultIni, cppArgs); 381 382 // The configuration database is now complete; start processing it. 383 384 // Parse and check all non-config-hierarchy parameters. 385 ParamContext::parseAllContexts(simConfigDB); 386 ParamContext::checkAllContexts(); 387 388 // Print header info into stats file. Can't do this sooner since 389 // the stat file name is set via a .ini param... thus it just got 390 // opened above during ParamContext::checkAllContexts(). 391 392 // Print hello message to stats file if it's actually a file. If 393 // it's not (i.e. it's cout or cerr) then we already did it above. 394 if (outputStream != &cout && outputStream != &cerr) 395 sayHello(*outputStream); 396 397 // Echo command line and all parameter settings to stats file as well. 398 echoCommandLine(argc, argv, *outputStream); 399 ParamContext::showAllContexts(*configStream); 400 401 // Now process the configuration hierarchy and create the SimObjects. 402 ConfigHierarchy configHierarchy(simConfigDB); 403 configHierarchy.build(); 404 configHierarchy.createSimObjects(); 405 406 // Restore checkpointed state, if any. 407 configHierarchy.unserializeSimObjects(); 408 409 // Done processing the configuration database. 410 // Check for unreferenced entries. 411 if (simConfigDB.printUnreferenced() && quitOnUnreferenced) { 412 cerr << "Fatal: unreferenced .ini sections/entries." << endl 413 << "If this is not an error, add 'unref_section_ok=y' or " 414 << "'unref_entries_ok=y' to the appropriate sections " 415 << "to suppress this message." << endl; 416 exit(1); 417 } 418 419 SimObject::regAllStats(); 420 421 // uncomment the following to get PC-based execution-time profile 422#ifdef DO_PROFILE 423 init_profile((char *)&_init, (char *)&_fini); 424#endif 425 426 // Check to make sure that the stats package is properly initialized 427 Stats::check(); 428 429 // Reset to put the stats in a consistent state. 430 Stats::reset(); 431 432 // Nothing to simulate if we don't have at least one CPU somewhere. 433 if (BaseCPU::numSimulatedCPUs() == 0) { 434 cerr << "Fatal: no CPUs to simulate." << endl; 435 exit(1); 436 } 437 438 SimInit(); 439 warn("Entering event queue. Starting simulation...\n"); 440 441 while (!mainEventQueue.empty()) { 442 assert(curTick <= mainEventQueue.nextTick() && 443 "event scheduled in the past"); 444 445 // forward current cycle to the time of the first event on the 446 // queue 447 curTick = mainEventQueue.nextTick(); 448 mainEventQueue.serviceOne(); 449 450 if (async_event) { 451 async_event = false; 452 if (async_dump) { 453 async_dump = false; 454 455 using namespace Stats; 456 SetupEvent(Dump, curTick); 457 } 458 459 if (async_dumpreset) { 460 async_dumpreset = false; 461 462 using namespace Stats; 463 SetupEvent(Dump | Reset, curTick); 464 } 465 466 if (async_exit) { 467 async_exit = false; 468 new SimExitEvent("User requested STOP"); 469 } 470 471 if (async_io || async_alarm) { 472 async_io = false; 473 async_alarm = false; 474 pollQueue.service(); 475 } 476 } 477 } 478 479 // This should never happen... every conceivable way for the 480 // simulation to terminate (hit max cycles/insts, signal, 481 // simulated system halts/exits) generates an exit event, so we 482 // should never run out of events on the queue. 483 exitNow("no events on event loop! All CPUs must be idle.", 1); 484 485 return 0; 486} 487