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