diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2011-01-19 11:48:00 -0800 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2011-01-19 11:48:00 -0800 |
commit | a368fba7d4fa01b58d5c2d9b3cafd56e1102287c (patch) | |
tree | 02c8d6444104f785014fda27c966e7a82d21d766 /src/sim/root.cc | |
parent | f7885b8f260ca11c2f4a405525d9fc4e554f41a8 (diff) | |
download | gem5-a368fba7d4fa01b58d5c2d9b3cafd56e1102287c.tar.xz |
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.
Diffstat (limited to 'src/sim/root.cc')
-rw-r--r-- | src/sim/root.cc | 89 |
1 files changed, 83 insertions, 6 deletions
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() |