Time: Add a mechanism to prevent M5 from running faster than real time.
[gem5.git] / src / sim / root.cc
index 6348ec1041cb3dc027ae1ee0a4d0b6d0100d49fc..d44c72f4dbc07cef4a447024ec39d25819d0c2d5 100644 (file)
@@ -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
  * 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: Nathan Binkert
+ *          Steve Reinhardt
+ *          Gabe Black
  */
 
-#include <cstring>
-#include <fstream>
-#include <list>
-#include <string>
-#include <vector>
-
 #include "base/misc.hh"
-#include "base/output.hh"
-#include "sim/builder.hh"
-#include "sim/host.hh"
-#include "sim/sim_events.hh"
-#include "sim/sim_object.hh"
+#include "sim/core.hh"
 #include "sim/root.hh"
 
-using namespace std;
-
-Tick curTick = 0;
-ostream *outputStream;
-ostream *configStream;
-
-/// The simulated frequency of curTick. (This is only here for a short time)
-Tick ticksPerSecond;
-
-namespace Clock {
-/// The simulated frequency of curTick. (In ticks per second)
-Tick Frequency;
-
-namespace Float {
-double s;
-double ms;
-double us;
-double ns;
-double ps;
-
-double Hz;
-double kHz;
-double MHz;
-double GHZ;
-/* namespace Float */ }
-
-namespace Int {
-Tick s;
-Tick ms;
-Tick us;
-Tick ns;
-Tick ps;
-/* namespace Float */ }
-
-/* namespace Clock */ }
+Root *Root::_root = NULL;
 
-
-// Dummy Object
-class Root : public SimObject
+/*
+ * 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()
 {
-  private:
-    Tick max_tick;
-    Tick progress_interval;
-
-  public:
-    Root(const std::string &name, Tick maxtick, Tick pi)
-        : SimObject(name), max_tick(maxtick), progress_interval(pi)
-    {}
-
-    virtual void startup();
-};
+    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::startup()
+Root::timeSyncEnable(bool en)
 {
-    if (max_tick != 0)
-        new SimExitEvent(curTick + max_tick, "reached maximum cycle count");
-
-    if (progress_interval != 0)
-        new ProgressEvent(&mainEventQueue, progress_interval);
+    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);
+    }
 }
 
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root)
-
-    Param<Tick> clock;
-    Param<Tick> max_tick;
-    Param<Tick> progress_interval;
-    Param<string> output_file;
-
-END_DECLARE_SIM_OBJECT_PARAMS(Root)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(Root)
+/// Configure the period for time sync events.
+void
+Root::timeSyncPeriod(Time newPeriod)
+{
+    bool en = timeSyncEnabled();
+    _period = newPeriod;
+    _periodTick = _period.nsec() * SimClock::Int::ns +
+                  _period.sec() * SimClock::Int::s;
+    timeSyncEnable(en);
+}
 
-    INIT_PARAM(clock, "tick frequency"),
-    INIT_PARAM(max_tick, "maximum simulation time"),
-    INIT_PARAM(progress_interval, "print a progress message"),
-    INIT_PARAM(output_file, "file to dump simulator output to")
+/// Set the threshold for time remaining to spin wait.
+void
+Root::timeSyncSpinThreshold(Time newThreshold)
+{
+    bool en = timeSyncEnabled();
+    _spinThreshold = newThreshold;
+    timeSyncEnable(en);
+}
 
-END_INIT_SIM_OBJECT_PARAMS(Root)
+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);
+}
 
-CREATE_SIM_OBJECT(Root)
+Root *
+RootParams::create()
 {
     static bool created = false;
     if (created)
@@ -128,29 +125,5 @@ CREATE_SIM_OBJECT(Root)
 
     created = true;
 
-    outputStream = simout.find(output_file);
-    Root *root = new Root(getInstanceName(), max_tick, progress_interval);
-
-    using namespace Clock;
-    Frequency = clock;
-    Float::s = static_cast<double>(Frequency);
-    Float::ms = Float::s / 1.0e3;
-    Float::us = Float::s / 1.0e6;
-    Float::ns = Float::s / 1.0e9;
-    Float::ps = Float::s / 1.0e12;
-
-    Float::Hz  = 1.0 / Float::s;
-    Float::kHz = 1.0 / Float::ms;
-    Float::MHz = 1.0 / Float::us;
-    Float::GHZ = 1.0 / Float::ns;
-
-    Int::s  = Frequency;
-    Int::ms = Int::s / 1000;
-    Int::us = Int::ms / 1000;
-    Int::ns = Int::us / 1000;
-    Int::ps = Int::ns / 1000;
-
-    return root;
+    return new Root(this);
 }
-
-REGISTER_SIM_OBJECT("Root", Root)