changeset 553ad940c9db in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=553ad940c9db
description:
        kvm: Avoid synchronizing the TC on every KVM exit

        Reduce the number of KVM->TC synchronizations by overloading the
        getContext() method and only request an update when the TC is
        requested as opposed to every time KVM returns to gem5.

diffstat:

 src/cpu/base.hh     |   2 +-
 src/cpu/kvm/base.cc |  67 +++++++++++++++++++++++++++++++++++++++++++---------
 src/cpu/kvm/base.hh |  35 ++++++++++++++++++++++++++-
 3 files changed, 89 insertions(+), 15 deletions(-)

diffs (214 lines):

diff -r f551c8ad12a5 -r 553ad940c9db src/cpu/base.hh
--- a/src/cpu/base.hh   Mon Apr 22 13:20:32 2013 -0400
+++ b/src/cpu/base.hh   Mon Apr 22 13:20:32 2013 -0400
@@ -252,7 +252,7 @@
    int findContext(ThreadContext *tc);
 
    /// Given a thread num get tho thread context for it
-   ThreadContext *getContext(int tn) { return threadContexts[tn]; }
+   virtual ThreadContext *getContext(int tn) { return threadContexts[tn]; }
 
   public:
     typedef BaseCPUParams Params;
diff -r f551c8ad12a5 -r 553ad940c9db src/cpu/kvm/base.cc
--- a/src/cpu/kvm/base.cc       Mon Apr 22 13:20:32 2013 -0400
+++ b/src/cpu/kvm/base.cc       Mon Apr 22 13:20:32 2013 -0400
@@ -72,7 +72,8 @@
       _status(Idle),
       dataPort(name() + ".dcache_port", this),
       instPort(name() + ".icache_port", this),
-      contextDirty(true),
+      threadContextDirty(true),
+      kvmStateDirty(false),
       vcpuID(vm.allocVCPUID()), vcpuFD(-1), vcpuMMapSize(0),
       _kvmRun(NULL), mmioRing(NULL),
       pageSize(sysconf(_SC_PAGE_SIZE)),
@@ -205,6 +206,9 @@
 void
 BaseKvmCPU::serializeThread(std::ostream &os, ThreadID tid)
 {
+    // Update the thread context so we have something to serialize.
+    syncThreadContext();
+
     assert(tid == 0);
     assert(_status == Idle);
     thread->serialize(os);
@@ -217,7 +221,7 @@
     assert(tid == 0);
     assert(_status == Idle);
     thread->unserialize(cp, section);
-    contextDirty = true;
+    threadContextDirty = true;
 }
 
 unsigned int
@@ -263,10 +267,14 @@
 void
 BaseKvmCPU::switchOut()
 {
+    DPRINTF(Kvm, "switchOut\n");
+
+    // Make sure to update the thread context in case, the new CPU
+    // will need to access it.
+    syncThreadContext();
+
     BaseCPU::switchOut();
 
-    DPRINTF(Kvm, "switchOut\n");
-
     // We should have drained prior to executing a switchOut, which
     // means that the tick event shouldn't be scheduled and the CPU is
     // idle.
@@ -288,8 +296,9 @@
     assert(_status == Idle);
     assert(threadContexts.size() == 1);
 
-    // Force a gem5 -> KVM context synchronization
-    contextDirty = true;
+    // The BaseCPU updated the thread context, make sure that we
+    // synchronize next time we enter start the CPU.
+    threadContextDirty = true;
 }
 
 void
@@ -368,6 +377,15 @@
     suspendContext(thread_num);
 }
 
