main.cc revision 2667:fe64b8353b1c
1/*
2 * Copyright (c) 2000-2005 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 * Authors: Steve Raasch
29 *          Nathan Binkert
30 *          Steve Reinhardt
31 */
32
33///
34/// @file sim/main.cc
35///
36#include <Python.h>	// must be before system headers... see Python docs
37
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <errno.h>
41#include <libgen.h>
42#include <stdlib.h>
43#include <signal.h>
44#include <unistd.h>
45
46#include <list>
47#include <string>
48#include <vector>
49
50#include "base/callback.hh"
51#include "base/inifile.hh"
52#include "base/misc.hh"
53#include "base/output.hh"
54#include "base/pollevent.hh"
55#include "base/statistics.hh"
56#include "base/str.hh"
57#include "base/time.hh"
58#include "cpu/base.hh"
59#include "cpu/smt.hh"
60#include "sim/async.hh"
61#include "sim/builder.hh"
62#include "sim/configfile.hh"
63#include "sim/host.hh"
64#include "sim/sim_events.hh"
65#include "sim/sim_exit.hh"
66#include "sim/sim_object.hh"
67#include "sim/stat_control.hh"
68#include "sim/stats.hh"
69#include "sim/root.hh"
70
71using namespace std;
72
73// See async.h.
74volatile bool async_event = false;
75volatile bool async_dump = false;
76volatile bool async_dumpreset = false;
77volatile bool async_exit = false;
78volatile bool async_io = false;
79volatile bool async_alarm = false;
80
81/// Stats signal handler.
82void
83dumpStatsHandler(int sigtype)
84{
85    async_event = true;
86    async_dump = true;
87}
88
89void
90dumprstStatsHandler(int sigtype)
91{
92    async_event = true;
93    async_dumpreset = true;
94}
95
96/// Exit signal handler.
97void
98exitNowHandler(int sigtype)
99{
100    async_event = true;
101    async_exit = true;
102}
103
104/// Abort signal handler.
105void
106abortHandler(int sigtype)
107{
108    cerr << "Program aborted at cycle " << curTick << endl;
109
110#if TRACING_ON
111    // dump trace buffer, if there is one
112    Trace::theLog.dump(cerr);
113#endif
114}
115
116
117const char *briefCopyright =
118"Copyright (c) 2001-2006\n"
119"The Regents of The University of Michigan\n"
120"All Rights Reserved\n";
121
122/// Print welcome message.
123void
124sayHello(ostream &out)
125{
126    extern const char *compileDate;     // from date.cc
127
128    ccprintf(out, "M5 Simulator System\n");
129    // display copyright
130    ccprintf(out, "%s\n", briefCopyright);
131    ccprintf(out, "M5 compiled %d\n", compileDate);
132    ccprintf(out, "M5 started %s\n", Time::start);
133
134    char *host = getenv("HOSTNAME");
135    if (!host)
136        host = getenv("HOST");
137
138    if (host)
139        ccprintf(out, "M5 executing on %s\n", host);
140}
141
142
143extern "C" { void init_main(); }
144
145int
146main(int argc, char **argv)
147{
148    sayHello(cerr);
149
150    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
151    signal(SIGTRAP, SIG_IGN);
152    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
153    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
154    signal(SIGINT, exitNowHandler);		// dump final stats and exit
155    signal(SIGABRT, abortHandler);
156
157    Py_SetProgramName(argv[0]);
158
159    // default path to m5 python code is the currently executing
160    // file... Python ZipImporter will find embedded zip archive
161    char *pythonpath = argv[0];
162
163    bool interactive = false;
164    bool getopt_done = false;
165    do {
166        switch (getopt(argc, argv, "+p:i")) {
167            // -p <path> prepends <path> to PYTHONPATH instead of
168            // using built-in zip archive.  Useful when
169            // developing/debugging changes to built-in Python
170            // libraries, as the new Python can be tested without
171            // building a new m5 binary.
172          case 'p':
173            pythonpath = optarg;
174            break;
175
176            // -i forces entry into interactive mode after the
177            // supplied script is executed (just like the -i option to
178            // the Python interpreter).
179          case 'i':
180            interactive = true;
181            break;
182
183          case -1:
184            getopt_done = true;
185            break;
186
187          default:
188            fatal("Unrecognized option %c\n", optopt);
189        }
190    } while (!getopt_done);
191
192    // Fix up argc & argv to hide arguments we just processed.
193    // getopt() sets optind to the index of the first non-processed
194    // argv element.
195    argc -= optind;
196    argv += optind;
197
198    // Set up PYTHONPATH to make sure the m5 module is found
199    string newpath(pythonpath);
200
201    char *oldpath = getenv("PYTHONPATH");
202    if (oldpath != NULL) {
203        newpath += ":";
204        newpath += oldpath;
205    }
206
207    if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
208        fatal("setenv: %s\n", strerror(errno));
209
210    // initialize embedded Python interpreter
211    Py_Initialize();
212    PySys_SetArgv(argc, argv);
213
214    // initialize SWIG 'main' module
215    init_main();
216
217    if (argc > 0) {
218        // extra arg(s): first is script file, remaining ones are args
219        // to script file
220        char *filename = argv[0];
221        FILE *fp = fopen(filename, "r");
222        if (!fp) {
223            fatal("cannot open file '%s'\n", filename);
224        }
225
226        PyRun_AnyFile(fp, filename);
227    } else {
228        // no script file argument... force interactive prompt
229        interactive = true;
230    }
231
232    if (interactive) {
233        // The following code to import readline was copied from Python
234        // 2.4.3's Modules/main.c.
235        // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
236        // Python Software Foundation; All Rights Reserved
237        // We should only enable this if we're actually using an
238        // interactive prompt.
239        PyObject *v;
240        v = PyImport_ImportModule("readline");
241        if (v == NULL)
242            PyErr_Clear();
243        else
244            Py_DECREF(v);
245
246        PyRun_InteractiveLoop(stdin, "stdin");
247    }
248
249    // clean up Python intepreter.
250    Py_Finalize();
251}
252
253
254/// Initialize C++ configuration.  Exported to Python via SWIG; invoked
255/// from m5.instantiate().
256void
257initialize()
258{
259    configStream = simout.find("config.out");
260
261    // The configuration database is now complete; start processing it.
262    IniFile inifile;
263    inifile.load("config.ini");
264
265    // Initialize statistics database
266    Stats::InitSimStats();
267
268    // Now process the configuration hierarchy and create the SimObjects.
269    ConfigHierarchy configHierarchy(inifile);
270    configHierarchy.build();
271    configHierarchy.createSimObjects();
272
273    // Parse and check all non-config-hierarchy parameters.
274    ParamContext::parseAllContexts(inifile);
275    ParamContext::checkAllContexts();
276
277    // Echo all parameter settings to stats file as well.
278    ParamContext::showAllContexts(*configStream);
279
280    // Any objects that can't connect themselves until after construction should
281    // do so now
282    SimObject::connectAll();
283
284    // Do a second pass to finish initializing the sim objects
285    SimObject::initAll();
286
287    // Restore checkpointed state, if any.
288    configHierarchy.unserializeSimObjects();
289
290    // Done processing the configuration database.
291    // Check for unreferenced entries.
292    if (inifile.printUnreferenced())
293        panic("unreferenced sections/entries in the intermediate ini file");
294
295    SimObject::regAllStats();
296
297    // uncomment the following to get PC-based execution-time profile
298#ifdef DO_PROFILE
299    init_profile((char *)&_init, (char *)&_fini);
300#endif
301
302    // Check to make sure that the stats package is properly initialized
303    Stats::check();
304
305    // Reset to put the stats in a consistent state.
306    Stats::reset();
307
308    SimStartup();
309}
310
311
312/** Simulate for num_cycles additional cycles.  If num_cycles is -1
313 * (the default), do not limit simulation; some other event must
314 * terminate the loop.  Exported to Python via SWIG.
315 * @return The SimLoopExitEvent that caused the loop to exit.
316 */
317SimLoopExitEvent *
318simulate(Tick num_cycles = -1)
319{
320    warn("Entering event queue @ %d.  Starting simulation...\n", curTick);
321
322    // Fix up num_cycles.  Special default value -1 means simulate
323    // "forever"... schedule event at MaxTick just to be safe.
324    // Otherwise it's a delta for additional cycles to simulate past
325    // curTick, and thus must be non-negative.
326    if (num_cycles == -1)
327        num_cycles = MaxTick;
328    else if (num_cycles < 0)
329        fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
330    else
331        num_cycles = curTick + num_cycles;
332
333    Event *limit_event = new SimLoopExitEvent(num_cycles,
334                                              "simulate() limit reached");
335
336    while (1) {
337        // there should always be at least one event (the SimLoopExitEvent
338        // we just scheduled) in the queue
339        assert(!mainEventQueue.empty());
340        assert(curTick <= mainEventQueue.nextTick() &&
341               "event scheduled in the past");
342
343        // forward current cycle to the time of the first event on the
344        // queue
345        curTick = mainEventQueue.nextTick();
346        Event *exit_event = mainEventQueue.serviceOne();
347        if (exit_event != NULL) {
348            // hit some kind of exit event; return to Python
349            // event must be subclass of SimLoopExitEvent...
350            SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
351            if (se_event == NULL)
352                panic("Bogus exit event class!");
353
354            // if we didn't hit limit_event, delete it
355            if (se_event != limit_event) {
356                assert(limit_event->scheduled());
357                limit_event->deschedule();
358                delete limit_event;
359            }
360
361            return se_event;
362        }
363
364        if (async_event) {
365            async_event = false;
366            if (async_dump) {
367                async_dump = false;
368
369                using namespace Stats;
370                SetupEvent(Dump, curTick);
371            }
372
373            if (async_dumpreset) {
374                async_dumpreset = false;
375
376                using namespace Stats;
377                SetupEvent(Dump | Reset, curTick);
378            }
379
380            if (async_exit) {
381                async_exit = false;
382                exitSimLoop("user interrupt received");
383            }
384
385            if (async_io || async_alarm) {
386                async_io = false;
387                async_alarm = false;
388                pollQueue.service();
389            }
390        }
391    }
392
393    // not reached... only exit is return on SimLoopExitEvent
394}
395
396/**
397 * Queue of C++ callbacks to invoke on simulator exit.
398 */
399CallbackQueue exitCallbacks;
400
401/**
402 * Register an exit callback.
403 */
404void
405registerExitCallback(Callback *callback)
406{
407    exitCallbacks.add(callback);
408}
409
410/**
411 * Do C++ simulator exit processing.  Exported to SWIG to be invoked
412 * when simulator terminates via Python's atexit mechanism.
413 */
414void
415doExitCleanup()
416{
417    exitCallbacks.process();
418    exitCallbacks.clear();
419
420    cout.flush();
421
422    ParamContext::cleanupAllContexts();
423
424    // print simulation stats
425    Stats::DumpNow();
426}
427