perf: Report maximum values for counter overflow
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Jun 2016 19:34:45 +0000 (15:34 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 17 Jun 2016 16:17:55 +0000 (12:17 -0400)
The counters can overflow and wrap around.  Previously, if that happened,
we'd just report the wrapped value.  Now we'll report the maximum value.
Userspace (perf stat) can handle that if we'd like to.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/perfmon.c

index 07afd3c..c313c91 100644 (file)
@@ -306,6 +306,30 @@ static void perfmon_do_cores_free(void *opaque)
        pa->cores_counters[coreno] = (counter_t) err;
 }
 
+/* Helper: Reads a fixed counter's value.  Returns the max amount possible if
+ * the counter overflowed. */
+static uint64_t perfmon_read_fixed_counter(int ccno)
+{
+       uint64_t overflow_status = read_msr(MSR_CORE_PERF_GLOBAL_STATUS);
+
+       if (overflow_status & (1ULL << (32 + ccno)))
+               return (1ULL << cpu_caps.bits_x_fix_counter) - 1;
+       else
+               return read_msr(MSR_CORE_PERF_FIXED_CTR0 + ccno);
+}
+
+/* Helper: Reads an unfixed counter's value.  Returns the max amount possible if
+ * the counter overflowed. */
+static uint64_t perfmon_read_unfixed_counter(int ccno)
+{
+       uint64_t overflow_status = read_msr(MSR_CORE_PERF_GLOBAL_STATUS);
+
+       if (overflow_status & (1ULL << ccno))
+               return (1ULL << cpu_caps.bits_x_counter) - 1;
+       else
+               return read_msr(MSR_IA32_PERFCTR0 + ccno);
+}
+
 static void perfmon_do_cores_status(void *opaque)
 {
        struct perfmon_status_env *env = (struct perfmon_status_env *) opaque;
@@ -315,11 +339,9 @@ static void perfmon_do_cores_status(void *opaque)
 
        spin_lock_irqsave(&cctx->lock);
        if (perfmon_is_fixed_event(&env->pa->ev))
-               env->pef->cores_values[coreno] =
-                   read_msr(MSR_CORE_PERF_FIXED_CTR0 + ccno);
+               env->pef->cores_values[coreno] = perfmon_read_fixed_counter(ccno);
        else
-               env->pef->cores_values[coreno] =
-                   read_msr(MSR_IA32_PERFCTR0 + ccno);
+               env->pef->cores_values[coreno] = perfmon_read_unfixed_counter(ccno);
        spin_unlock_irqsave(&cctx->lock);
 }