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