return True
kvmVM = Param.KvmVM(Parent.any, 'KVM VM (i.e., shared memory domain)')
+ usePerfOverflow = Param.Bool(False, "Use perf event overflow counters (EXPERIMENTAL)")
hostFactor = Param.Float(1.0, "Cycle scale factor")
_kvmRun(NULL), mmioRing(NULL),
pageSize(sysconf(_SC_PAGE_SIZE)),
tickEvent(*this),
+ perfControlledByTimer(params->usePerfOverflow),
hostFactor(params->hostFactor)
{
if (pageSize == -1)
setupCounters();
setupSignalHandler();
- runTimer.reset(new PosixKvmTimer(KVM_TIMER_SIGNAL, CLOCK_MONOTONIC,
- params->hostFactor,
- params->clock));
+ if (params->usePerfOverflow)
+ runTimer.reset(new PerfKvmTimer(hwCycles,
+ KVM_TIMER_SIGNAL,
+ params->hostFactor,
+ params->clock));
+ else
+ runTimer.reset(new PosixKvmTimer(KVM_TIMER_SIGNAL, CLOCK_MONOTONIC,
+ params->hostFactor,
+ params->clock));
}
BaseKvmCPU::~BaseKvmCPU()
DPRINTF(KvmRun, "KVM: Executing for %i ticks\n", ticks);
timerOverflowed = false;
+
+ // Arm the run timer and start the cycle timer if it isn't
+ // controlled by the overflow timer. Starting/stopping the cycle
+ // timer automatically starts the other perf timers as they are in
+ // the same counter group.
runTimer->arm(ticks);
- startCounters();
+ if (!perfControlledByTimer)
+ hwCycles.start();
+
if (ioctl(KVM_RUN) == -1) {
if (errno != EINTR)
panic("KVM: Failed to start virtual CPU (errno: %i)\n",
errno);
}
- stopCounters();
+
runTimer->disarm();
+ if (!perfControlledByTimer)
+ hwCycles.stop();
+
uint64_t cyclesExecuted(hwCycles.read() - baseCycles);
Tick ticksExecuted(runTimer->ticksFromHostCycles(cyclesExecuted));
PERF_COUNT_HW_CPU_CYCLES);
cfgCycles.disabled(true)
.pinned(true);
+
+ if (perfControlledByTimer) {
+ // We need to configure the cycles counter to send overflows
+ // since we are going to use it to trigger timer signals that
+ // trap back into m5 from KVM. In practice, this means that we
+ // need to set some non-zero sample period that gets
+ // overridden when the timer is armed.
+ cfgCycles.wakeupEvents(1)
+ .samplePeriod(42);
+ }
+
hwCycles.attach(cfgCycles,
0); // TID (0 => currentThread)
0, // TID (0 => currentThread)
hwCycles);
}
-
-void
-BaseKvmCPU::startCounters()
-{
- // We only need to start/stop the hwCycles counter since hwCycles
- // and hwInstructions are a counter group with hwCycles as the
- // group leader.
- hwCycles.start();
-}
-
-void
-BaseKvmCPU::stopCounters()
-{
- hwCycles.stop();
-}
/** Setup hardware performance counters */
void setupCounters();
- /** @{ */
- /** Start/stop counting HW performance events */
- void startCounters();
- void stopCounters();
- /** @} */
-
/** KVM vCPU file descriptor */
int vcpuFD;
/** Size of MMAPed kvm_run area */
PerfKvmCounter hwInstructions;
/** @} */
+ /**
+ * Does the runTimer control the performance counters?
+ *
+ * The run timer will automatically enable and disable performance
+ * counters if a PerfEvent-based timer is used to control KVM
+ * exits.
+ */
+ bool perfControlledByTimer;
+
/**
* Timer used to force execution into the monitor after a
* specified number of simulation tick equivalents have executed
* like the new period isn't effective until after the next
* counter overflow. If you use this method to change the sample
* period, you will see one sample with the old period and then
- * start sampling with the new period.
+ * start sampling with the new period. This problem was fixed for
+ * ARM in version 3.7 of the kernel.
*
* @warning This method doesn't work at all on some 2.6.3x kernels
* since it has inverted check for the return value when copying
return resolution;
}
+
+
+PerfKvmTimer::PerfKvmTimer(PerfKvmCounter &ctr,
+ int signo, float hostFactor, Tick hostFreq)
+ : BaseKvmTimer(signo, hostFactor, hostFreq),
+ hwOverflow(ctr)
+{
+ hwOverflow.enableSignals(signo);
+}
+
+PerfKvmTimer::~PerfKvmTimer()
+{
+}
+
+void
+PerfKvmTimer::arm(Tick ticks)
+{
+ hwOverflow.period(hostCycles(ticks));
+ hwOverflow.refresh(1);
+}
+
+void
+PerfKvmTimer::disarm()
+{
+ hwOverflow.stop();
+}
+
+Tick
+PerfKvmTimer::calcResolution()
+{
+ // This is a bit arbitrary, but in practice, we can't really do
+ // anything useful in less than ~1000 anyway.
+ return ticksFromHostCycles(1000);
+}
#include <ctime>
+#include "cpu/kvm/perfevent.hh"
#include "sim/core.hh"
/**
timer_t timer;
};
+/**
+ * PerfEvent based timer using the host's CPU cycle counter.
+ *
+ * @warning There is a known problem in some versions of the PerfEvent
+ * API that prevents the counter overflow period from being updated
+ * reliably, which might break this timer. See PerfKvmCounter::period()
+ * for details.
+ */
+class PerfKvmTimer : public BaseKvmTimer
+{
+ public:
+ /**
+ * Create a timer that uses an existing hardware cycle counter.
+ *
+ * @note The performance counter must be configured for overflow
+ * sampling, which in practice means that it must have a non-zero
+ * sample period. The initial sample period is ignored since
+ * period will be updated when arm() is called.
+ *
+ * @param ctr Attached performance counter configured for overflow
+ * reporting.
+ * @param signo Signal to deliver
+ * @param hostFactor Performance scaling factor
+ * @param hostFreq Clock frequency of the host
+ */
+ PerfKvmTimer(PerfKvmCounter &ctr,
+ int signo,
+ float hostFactor, Tick hostFreq);
+ ~PerfKvmTimer();
+
+ void arm(Tick ticks);
+ void disarm();
+
+ protected:
+ Tick calcResolution();
+
+ private:
+ PerfKvmCounter &hwOverflow;
+};
+
#endif