From: Gabe Black Date: Wed, 19 Jan 2011 19:48:00 +0000 (-0800) Subject: Time: Add a mechanism to prevent M5 from running faster than real time. X-Git-Tag: stable_2012_02_02~635 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a368fba7d4fa01b58d5c2d9b3cafd56e1102287c;p=gem5.git Time: Add a mechanism to prevent M5 from running faster than real time. M5 skips over any simulated time where it doesn't have any work to do. When the simulation is active, the time skipped is short and the work done at any point in time is relatively substantial. If the time between events is long and/or the work to do at each event is small, it's possible for simulated time to pass faster than real time. When running a benchmark that can be good because it means the simulation will finish sooner in real time. When interacting with the real world through, for instance, a serial terminal or bridge to a real network, this can be a problem. Human or network response time could be greatly exagerated from the perspective of the simulation and make simulated events happen "too soon" from an external perspective. This change adds the capability to force the simulation to run no faster than real time. It does so by scheduling a periodic event that checks to see if its simulated period is shorter than its real period. If it is, it stalls the simulation until they're equal. This is called time syncing. A future change could add pseudo instructions which turn time syncing on and off from within the simulation. That would allow time syncing to be used for the interactive parts of a session but then turned off when running a benchmark using the m5 utility program inside a script. Time syncing would probably not happen anyway while running a benchmark because there would be plenty of work for M5 to do, but the event overhead could be avoided. --- diff --git a/configs/example/fs.py b/configs/example/fs.py index a45b48c76..e9bc9afb6 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -65,6 +65,10 @@ config_root = os.path.dirname(config_path) parser = optparse.OptionParser() +# Simulation options +parser.add_option("--timesync", action="store_true", + help="Prevent simulated time from getting ahead of real time") + # System options parser.add_option("--kernel", action="store", type="string") parser.add_option("--script", action="store", type="string") @@ -187,4 +191,7 @@ else: print "Error I don't know how to create more than 2 systems." sys.exit(1) +if options.timesync: + root.time_sync_enable = True + Simulation.run(options, root, test_sys, FutureClass) diff --git a/src/sim/Root.py b/src/sim/Root.py index 4edcffa2c..e15de1554 100644 --- a/src/sim/Root.py +++ b/src/sim/Root.py @@ -57,4 +57,9 @@ class Root(SimObject): return 'root' type = 'Root' - dummy = Param.Int(0, "We don't support objects without params") + + # Time syncing prevents the simulation from running faster than real time. + time_sync_enable = Param.Bool(False, "whether time syncing is enabled") + time_sync_period = Param.Clock("100ms", "how often to sync with real time") + time_sync_spin_threshold = \ + Param.Clock("100us", "when less than this much time is left, spin") diff --git a/src/sim/SConscript b/src/sim/SConscript index 97c6ddaae..f959870cd 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -73,6 +73,7 @@ TraceFlag('Interrupt') TraceFlag('Loader') TraceFlag('Stack') TraceFlag('SyscallVerbose') +TraceFlag('TimeSync') TraceFlag('TLB') TraceFlag('Thread') TraceFlag('Timer') diff --git a/src/sim/root.cc b/src/sim/root.cc index 2e5c070c8..d44c72f4d 100644 --- a/src/sim/root.cc +++ b/src/sim/root.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2011 Advanced Micro Devices * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,17 +28,93 @@ * * Authors: Nathan Binkert * Steve Reinhardt + * Gabe Black */ #include "base/misc.hh" -#include "params/Root.hh" -#include "sim/sim_object.hh" +#include "sim/core.hh" +#include "sim/root.hh" -// Dummy Object -struct Root : public SimObject +Root *Root::_root = NULL; + +/* + * This function is called periodically by an event in M5 and ensures that + * at least as much real time has passed between invocations as simulated time. + * If not, the function either sleeps, or if the difference is small enough + * spin waits. + */ +void +Root::timeSync() +{ + Time cur_time, diff, period = timeSyncPeriod(); + + do { + cur_time.setTimer(); + diff = cur_time - lastTime; + Time remainder = period - diff; + if (diff < period && remainder > _spinThreshold) { + DPRINTF(TimeSync, "Sleeping to sync with real time.\n"); + // Sleep until the end of the period, or until a signal. + sleep(remainder); + // Refresh the current time. + cur_time.setTimer(); + } + } while (diff < period); + lastTime = cur_time; + schedule(&syncEvent, curTick() + _periodTick); +} + +void +Root::timeSyncEnable(bool en) +{ + if (en == _enabled) + return; + _enabled = en; + if (_enabled) { + // Get event going. + Tick periods = ((curTick() + _periodTick - 1) / _periodTick); + Tick nextPeriod = periods * _periodTick; + schedule(&syncEvent, nextPeriod); + } else { + // Stop event. + deschedule(&syncEvent); + } +} + +/// Configure the period for time sync events. +void +Root::timeSyncPeriod(Time newPeriod) { - Root(RootParams *params) : SimObject(params) {} -}; + bool en = timeSyncEnabled(); + _period = newPeriod; + _periodTick = _period.nsec() * SimClock::Int::ns + + _period.sec() * SimClock::Int::s; + timeSyncEnable(en); +} + +/// Set the threshold for time remaining to spin wait. +void +Root::timeSyncSpinThreshold(Time newThreshold) +{ + bool en = timeSyncEnabled(); + _spinThreshold = newThreshold; + timeSyncEnable(en); +} + +Root::Root(RootParams *p) : SimObject(p), _enabled(false), + _periodTick(p->time_sync_period), syncEvent(this) +{ + uint64_t nsecs = p->time_sync_period / SimClock::Int::ns; + _period.set(nsecs / Time::NSEC_PER_SEC, nsecs % Time::NSEC_PER_SEC); + nsecs = p->time_sync_spin_threshold / SimClock::Int::ns; + _spinThreshold.set(nsecs / Time::NSEC_PER_SEC, + nsecs % Time::NSEC_PER_SEC); + + assert(_root == NULL); + _root = this; + lastTime.setTimer(); + timeSyncEnable(p->time_sync_enable); +} Root * RootParams::create() diff --git a/src/sim/root.hh b/src/sim/root.hh new file mode 100644 index 000000000..2beced9d4 --- /dev/null +++ b/src/sim/root.hh @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Advanced Micro Devices + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +/** + * @file This file defines the Root simobject and the methods used to control + * the time syncing mechanism provided through it. + * + * Time syncing prevents simulated time from passing faster than real time. It + * works by scheduling a periodic event that checks to see if its simulated + * period is shorter than its real period. If it is, it stalls the simulation + * until they're equal. + */ + +#ifndef __SIM_ROOT_HH__ +#define __SIM_ROOT_HH__ + +#include "base/time.hh" +#include "params/Root.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Root : public SimObject +{ + private: + static Root *_root; + + protected: + bool _enabled; + Time _period; + Tick _periodTick; + Time _spinThreshold; + + Time lastTime; + + void timeSync(); + EventWrapper syncEvent; + friend class EventWrapper; + + public: + /** + * Use this function to get a pointer to the single Root object in the + * simulation. This function asserts that such an object has actual been + * constructed to avoid having to perform that check everywhere the root + * is used. This is to allow calling the functions below. + * + * @return Pointer to the single root object. + */ + static Root * + root() + { + assert(_root); + return _root; + } + + public: + + /// Check whether time syncing is enabled. + bool timeSyncEnabled() const { return _enabled; } + /// Retrieve the period for the sync event. + const Time timeSyncPeriod() const { return _period; } + /// Retrieve the threshold for time remaining to spin wait. + const Time timeSyncSpinThreshold() const { return _spinThreshold; } + + /// Enable or disable time syncing. + void timeSyncEnable(bool en); + /// Configure the period for time sync events. + void timeSyncPeriod(Time newPeriod); + /// Set the threshold for time remaining to spin wait. + void timeSyncSpinThreshold(Time newThreshold); + + Root(RootParams *p); +}; + +#endif // __SIM_ROOT_HH__