+ThreadContext *
+BaseKvmCPU::getContext(int tn)
+{
+    assert(tn == 0);
+    syncThreadContext();
+    return tc;
+}
+
+
 Counter
 BaseKvmCPU::totalInsts() const
 {
@@ -394,14 +412,8 @@
 
     DPRINTF(KvmRun, "Entering KVM...\n");
 
-    if (contextDirty) {
-        contextDirty = false;
-        updateKvmState();
-    }
-
     Tick ticksToExecute(mainEventQueue.nextTick() - curTick());
     Tick ticksExecuted(kvmRun(ticksToExecute));
-    updateThreadContext();
 
     Tick delay(ticksExecuted + handleKvmExit());
 
@@ -423,6 +435,13 @@
     uint64_t baseCycles(hwCycles.read());
     uint64_t baseInstrs(hwInstructions.read());
 
+    // We might need to update the KVM state.
+    syncKvmState();
+    // Entering into KVM implies that we'll have to reload the thread
+    // context from KVM if we want to access it. Flag the KVM state as
+    // dirty with respect to the cached thread context.
+    kvmStateDirty = true;
+
     if (ticks < runTimer->resolution()) {
         DPRINTF(KvmRun, "KVM: Adjusting tick count (%i -> %i)\n",
                 ticks, runTimer->resolution());
@@ -604,6 +623,30 @@
 #endif
 }
 
+void
+BaseKvmCPU::syncThreadContext()
+{
+    if (!kvmStateDirty)
+        return;
+
+    assert(!threadContextDirty);
+
+    updateThreadContext();
+    kvmStateDirty = false;
+}
+
+void
+BaseKvmCPU::syncKvmState()
+{
+    if (!threadContextDirty)
+        return;
+
+    assert(!kvmStateDirty);
+
+    updateKvmState();
+    threadContextDirty = false;
+}
+
 Tick
 BaseKvmCPU::handleKvmExit()
 {
diff -r f551c8ad12a5 -r 553ad940c9db src/cpu/kvm/base.hh
--- a/src/cpu/kvm/base.hh       Mon Apr 22 13:20:32 2013 -0400
+++ b/src/cpu/kvm/base.hh       Mon Apr 22 13:20:32 2013 -0400
@@ -102,13 +102,27 @@
     void deallocateContext(ThreadID thread_num);
     void haltContext(ThreadID thread_num);
 
+    ThreadContext *getContext(int tn);
+
     Counter totalInsts() const;
     Counter totalOps() const;
 
     /** Dump the internal state to the terminal. */
     virtual void dump();
 
-    /** SimpleThread object, provides all the architectural state. */
+    /**
+     * A cached copy of a thread's state in the form of a SimpleThread
+     * object.
+     *
+     * Normally the actual thread state is stored in the KVM vCPU. If KVM has
+     * been running this copy is will be out of date. If we recently handled
+     * some events within gem5 that required state to be updated this could be
+     * the most up-to-date copy. When getContext() or updateThreadContext() is
+     * called this copy gets updated.  The method syncThreadContext can
+     * be used within a KVM CPU to update the thread context if the
+     * KVM state is dirty (i.e., the vCPU has been run since the last
+     * update).
+     */
     SimpleThread *thread;
 
     /** ThreadContext object, provides an interface for external
@@ -272,6 +286,17 @@
      * and update gem5's thread state.
      */
     virtual void updateThreadContext() = 0;
+
+    /**
+     * Update a thread context if the KVM state is dirty with respect
+     * to the cached thread context.
+     */
+    void syncThreadContext();
+
+    /**
+     * Update the KVM if the thread context is dirty.
+     */
+    void syncKvmState();
     /** @} */
 
     /** @{ */
@@ -391,7 +416,13 @@
      * Is the gem5 context dirty? Set to true to force an update of
      * the KVM vCPU state upon the next call to kvmRun().
      */
-    bool contextDirty;
+    bool threadContextDirty;
+
+    /**
+     * Is the KVM state dirty? Set to true to force an update of
+     * the KVM vCPU state upon the next call to kvmRun().
+     */
+    bool kvmStateDirty;
 
     /** KVM internal ID of the vCPU */
     const long vcpuID;
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to