systemc: self-manage TimeSlot in Scheduler

TimeSlot is new and deleted frequently. Having a recycling memory
manager can help saving the time spent new and delete. Tested and see
about 4% improvement in simulation speed.

Change-Id: I0ab173168336a883b85f768d7fdf07a936a14d69
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/34615
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh
index 693cb3a..273faf7 100644
--- a/src/systemc/core/scheduler.hh
+++ b/src/systemc/core/scheduler.hh
@@ -152,14 +152,24 @@
     class TimeSlot : public ::Event
     {
       public:
-        TimeSlot(const Tick& targeted_when) : ::Event(Default_Pri, AutoDelete),
-                                              targeted_when(targeted_when) {}
+        TimeSlot(Scheduler* scheduler) : ::Event(Default_Pri, AutoDelete),
+                                         parent_scheduler(scheduler) {}
         // Event::when() is only set after it's scheduled to an event queue.
         // However, TimeSlot won't be scheduled before init is done. We need
         // to keep the real 'targeted_when' information before scheduled.
         Tick targeted_when;
+        Scheduler* parent_scheduler;
         ScEvents events;
         void process();
+
+      protected:
+        void
+        releaseImpl() override
+        {
+            if (!scheduled())
+                parent_scheduler->releaseTimeSlot(this);
+        }
+
     };
 
     typedef std::list<TimeSlot *> TimeSlots;
@@ -259,7 +269,7 @@
         while (it != timeSlots.end() && (*it)->targeted_when < tick)
             it++;
         if (it == timeSlots.end() || (*it)->targeted_when != tick) {
-            it = timeSlots.emplace(it, new TimeSlot(tick));
+            it = timeSlots.emplace(it, acquireTimeSlot(tick));
             schedule(*it, tick);
         }
         event->schedule((*it)->events, tick);
@@ -386,6 +396,27 @@
     void registerTraceFile(TraceFile *tf) { traceFiles.insert(tf); }
     void unregisterTraceFile(TraceFile *tf) { traceFiles.erase(tf); }
 
+    TimeSlot*
+    acquireTimeSlot(Tick tick)
+    {
+        TimeSlot *ts = nullptr;
+        if (!freeTimeSlots.empty()) {
+            ts = freeTimeSlots.top();
+            freeTimeSlots.pop();
+        } else {
+            ts = new TimeSlot(this);
+        }
+        ts->targeted_when = tick;
+        ts->events.clear();
+        return ts;
+    }
+
+    void
+    releaseTimeSlot(TimeSlot *ts)
+    {
+        freeTimeSlots.push(ts);
+    }
+
   private:
     typedef const EventBase::Priority Priority;
     static Priority DefaultPriority = EventBase::Default_Pri;
@@ -422,6 +453,7 @@
 
     ScEvents deltas;
     TimeSlots timeSlots;
+    std::stack<TimeSlot*> freeTimeSlots;
 
     Process *
     getNextReady()