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