Hi -
I get a GPF when I try to run this in qemu on the wrmsr in perf_init.
I put together a minor fix for this (pasted below, and also at
origin/perf-b). If it looks good to you, I'll merge this patch set.
Also, I tried using it on my desktop. The non-interrupt use looks fine:
/ $ perf record -e TLB_FLUSH:STLB_ANY,int=0,icount=0 -- sleep 10
Event: TLB_FLUSH:STLB_ANY
7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
With the interrupt:
/ $ perf record -e TLB_FLUSH:STLB_ANY,int=1,icount=20 -- sleep 10
Event: TLB_FLUSH:STLB_ANY
281474976710643 281474976710636 281474976710636 281474976710636
281474976710636 281474976710636 281474976710636 281474976710636
281474976710636 28147497671
Those are close to negative numbers (e.g. 0xfffffffffff3). Whatever
the issue, we can deal with it in a follow-up patch.
Barret
>From 64d18dc7359cdda1f2980e19db62f0ec6400e31f Mon Sep 17 00:00:00 2001
From: Barret Rhoden <[email protected]>
Date: Wed, 16 Dec 2015 17:14:36 -0500
Subject: x86: Detect and handle missing perf support
If a machine has perf version 0, which is the case for my Qemu, we'll get a
GPF during initialization. The per core initialization and any accesses to
the Qperf file will abort if we don't have the right version.
This assumes that if open of a Qperf fails, that there is no other way for
the user to trigger access to the perf MSRs.
Signed-off-by: Barret Rhoden <[email protected]>
---
kern/arch/x86/devarch.c | 2 ++
kern/arch/x86/init.c | 2 +-
kern/arch/x86/perfmon.c | 24 +++++++++++++-----------
kern/arch/x86/perfmon.h | 4 +++-
kern/arch/x86/smp_boot.c | 4 ++--
5 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/kern/arch/x86/devarch.c b/kern/arch/x86/devarch.c
index 6549891548aa..04dba60d728c 100644
--- a/kern/arch/x86/devarch.c
+++ b/kern/arch/x86/devarch.c
@@ -475,6 +475,8 @@ static struct chan *archopen(struct chan *c, int omode)
c = devopen(c, omode, archdir, Qmax, devgen);
switch ((uint32_t) c->qid.path) {
case Qperf:
+ if (!perfmon_supported())
+ error(ENODEV, "perf is not supported");
assert(!c->aux);
c->aux = arch_create_perf_context();
break;
diff --git a/kern/arch/x86/init.c b/kern/arch/x86/init.c
index fe35276262d1..a2080485938c 100644
--- a/kern/arch/x86/init.c
+++ b/kern/arch/x86/init.c
@@ -80,6 +80,7 @@ void arch_init()
save_fp_state(&x86_default_fpu); /* used in arch/trap.h for fpu init */
pci_init();
vmm_init();
+ perfmon_global_init();
// this returns when all other cores are done and ready to receive IPIs
#ifdef CONFIG_SINGLE_CORE
smp_percpu_init();
@@ -88,7 +89,6 @@ void arch_init()
#endif
proc_init();
- perfmon_init();
cons_irq_init();
intel_lpc_init();
#ifdef CONFIG_ENABLE_LEGACY_USB
diff --git a/kern/arch/x86/perfmon.c b/kern/arch/x86/perfmon.c
index 810be3c6e5ae..4ea89d8f3ba8 100644
--- a/kern/arch/x86/perfmon.c
+++ b/kern/arch/x86/perfmon.c
@@ -291,23 +291,25 @@ static void perfmon_arm_irq(void)
write_mmreg32(LAPIC_LVT_PERFMON, IdtLAPIC_PCINT);
}
-void perfmon_init(void)
+bool perfmon_supported(void)
+{
+ return cpu_caps.perfmon_version >= 2;
+}
+
+void perfmon_global_init(void)
+{
+ perfmon_read_cpu_caps(&cpu_caps);
+}
+
+void perfmon_pcpu_init(void)
{
int i;
+ if (!perfmon_supported())
+ return;
/* Enable user level access to the performance counters */
lcr4(rcr4() | CR4_PCE);
- /* This will be called from every core, no need to execute more than
once.
- * All the call to perfmon_init() will be done when the core boots, so
- * they will be no perfmon users calling it, while
perfmon_read_cpu_caps()
- * is executing.
- * All the cores will be writing the same values, so even from that POV,
- * no serialization is required.
- */
- if (cpu_caps.perfmon_version == 0)
- perfmon_read_cpu_caps(&cpu_caps);
-
/* Reset all the counters and selectors to zero.
*/
write_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
diff --git a/kern/arch/x86/perfmon.h b/kern/arch/x86/perfmon.h
index a655098df9bb..822b96a9e9cf 100644
--- a/kern/arch/x86/perfmon.h
+++ b/kern/arch/x86/perfmon.h
@@ -49,7 +49,9 @@ struct perfmon_status {
uint64_t cores_values[0];
};
-void perfmon_init(void);
+bool perfmon_supported(void);
+void perfmon_global_init(void);
+void perfmon_pcpu_init(void);
void perfmon_interrupt(struct hw_trapframe *hw_tf, void *data);
void perfmon_get_cpu_caps(struct perfmon_cpu_caps *pcc);
int perfmon_open_event(const struct core_set *cset, struct perfmon_session *ps,
diff --git a/kern/arch/x86/smp_boot.c b/kern/arch/x86/smp_boot.c
index 7f6f4d9bf1fb..e248d9edee1f 100644
--- a/kern/arch/x86/smp_boot.c
+++ b/kern/arch/x86/smp_boot.c
@@ -302,7 +302,7 @@ void __arch_pcpu_init(uint32_t coreid)
assert(read_msr(MSR_KERN_GS_BASE) == (uint64_t)pcpui);
/* Don't try setting up til after setting GS */
x86_sysenter_init(x86_get_stacktop_tss(pcpui->tss));
- /* need to init perfctr before potentiall using it in timer handler */
- perfmon_init();
+ /* need to init perfctr before potentially using it in timer handler */
+ perfmon_pcpu_init();
vmm_pcpu_init();
}
--
2.6.0.rc2.230.g3dd15c0
--
You received this message because you are subscribed to the Google Groups
"Akaros" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.