Signed-off-by: Avi Kivity <a...@redhat.com>
---
 config-x86-common.mak |    4 ++-
 x86/pmu.c             |   63 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 1 deletions(-)
 create mode 100644 x86/pmu.c

diff --git a/config-x86-common.mak b/config-x86-common.mak
index 033bae0..7932b5c 100644
--- a/config-x86-common.mak
+++ b/config-x86-common.mak
@@ -34,7 +34,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \
                $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \
                $(TEST_DIR)/kvmclock_test.flat  $(TEST_DIR)/eventinj.flat \
-               $(TEST_DIR)/s3.flat
+               $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat
 
 tests-common += api/api-sample
 tests-common += api/dirty-log
@@ -85,6 +85,8 @@ $(TEST_DIR)/eventinj.elf: $(cstart.o) $(TEST_DIR)/eventinj.o
 
 $(TEST_DIR)/s3.elf: $(cstart.o) $(TEST_DIR)/s3.o
 
+$(TEST_DIR)/pmu.elf: $(cstart.o) $(TEST_DIR)/pmu.o
+
 arch_clean:
        $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
        $(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
diff --git a/x86/pmu.c b/x86/pmu.c
new file mode 100644
index 0000000..1513ea7
--- /dev/null
+++ b/x86/pmu.c
@@ -0,0 +1,63 @@
+
+#include "x86/msr.h"
+#include "x86/processor.h"
+#include "libcflat.h"
+#include <stdint.h>
+
+#define N 1000000
+
+static int tests, failures;
+
+static void loop()
+{
+    unsigned long tmp;
+
+    asm volatile("1: nop; nop; nop; nop; nop; nop; nop; nop; nop; loop 1b"
+                : "=c"(tmp) : "0"(N));
+
+}
+
+static uint64_t measure(uint32_t sel_unit)
+{
+    wrmsr(MSR_IA32_PERFCTR0, 0);
+    wrmsr(MSR_P6_EVNTSEL0, 0x430000 | sel_unit);  // enable
+    loop();
+    wrmsr(MSR_P6_EVNTSEL0, sel_unit); // disable
+    return rdmsr(MSR_IA32_PERFCTR0);
+}
+
+static void report(const char *name, bool pass)
+{
+    printf("%s: pmu %s\n", pass ? "PASS" : "FAIL", name);
+    tests += 1;
+    failures += !pass;
+}
+
+static void check(const char *name, uint32_t sel_unit,
+                 float min, float max)
+{
+    bool pass;
+    uint64_t n;
+
+    n = measure(sel_unit);
+    pass = n >= min * N && n <= max * N;
+    report(name, pass);
+}
+
+static void check_rdpmc(void)
+{
+    uint64_t val = 0x123456789ull;
+    wrmsr(MSR_IA32_PERFCTR0, val);
+    report("rdpmc", rdpmc(0) == (u32)val);
+}
+
+int main(int ac, char **av)
+{
+    check("cycles", 0x003c, 1, 15);
+    check("branches", 0x00c4, 1, 1.1);
+    check("branch misses", 0x00c5, 0, 0.1);
+    check("instructions", 0x00c0, 10, 10.2);
+    check_rdpmc();
+    printf("\n%d tests, %d failures\n", tests, failures);
+    return !failures ? 0 : 1;
+}
-- 
1.7.5.3

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to