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