diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-06-20 11:50:20 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-06-20 11:58:57 -0400 |
commit | bde96030f438b5eb6fb74f3bdd06d9f68bb3ba00 (patch) | |
tree | b7e0ab3591d7c43bcbb6f3e68660383eb7a7be5e /kernel/events | |
parent | e12cbc10cb27fcbe51b5f68e2015138dc451a2eb (diff) |
hw_breakpoint: Introduce "struct bp_cpuinfo"
This patch simply moves all per-cpu variables into the new
single per-cpu "struct bp_cpuinfo".
To me this looks more logical and clean, but this can also
simplify the further potential changes. In particular, I do not
think this memory should be per-cpu, it is never used "locally".
After this change it is trivial to turn it into, say,
bootmem[nr_cpu_ids].
Reported-by: Vince Weaver <vincent.weaver@maine.edu>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Link: http://lkml.kernel.org/r/20130620155020.GA6350@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/hw_breakpoint.c | 69 |
1 files changed, 36 insertions, 33 deletions
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 38418f786f36..1559fb0b9296 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
@@ -46,23 +46,26 @@ | |||
46 | #include <linux/smp.h> | 46 | #include <linux/smp.h> |
47 | 47 | ||
48 | #include <linux/hw_breakpoint.h> | 48 | #include <linux/hw_breakpoint.h> |
49 | |||
50 | |||
51 | /* | 49 | /* |
52 | * Constraints data | 50 | * Constraints data |
53 | */ | 51 | */ |
52 | struct bp_cpuinfo { | ||
53 | /* Number of pinned cpu breakpoints in a cpu */ | ||
54 | unsigned int cpu_pinned; | ||
55 | /* tsk_pinned[n] is the number of tasks having n+1 breakpoints */ | ||
56 | unsigned int *tsk_pinned; | ||
57 | /* Number of non-pinned cpu/task breakpoints in a cpu */ | ||
58 | unsigned int flexible; /* XXX: placeholder, see fetch_this_slot() */ | ||
59 | }; | ||
54 | 60 | ||
55 | /* Number of pinned cpu breakpoints in a cpu */ | 61 | static DEFINE_PER_CPU(struct bp_cpuinfo, bp_cpuinfo[TYPE_MAX]); |
56 | static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]); | ||
57 | |||
58 | /* Number of pinned task breakpoints in a cpu */ | ||
59 | static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]); | ||
60 | |||
61 | /* Number of non-pinned cpu/task breakpoints in a cpu */ | ||
62 | static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]); | ||
63 | |||
64 | static int nr_slots[TYPE_MAX]; | 62 | static int nr_slots[TYPE_MAX]; |
65 | 63 | ||
64 | static struct bp_cpuinfo *get_bp_info(int cpu, enum bp_type_idx type) | ||
65 | { | ||
66 | return per_cpu_ptr(bp_cpuinfo + type, cpu); | ||
67 | } | ||
68 | |||
66 | /* Keep track of the breakpoints attached to tasks */ | 69 | /* Keep track of the breakpoints attached to tasks */ |
67 | static LIST_HEAD(bp_task_head); | 70 | static LIST_HEAD(bp_task_head); |
68 | 71 | ||
@@ -96,8 +99,8 @@ static inline enum bp_type_idx find_slot_idx(struct perf_event *bp) | |||
96 | */ | 99 | */ |
97 | static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) | 100 | static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) |
98 | { | 101 | { |
102 | unsigned int *tsk_pinned = get_bp_info(cpu, type)->tsk_pinned; | ||
99 | int i; | 103 | int i; |
100 | unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); | ||
101 | 104 | ||
102 | for (i = nr_slots[type] - 1; i >= 0; i--) { | 105 | for (i = nr_slots[type] - 1; i >= 0; i--) { |
103 | if (tsk_pinned[i] > 0) | 106 | if (tsk_pinned[i] > 0) |
@@ -146,8 +149,10 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, | |||
146 | int cpu; | 149 | int cpu; |
147 | 150 | ||
148 | for_each_cpu(cpu, cpumask) { | 151 | for_each_cpu(cpu, cpumask) { |
149 | unsigned int nr = per_cpu(nr_cpu_bp_pinned[type], cpu); | 152 | struct bp_cpuinfo *info = get_bp_info(cpu, type); |
153 | int nr; | ||
150 | 154 | ||
155 | nr = info->cpu_pinned; | ||
151 | if (!bp->hw.bp_target) | 156 | if (!bp->hw.bp_target) |
152 | nr += max_task_bp_pinned(cpu, type); | 157 | nr += max_task_bp_pinned(cpu, type); |
153 | else | 158 | else |
@@ -156,8 +161,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, | |||
156 | if (nr > slots->pinned) | 161 | if (nr > slots->pinned) |
157 | slots->pinned = nr; | 162 | slots->pinned = nr; |
158 | 163 | ||
159 | nr = per_cpu(nr_bp_flexible[type], cpu); | 164 | nr = info->flexible; |
160 | |||
161 | if (nr > slots->flexible) | 165 | if (nr > slots->flexible) |
162 | slots->flexible = nr; | 166 | slots->flexible = nr; |
163 | } | 167 | } |
@@ -180,8 +184,7 @@ fetch_this_slot(struct bp_busy_slots *slots, int weight) | |||
180 | static void toggle_bp_task_slot(struct perf_event *bp, int cpu, | 184 | static void toggle_bp_task_slot(struct perf_event *bp, int cpu, |
181 | enum bp_type_idx type, int weight) | 185 | enum bp_type_idx type, int weight) |
182 | { | 186 | { |
183 | /* tsk_pinned[n-1] is the number of tasks having n>0 breakpoints */ | 187 | unsigned int *tsk_pinned = get_bp_info(cpu, type)->tsk_pinned; |
184 | unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); | ||
185 | int old_idx, new_idx; | 188 | int old_idx, new_idx; |
186 | 189 | ||
187 | old_idx = task_bp_pinned(cpu, bp, type) - 1; | 190 | old_idx = task_bp_pinned(cpu, bp, type) - 1; |
@@ -208,7 +211,7 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, | |||
208 | 211 | ||
209 | /* Pinned counter cpu profiling */ | 212 | /* Pinned counter cpu profiling */ |
210 | if (!bp->hw.bp_target) { | 213 | if (!bp->hw.bp_target) { |
211 | per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; | 214 | get_bp_info(bp->cpu, type)->cpu_pinned += weight; |
212 | return; | 215 | return; |
213 | } | 216 | } |
214 | 217 | ||
@@ -240,8 +243,8 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp) | |||
240 | * | 243 | * |
241 | * - If attached to a single cpu, check: | 244 | * - If attached to a single cpu, check: |
242 | * | 245 | * |
243 | * (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu) | 246 | * (per_cpu(info->flexible, cpu) || (per_cpu(info->cpu_pinned, cpu) |
244 | * + max(per_cpu(nr_task_bp_pinned, cpu)))) < HBP_NUM | 247 | * + max(per_cpu(info->tsk_pinned, cpu)))) < HBP_NUM |
245 | * | 248 | * |
246 | * -> If there are already non-pinned counters in this cpu, it means | 249 | * -> If there are already non-pinned counters in this cpu, it means |
247 | * there is already a free slot for them. | 250 | * there is already a free slot for them. |
@@ -251,8 +254,8 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp) | |||
251 | * | 254 | * |
252 | * - If attached to every cpus, check: | 255 | * - If attached to every cpus, check: |
253 | * | 256 | * |
254 | * (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *)) | 257 | * (per_cpu(info->flexible, *) || (max(per_cpu(info->cpu_pinned, *)) |
255 | * + max(per_cpu(nr_task_bp_pinned, *)))) < HBP_NUM | 258 | * + max(per_cpu(info->tsk_pinned, *)))) < HBP_NUM |
256 | * | 259 | * |
257 | * -> This is roughly the same, except we check the number of per cpu | 260 | * -> This is roughly the same, except we check the number of per cpu |
258 | * bp for every cpu and we keep the max one. Same for the per tasks | 261 | * bp for every cpu and we keep the max one. Same for the per tasks |
@@ -263,16 +266,16 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp) | |||
263 | * | 266 | * |
264 | * - If attached to a single cpu, check: | 267 | * - If attached to a single cpu, check: |
265 | * | 268 | * |
266 | * ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu) | 269 | * ((per_cpu(info->flexible, cpu) > 1) + per_cpu(info->cpu_pinned, cpu) |
267 | * + max(per_cpu(nr_task_bp_pinned, cpu))) < HBP_NUM | 270 | * + max(per_cpu(info->tsk_pinned, cpu))) < HBP_NUM |
268 | * | 271 | * |
269 | * -> Same checks as before. But now the nr_bp_flexible, if any, must keep | 272 | * -> Same checks as before. But now the info->flexible, if any, must keep |
270 | * one register at least (or they will never be fed). | 273 | * one register at least (or they will never be fed). |
271 | * | 274 | * |
272 | * - If attached to every cpus, check: | 275 | * - If attached to every cpus, check: |
273 | * | 276 | * |
274 | * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) | 277 | * ((per_cpu(info->flexible, *) > 1) + max(per_cpu(info->cpu_pinned, *)) |
275 | * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM | 278 | * + max(per_cpu(info->tsk_pinned, *))) < HBP_NUM |
276 | */ | 279 | */ |
277 | static int __reserve_bp_slot(struct perf_event *bp) | 280 | static int __reserve_bp_slot(struct perf_event *bp) |
278 | { | 281 | { |
@@ -622,7 +625,6 @@ static struct pmu perf_breakpoint = { | |||
622 | 625 | ||
623 | int __init init_hw_breakpoint(void) | 626 | int __init init_hw_breakpoint(void) |
624 | { | 627 | { |
625 | unsigned int **task_bp_pinned; | ||
626 | int cpu, err_cpu; | 628 | int cpu, err_cpu; |
627 | int i; | 629 | int i; |
628 | 630 | ||
@@ -631,10 +633,11 @@ int __init init_hw_breakpoint(void) | |||
631 | 633 | ||
632 | for_each_possible_cpu(cpu) { | 634 | for_each_possible_cpu(cpu) { |
633 | for (i = 0; i < TYPE_MAX; i++) { | 635 | for (i = 0; i < TYPE_MAX; i++) { |
634 | task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu); | 636 | struct bp_cpuinfo *info = get_bp_info(cpu, i); |
635 | *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i], | 637 | |
636 | GFP_KERNEL); | 638 | info->tsk_pinned = kcalloc(nr_slots[i], sizeof(int), |
637 | if (!*task_bp_pinned) | 639 | GFP_KERNEL); |
640 | if (!info->tsk_pinned) | ||
638 | goto err_alloc; | 641 | goto err_alloc; |
639 | } | 642 | } |
640 | } | 643 | } |
@@ -648,7 +651,7 @@ int __init init_hw_breakpoint(void) | |||
648 | err_alloc: | 651 | err_alloc: |
649 | for_each_possible_cpu(err_cpu) { | 652 | for_each_possible_cpu(err_cpu) { |
650 | for (i = 0; i < TYPE_MAX; i++) | 653 | for (i = 0; i < TYPE_MAX; i++) |
651 | kfree(per_cpu(nr_task_bp_pinned[i], err_cpu)); | 654 | kfree(get_bp_info(err_cpu, i)->tsk_pinned); |
652 | if (err_cpu == cpu) | 655 | if (err_cpu == cpu) |
653 | break; | 656 | break; |
654 | } | 657 | } |