Time: Add a mechanism to prevent M5 from running faster than real time.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 19 Jan 2011 19:48:00 +0000 (11:48 -0800)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 19 Jan 2011 19:48:00 +0000 (11:48 -0800)
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.

configs/example/fs.py
src/sim/Root.py
src/sim/SConscript
src/sim/root.cc
src/sim/root.hh [new file with mode: 0644]

index a45b48c76987c39822cf69bebc9edcc3d7c2e73e..e9bc9afb66fdb353bd11609adca0b533094fb1d9 100644 (file)
@@ -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)
index 4edcffa2c0f4b9632935a9bbbf1dda7427c17aca..e15de155460b5c41634c52c521a032595d8e5472 100644 (file)
@@ -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")
index 97c6ddaaea927913e2af943f55d785c152dc60b3..f959870cdbc6c55307bfb510b9ef6fa434d1578c 100644 (file)
@@ -73,6 +73,7 @@ TraceFlag('Interrupt')
 TraceFlag('Loader')
 TraceFlag('Stack')
 TraceFlag('SyscallVerbose')
+TraceFlag('TimeSync')
 TraceFlag('TLB')
 TraceFlag('Thread')
 TraceFlag('Timer')
index 2e5c070c8af4b8cf958e1420f163c82866a7f966..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
  *
  * 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 (file)
index 0000000..2beced9
--- /dev/null
@@ -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<Root, &Root::timeSync> syncEvent;
+    friend class EventWrapper<Root, &Root::timeSync>;
+
+  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__