perf: Report errors when counter setup fails
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 14 Jun 2016 19:40:18 +0000 (15:40 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 17 Jun 2016 16:17:54 +0000 (12:17 -0400)
Previously, the kernel would return a negative value for PED, but perf
would ignore it.  Then later we'd try to close it and would get a cryptic
value back (negative value out of range).

Now we try to provide helpful errstrs.

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

index f9150ea..07afd3c 100644 (file)
@@ -197,6 +197,29 @@ static void perfmon_set_unfixed_trigger(unsigned int idx, uint64_t count)
        write_msr(MSR_IA32_PERFCTR0 + idx, write_val);
 }
 
+/* Helper: sets errno/errstr based on the error code returned from the core.  We
+ * don't have a great way to get errors back from smp_do_in_cores() commands.
+ * We use negative counter values (e.g. i = -EBUSY) to signal an error of a
+ * certain type.  This converts that to something useful for userspace. */
+static void perfmon_convert_error(int err_code, int core_id)
+{
+       switch (err_code) {
+       case EBUSY:
+               set_error(err_code, "Fixed perf counter is busy on core %d", core_id);
+               break;
+       case ENOSPC:
+               set_error(err_code, "Perf counter idx out of range on core %d",
+                         core_id);
+               break;
+       case ENOENT:
+               set_error(err_code, "Perf counter not set on core %d", core_id);
+               break;
+       default:
+               set_error(err_code, "Unknown perf counter error on core %d", core_id);
+               break;
+       };
+}
+
 static void perfmon_do_cores_alloc(void *opaque)
 {
        struct perfmon_alloc *pa = (struct perfmon_alloc *) opaque;
@@ -210,7 +233,7 @@ static void perfmon_do_cores_alloc(void *opaque)
 
                i = PMEV_GET_EVENT(pa->ev.event);
                if (i >= (int) cpu_caps.fix_counters_x_proc) {
-                       i = -EINVAL;
+                       i = -ENOSPC;
                } else if (!perfmon_fix_event_available(i, fxctrl_value)) {
                        i = -EBUSY;
                } else {
@@ -484,7 +507,8 @@ int perfmon_open_event(const struct core_set *cset, struct perfmon_session *ps,
 
                        if (unlikely(ccno < 0)) {
                                perfmon_destroy_alloc(pa);
-                               return (int) ccno;
+                               perfmon_convert_error(-(int)ccno, i);
+                               return -1;
                        }
                }
        }
index 3e60fda..915d92c 100644 (file)
@@ -579,6 +579,11 @@ void perf_context_event_submit(struct perf_context *pctx,
        pevt->cores = *cores;
        pevt->sel = *sel;
        pevt->ped = perf_open_event(pctx->perf_fd, cores, sel);
+       if (pevt->ped < 0) {
+               fprintf(stderr, "Unable to submit event \"%s\": %s\n", sel->fq_str,
+                       errstr());
+               exit(1);
+       }
 }
 
 void perf_context_show_values(struct perf_context *pctx, FILE *file)