changeset 997be6ba467e in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=997be6ba467e
description:
        config: Fix to SystemC example's event handling

        This patch fixes checkpoint restore in the SystemC hosting example by 
handling
        early PollEvent events correctly before any EventQueue events are 
posted.

        The SystemC event queue handler (SCEventQueue) reports an error if the 
event
        loop is entered with no Events posted.  It is possible for this to 
happen
        after instantiate due to PollEvent events.  This patch separates out
        `external' events into a different handler in sc_module.cc to prevent 
the
        error from occurring.

        This fix also improves the event handling of asynchronous events by:

            1) Making asynchronous events 'catch up' gem5 time to SystemC
                time to avoid the appearance that events have been lost
                while servicing an asynchronous event that schedules an
                event loop exit event

            2) Add an in_simulate data member to Module to allow the event
                loop to check whether events should be processed or deferred
                until the next time Module::simulate is entered

            3) Cancel pending events around the entry/exit of the event loop
                in Module::simulate

            4) Moving the state initialisation of the example entirely into
                run to correct a problem with early events in checkpoint
                restore.

        It is still possible to schedule asynchronous events (and talk PollQueue
        actions) while simulate is not running.  This behaviour may stil cause
        some problems.

diffstat:

 util/systemc/Makefile           |    1 +
 util/systemc/main.cc            |  111 ++++++++++++++++++++-------------------
 util/systemc/sc_gem5_control.cc |    5 +-
 util/systemc/sc_logger.cc       |    8 +-
 util/systemc/sc_module.cc       |   81 ++++++++++++++++++++++++++--
 util/systemc/sc_module.hh       |   12 ++++
 6 files changed, 151 insertions(+), 67 deletions(-)

diffs (truncated from 422 to 300 lines):

diff -r 5d7af9fa9809 -r 997be6ba467e util/systemc/Makefile
--- a/util/systemc/Makefile     Tue Dec 02 06:08:06 2014 -0500
+++ b/util/systemc/Makefile     Tue Dec 02 06:08:09 2014 -0500
@@ -66,4 +66,5 @@
 
 clean:
        $(RM) $(ALL)
+       $(RM) *.o
        $(RM) -r m5out
diff -r 5d7af9fa9809 -r 997be6ba467e util/systemc/main.cc
--- a/util/systemc/main.cc      Tue Dec 02 06:08:06 2014 -0500
+++ b/util/systemc/main.cc      Tue Dec 02 06:08:09 2014 -0500
@@ -120,8 +120,6 @@
 
     SimControl(sc_core::sc_module_name name, int argc_, char **argv_);
 
-    void before_end_of_elaboration();
-
     void run();
 };
 
@@ -141,14 +139,26 @@
 
     cxxConfigInit();
 
+    /* Pass DPRINTF messages to SystemC */
     Trace::setDebugLogger(&logger);
 
+    /* @todo need this as an option */
     Gem5SystemC::setTickFrequency();
-    sc_core::sc_set_time_resolution(1, sc_core::SC_PS);
 
+    /* Make a SystemC-synchronising event queue and install it as the
+     *  sole top level gem5 EventQueue */
     Gem5SystemC::Module::setupEventQueues(*this);
+
+    if (sc_core::sc_get_time_resolution() !=
+        sc_core::sc_time(1, sc_core::SC_PS))
+    {
+        fatal("Time resolution must be set to 1 ps for gem5 to work");
+    }
+
+    /* Enable keyboard interrupt, async I/O etc. */
     initSignals();
 
+    /* Enable stats */
     Stats::initSimStats();
     Stats::registerHandlers(CxxConfig::statsReset, CxxConfig::statsDump);
 
@@ -168,10 +178,9 @@
 
     CxxConfigFileBase *conf = new CxxIniFile();
 
-    if (!conf->load(config_file.c_str())) {
-        std::cerr << "Can't open config file: " << config_file << '\n';
-        std::exit(EXIT_FAILURE);
-    }
+    if (!conf->load(config_file.c_str()))
+        fatal("Can't open config file: %s", config_file);
+
     arg_ptr++;
 
     config_manager = new CxxConfigManager(*conf);
@@ -231,8 +240,7 @@
             }
         }
     } catch (CxxConfigManager::Exception &e) {
-        std::cerr << e.name << ": " << e.message << "\n";
-        std::exit(EXIT_FAILURE);
+        fatal("Config problem in sim object %s: %s", e.name, e.message);
     }
 
     CxxConfig::statsEnable();
@@ -241,32 +249,52 @@
     try {
         config_manager->instantiate();
     } catch (CxxConfigManager::Exception &e) {
-        std::cerr << "Config problem in sim object " << e.name
-            << ": " << e.message << "\n";
-
-        std::exit(EXIT_FAILURE);
-    }
-}
-
-void SimControl::before_end_of_elaboration()
-{
-    if (!checkpoint_restore) {
-        try {
-            config_manager->initState();
-            config_manager->startup();
-        } catch (CxxConfigManager::Exception &e) {
-            std::cerr << "Config problem in sim object " << e.name
-                << ": " << e.message << "\n";
-
-            std::exit(EXIT_FAILURE);
-        }
+        fatal("Config problem in sim object %s: %s", e.name, e.message);
     }
 }
 
 void SimControl::run()
 {
+    EventQueue *eventq = getEventQueue(0);
     GlobalSimLoopExitEvent *exit_event = NULL;
 
+    /* There *must* be no scheduled events yet */
+    fatal_if(!eventq->empty(), "There must be no posted events"
+        " before SimControl::run");
+
+    try {
+        if (checkpoint_restore) {
+            std::cerr << "Restoring checkpoint\n";
+
+            Checkpoint *checkpoint = new Checkpoint(checkpoint_dir,
+                config_manager->getSimObjectResolver());
+
+            /* Catch SystemC up with gem5 after checkpoint restore.
+             *  Note that gem5 leading SystemC is always a violation of the
+             *  required relationship between the two, hence this careful
+             *  catchup */
+            Tick systemc_time = sc_core::sc_time_stamp().value();
+            if (curTick() > systemc_time) {
+                Tick wait_period = curTick() - systemc_time;
+
+                std::cerr << "Waiting for " << wait_period << "ps for"
+                    " SystemC to catch up to gem5\n";
+                wait(sc_core::sc_time(wait_period, sc_core::SC_PS));
+            }
+
+            config_manager->loadState(checkpoint);
+            config_manager->startup();
+            config_manager->drainResume();
+        } else {
+            config_manager->initState();
+            config_manager->startup();
+        }
+    } catch (CxxConfigManager::Exception &e) {
+        fatal("Config problem in sim object %s: %s", e.name, e.message);
+    }
+
+    fatal_if(eventq->empty(), "No events to process after system startup");
+
     if (checkpoint_save) {
         exit_event = simulate(pre_run_time);
 
@@ -299,32 +327,6 @@
         config_manager->drainResume();
     }
 
-    if (checkpoint_restore) {
-        std::cerr << "Restoring checkpoint\n";
-
-        Checkpoint *checkpoint = new Checkpoint(checkpoint_dir,
-            config_manager->getSimObjectResolver());
-
-        Serializable::unserializeGlobals(checkpoint);
-
-        /* gem5 time can have changed, so lets wait until SystemC
-         *  catches up */
-        Tick systemc_time = sc_core::sc_time_stamp().value();
-        if (curTick() > systemc_time) {
-            Tick wait_period = curTick() - systemc_time;
-
-            std::cerr << "Waiting for " << wait_period << "ps for"
-                " SystemC to catch up to gem5\n";
-            wait(sc_core::sc_time(wait_period, sc_core::SC_PS));
-        }
-
-        config_manager->loadState(checkpoint);
-
-        config_manager->drainResume();
-
-        std::cerr << "Restored from checkpoint\n";
-    }
-
     if (switch_cpus) {
         exit_event = simulate(pre_switch_time);
 
@@ -350,6 +352,7 @@
 
         old_cpu.switchOut();
         system.setMemoryMode(Enums::timing);
+
         new_cpu.takeOverFrom(&old_cpu);
         config_manager->drainResume();
 
diff -r 5d7af9fa9809 -r 997be6ba467e util/systemc/sc_gem5_control.cc
--- a/util/systemc/sc_gem5_control.cc   Tue Dec 02 06:08:06 2014 -0500
+++ b/util/systemc/sc_gem5_control.cc   Tue Dec 02 06:08:09 2014 -0500
@@ -228,8 +228,11 @@
      *  sole top level gem5 EventQueue */
     Gem5SystemC::Module::setupEventQueues(*this);
 
-    if (sc_core::sc_get_time_resolution() != sc_core::sc_time(1, 
sc_core::SC_PS))
+    if (sc_core::sc_get_time_resolution() !=
+        sc_core::sc_time(1, sc_core::SC_PS))
+    {
         fatal("Time resolution must be set to 1 ps for gem5 to work");
+    }
 
     /* Enable keyboard interrupt, async I/O etc. */
     initSignals();
diff -r 5d7af9fa9809 -r 997be6ba467e util/systemc/sc_logger.cc
--- a/util/systemc/sc_logger.cc Tue Dec 02 06:08:06 2014 -0500
+++ b/util/systemc/sc_logger.cc Tue Dec 02 06:08:09 2014 -0500
@@ -87,10 +87,10 @@
 /** This is pretty much the least efficient way of doing this, but it has the
  *  advantage of having very few corners to get wrong.
  *
- *  A newly allocated streambuf will have no buffer to serve to its [oi]stream.
- *  It will, therefore, call overflow for every character it wants to insert
- *  into the output stream.  Those characters are captured one by one here and
- *  added to this->line. */
+ *  A newly allocated streambuf will have no buffer to serve to its
+ *  [oi]stream.  It will, therefore, call overflow for every character it
+ *  wants to insert into the output stream.  Those characters are captured one
+ *  by one here and added to this->line. */
 int
 CuttingStreambuf::overflow(int chr)
 {
diff -r 5d7af9fa9809 -r 997be6ba467e util/systemc/sc_module.cc
--- a/util/systemc/sc_module.cc Tue Dec 02 06:08:06 2014 -0500
+++ b/util/systemc/sc_module.cc Tue Dec 02 06:08:09 2014 -0500
@@ -76,10 +76,14 @@
     ::setClockFrequency(1000000000000);
 }
 
-Module::Module(sc_core::sc_module_name name) : sc_core::sc_module(name)
+Module::Module(sc_core::sc_module_name name) : sc_core::sc_module(name),
+    in_simulate(false)
 {
     SC_METHOD(eventLoop);
     sensitive << eventLoopEnterEvent;
+    dont_initialize();
+
+    SC_METHOD(serviceExternalEvent);
     sensitive << externalSchedulingEvent;
     dont_initialize();
 }
@@ -95,12 +99,38 @@
 void
 Module::setupEventQueues(Module &module)
 {
+    fatal_if(mainEventQueue.size() != 0,
+        "Gem5SystemC::Module::setupEventQueues must be called"
+        " before any gem5 event queues are set up");
+
     numMainEventQueues = 1;
     mainEventQueue.push_back(new SCEventQueue("events", module));
     curEventQueue(getEventQueue(0));
 }
 
 void
+Module::catchup()
+{
+    EventQueue *eventq = getEventQueue(0);
+    Tick systemc_time = sc_core::sc_time_stamp().value();
+    Tick gem5_time = curTick();
+
+    /* gem5 time *must* lag SystemC as SystemC is the master */
+    fatal_if(gem5_time > systemc_time, "gem5 time must lag SystemC time"
+        " gem5: %d SystemC: %d", gem5_time, systemc_time);
+
+    eventq->setCurTick(systemc_time);
+
+    if (!eventq->empty()) {
+        Tick next_event_time M5_VAR_USED = eventq->nextTick();
+
+        fatal_if(gem5_time > next_event_time,
+            "Missed an event at time %d gem5: %d, SystemC: %d",
+            next_event_time, gem5_time, systemc_time);
+    }
+}
+
+void
 Module::notify(sc_core::sc_time time_from_now)
 {
     externalSchedulingEvent.notify(time_from_now);
@@ -109,8 +139,17 @@
 void
 Module::serviceAsyncEvent()
 {
+    EventQueue *eventq = getEventQueue(0);
+
     assert(async_event);
 
+    /* Catch up gem5 time with SystemC time so that any event here won't
+     * be in the past relative to the current time */
+    Tick systemc_time = sc_core::sc_time_stamp().value();
+
+    /* Move time on to match SystemC */
+    catchup();
+
     async_event = false;
     if (async_statdump || async_statreset) {
         Stats::schedStatEvent(async_statdump, async_statreset);
@@ -133,22 +172,37 @@
 }
 
 void
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to