x86, perf_counter, bts: Fail if BTS is not available
authormarkus.t.metzger@intel.com <markus.t.metzger@intel.com>
Wed, 2 Sep 2009 14:04:46 +0000 (16:04 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 4 Sep 2009 07:26:39 +0000 (09:26 +0200)
Reserve PERF_COUNT_HW_BRANCH_INSTRUCTIONS with sample_period ==
1 for BTS tracing and fail, if BTS is not available.

Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20090902140612.943801000@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/cpu/perf_counter.c

index 396e35d..2f41874 100644 (file)
@@ -769,7 +769,7 @@ static int reserve_bts_hardware(void)
        int cpu, err = 0;
 
        if (!bts_available())
-               return -EOPNOTSUPP;
+               return 0;
 
        get_online_cpus();
 
@@ -914,7 +914,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
                        if (!reserve_pmc_hardware())
                                err = -EBUSY;
                        else
-                               reserve_bts_hardware();
+                               err = reserve_bts_hardware();
                }
                if (!err)
                        atomic_inc(&active_counters);
@@ -979,6 +979,13 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
        if (config == -1LL)
                return -EINVAL;
 
+       /*
+        * Branch tracing:
+        */
+       if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
+           (hwc->sample_period == 1) && !bts_available())
+               return -EOPNOTSUPP;
+
        hwc->config |= config;
 
        return 0;
@@ -1355,19 +1362,9 @@ static int x86_pmu_enable(struct perf_counter *counter)
 
        idx = fixed_mode_idx(counter, hwc);
        if (idx == X86_PMC_IDX_FIXED_BTS) {
-               /*
-                * Try to use BTS for branch tracing. If that is not
-                * available, try to get a generic counter.
-                */
-               if (unlikely(!cpuc->ds))
-                       goto try_generic;
-
-               /*
-                * Try to get the fixed counter, if that is already taken
-                * then try to get a generic counter:
-                */
+               /* BTS is already occupied. */
                if (test_and_set_bit(idx, cpuc->used_mask))
-                       goto try_generic;
+                       return -EAGAIN;
 
                hwc->config_base        = 0;
                hwc->counter_base       = 0;