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