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