aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-06-20 11:50:20 -0400
committerIngo Molnar <mingo@kernel.org>2013-06-20 11:58:57 -0400
commitbde96030f438b5eb6fb74f3bdd06d9f68bb3ba00 (patch)
treeb7e0ab3591d7c43bcbb6f3e68660383eb7a7be5e /kernel/events
parente12cbc10cb27fcbe51b5f68e2015138dc451a2eb (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.c69
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 */
52struct 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 */ 61static DEFINE_PER_CPU(struct bp_cpuinfo, bp_cpuinfo[TYPE_MAX]);
56static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]);
57
58/* Number of pinned task breakpoints in a cpu */
59static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]);
60
61/* Number of non-pinned cpu/task breakpoints in a cpu */
62static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]);
63
64static int nr_slots[TYPE_MAX]; 62static int nr_slots[TYPE_MAX];
65 63
64static 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 */
67static LIST_HEAD(bp_task_head); 70static 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 */
97static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) 100static 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)
180static void toggle_bp_task_slot(struct perf_event *bp, int cpu, 184static 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 */
277static int __reserve_bp_slot(struct perf_event *bp) 280static int __reserve_bp_slot(struct perf_event *bp)
278{ 281{
@@ -622,7 +625,6 @@ static struct pmu perf_breakpoint = {
622 625
623int __init init_hw_breakpoint(void) 626int __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 }