diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-03-27 04:46:19 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-03-27 04:46:19 -0400 |
commit | 936c663aed930972f7e185485fd6c2da69e33819 (patch) | |
tree | 41bb069f66e109fc63c4114a4390de44d3068356 /kernel/events | |
parent | 072e5a1cfabca7276744d24726e094d85721df5c (diff) | |
parent | 50f16a8bf9d7a92c437ed1867d0f7e1dc6a9aca9 (diff) |
Merge branch 'perf/x86' into perf/core, because it's ready
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/core.c | 73 | ||||
-rw-r--r-- | kernel/events/hw_breakpoint.c | 8 |
2 files changed, 29 insertions, 52 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index 9a5f339a0e2d..b01dfb602db1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -34,11 +34,11 @@ | |||
34 | #include <linux/syscalls.h> | 34 | #include <linux/syscalls.h> |
35 | #include <linux/anon_inodes.h> | 35 | #include <linux/anon_inodes.h> |
36 | #include <linux/kernel_stat.h> | 36 | #include <linux/kernel_stat.h> |
37 | #include <linux/cgroup.h> | ||
37 | #include <linux/perf_event.h> | 38 | #include <linux/perf_event.h> |
38 | #include <linux/ftrace_event.h> | 39 | #include <linux/ftrace_event.h> |
39 | #include <linux/hw_breakpoint.h> | 40 | #include <linux/hw_breakpoint.h> |
40 | #include <linux/mm_types.h> | 41 | #include <linux/mm_types.h> |
41 | #include <linux/cgroup.h> | ||
42 | #include <linux/module.h> | 42 | #include <linux/module.h> |
43 | #include <linux/mman.h> | 43 | #include <linux/mman.h> |
44 | #include <linux/compat.h> | 44 | #include <linux/compat.h> |
@@ -351,32 +351,6 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx, | |||
351 | 351 | ||
352 | #ifdef CONFIG_CGROUP_PERF | 352 | #ifdef CONFIG_CGROUP_PERF |
353 | 353 | ||
354 | /* | ||
355 | * perf_cgroup_info keeps track of time_enabled for a cgroup. | ||
356 | * This is a per-cpu dynamically allocated data structure. | ||
357 | */ | ||
358 | struct perf_cgroup_info { | ||
359 | u64 time; | ||
360 | u64 timestamp; | ||
361 | }; | ||
362 | |||
363 | struct perf_cgroup { | ||
364 | struct cgroup_subsys_state css; | ||
365 | struct perf_cgroup_info __percpu *info; | ||
366 | }; | ||
367 | |||
368 | /* | ||
369 | * Must ensure cgroup is pinned (css_get) before calling | ||
370 | * this function. In other words, we cannot call this function | ||
371 | * if there is no cgroup event for the current CPU context. | ||
372 | */ | ||
373 | static inline struct perf_cgroup * | ||
374 | perf_cgroup_from_task(struct task_struct *task) | ||
375 | { | ||
376 | return container_of(task_css(task, perf_event_cgrp_id), | ||
377 | struct perf_cgroup, css); | ||
378 | } | ||
379 | |||
380 | static inline bool | 354 | static inline bool |
381 | perf_cgroup_match(struct perf_event *event) | 355 | perf_cgroup_match(struct perf_event *event) |
382 | { | 356 | { |
@@ -3220,7 +3194,10 @@ static void __perf_event_read(void *info) | |||
3220 | 3194 | ||
3221 | static inline u64 perf_event_count(struct perf_event *event) | 3195 | static inline u64 perf_event_count(struct perf_event *event) |
3222 | { | 3196 | { |
3223 | return local64_read(&event->count) + atomic64_read(&event->child_count); | 3197 | if (event->pmu->count) |
3198 | return event->pmu->count(event); | ||
3199 | |||
3200 | return __perf_event_count(event); | ||
3224 | } | 3201 | } |
3225 | 3202 | ||
3226 | static u64 perf_event_read(struct perf_event *event) | 3203 | static u64 perf_event_read(struct perf_event *event) |
@@ -7149,7 +7126,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
7149 | struct perf_event *group_leader, | 7126 | struct perf_event *group_leader, |
7150 | struct perf_event *parent_event, | 7127 | struct perf_event *parent_event, |
7151 | perf_overflow_handler_t overflow_handler, | 7128 | perf_overflow_handler_t overflow_handler, |
7152 | void *context) | 7129 | void *context, int cgroup_fd) |
7153 | { | 7130 | { |
7154 | struct pmu *pmu; | 7131 | struct pmu *pmu; |
7155 | struct perf_event *event; | 7132 | struct perf_event *event; |
@@ -7204,16 +7181,12 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
7204 | 7181 | ||
7205 | if (task) { | 7182 | if (task) { |
7206 | event->attach_state = PERF_ATTACH_TASK; | 7183 | event->attach_state = PERF_ATTACH_TASK; |
7207 | |||
7208 | if (attr->type == PERF_TYPE_TRACEPOINT) | ||
7209 | event->hw.tp_target = task; | ||
7210 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
7211 | /* | 7184 | /* |
7212 | * hw_breakpoint is a bit difficult here.. | 7185 | * XXX pmu::event_init needs to know what task to account to |
7186 | * and we cannot use the ctx information because we need the | ||
7187 | * pmu before we get a ctx. | ||
7213 | */ | 7188 | */ |
7214 | else if (attr->type == PERF_TYPE_BREAKPOINT) | 7189 | event->hw.target = task; |
7215 | event->hw.bp_target = task; | ||
7216 | #endif | ||
7217 | } | 7190 | } |
7218 | 7191 | ||
7219 | if (!overflow_handler && parent_event) { | 7192 | if (!overflow_handler && parent_event) { |
@@ -7245,6 +7218,12 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
7245 | if (!has_branch_stack(event)) | 7218 | if (!has_branch_stack(event)) |
7246 | event->attr.branch_sample_type = 0; | 7219 | event->attr.branch_sample_type = 0; |
7247 | 7220 | ||
7221 | if (cgroup_fd != -1) { | ||
7222 | err = perf_cgroup_connect(cgroup_fd, event, attr, group_leader); | ||
7223 | if (err) | ||
7224 | goto err_ns; | ||
7225 | } | ||
7226 | |||
7248 | pmu = perf_init_event(event); | 7227 | pmu = perf_init_event(event); |
7249 | if (!pmu) | 7228 | if (!pmu) |
7250 | goto err_ns; | 7229 | goto err_ns; |
@@ -7268,6 +7247,8 @@ err_pmu: | |||
7268 | event->destroy(event); | 7247 | event->destroy(event); |
7269 | module_put(pmu->module); | 7248 | module_put(pmu->module); |
7270 | err_ns: | 7249 | err_ns: |
7250 | if (is_cgroup_event(event)) | ||
7251 | perf_detach_cgroup(event); | ||
7271 | if (event->ns) | 7252 | if (event->ns) |
7272 | put_pid_ns(event->ns); | 7253 | put_pid_ns(event->ns); |
7273 | kfree(event); | 7254 | kfree(event); |
@@ -7486,6 +7467,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
7486 | int move_group = 0; | 7467 | int move_group = 0; |
7487 | int err; | 7468 | int err; |
7488 | int f_flags = O_RDWR; | 7469 | int f_flags = O_RDWR; |
7470 | int cgroup_fd = -1; | ||
7489 | 7471 | ||
7490 | /* for future expandability... */ | 7472 | /* for future expandability... */ |
7491 | if (flags & ~PERF_FLAG_ALL) | 7473 | if (flags & ~PERF_FLAG_ALL) |
@@ -7551,21 +7533,16 @@ SYSCALL_DEFINE5(perf_event_open, | |||
7551 | 7533 | ||
7552 | get_online_cpus(); | 7534 | get_online_cpus(); |
7553 | 7535 | ||
7536 | if (flags & PERF_FLAG_PID_CGROUP) | ||
7537 | cgroup_fd = pid; | ||
7538 | |||
7554 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, | 7539 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, |
7555 | NULL, NULL); | 7540 | NULL, NULL, cgroup_fd); |
7556 | if (IS_ERR(event)) { | 7541 | if (IS_ERR(event)) { |
7557 | err = PTR_ERR(event); | 7542 | err = PTR_ERR(event); |
7558 | goto err_cpus; | 7543 | goto err_cpus; |
7559 | } | 7544 | } |
7560 | 7545 | ||
7561 | if (flags & PERF_FLAG_PID_CGROUP) { | ||
7562 | err = perf_cgroup_connect(pid, event, &attr, group_leader); | ||
7563 | if (err) { | ||
7564 | __free_event(event); | ||
7565 | goto err_cpus; | ||
7566 | } | ||
7567 | } | ||
7568 | |||
7569 | if (is_sampling_event(event)) { | 7546 | if (is_sampling_event(event)) { |
7570 | if (event->pmu->capabilities & PERF_PMU_CAP_NO_INTERRUPT) { | 7547 | if (event->pmu->capabilities & PERF_PMU_CAP_NO_INTERRUPT) { |
7571 | err = -ENOTSUPP; | 7548 | err = -ENOTSUPP; |
@@ -7802,7 +7779,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | |||
7802 | */ | 7779 | */ |
7803 | 7780 | ||
7804 | event = perf_event_alloc(attr, cpu, task, NULL, NULL, | 7781 | event = perf_event_alloc(attr, cpu, task, NULL, NULL, |
7805 | overflow_handler, context); | 7782 | overflow_handler, context, -1); |
7806 | if (IS_ERR(event)) { | 7783 | if (IS_ERR(event)) { |
7807 | err = PTR_ERR(event); | 7784 | err = PTR_ERR(event); |
7808 | goto err; | 7785 | goto err; |
@@ -8163,7 +8140,7 @@ inherit_event(struct perf_event *parent_event, | |||
8163 | parent_event->cpu, | 8140 | parent_event->cpu, |
8164 | child, | 8141 | child, |
8165 | group_leader, parent_event, | 8142 | group_leader, parent_event, |
8166 | NULL, NULL); | 8143 | NULL, NULL, -1); |
8167 | if (IS_ERR(child_event)) | 8144 | if (IS_ERR(child_event)) |
8168 | return child_event; | 8145 | return child_event; |
8169 | 8146 | ||
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 9803a6600d49..92ce5f4ccc26 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
@@ -116,12 +116,12 @@ static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) | |||
116 | */ | 116 | */ |
117 | static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type) | 117 | static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type) |
118 | { | 118 | { |
119 | struct task_struct *tsk = bp->hw.bp_target; | 119 | struct task_struct *tsk = bp->hw.target; |
120 | struct perf_event *iter; | 120 | struct perf_event *iter; |
121 | int count = 0; | 121 | int count = 0; |
122 | 122 | ||
123 | list_for_each_entry(iter, &bp_task_head, hw.bp_list) { | 123 | list_for_each_entry(iter, &bp_task_head, hw.bp_list) { |
124 | if (iter->hw.bp_target == tsk && | 124 | if (iter->hw.target == tsk && |
125 | find_slot_idx(iter) == type && | 125 | find_slot_idx(iter) == type && |
126 | (iter->cpu < 0 || cpu == iter->cpu)) | 126 | (iter->cpu < 0 || cpu == iter->cpu)) |
127 | count += hw_breakpoint_weight(iter); | 127 | count += hw_breakpoint_weight(iter); |
@@ -153,7 +153,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, | |||
153 | int nr; | 153 | int nr; |
154 | 154 | ||
155 | nr = info->cpu_pinned; | 155 | nr = info->cpu_pinned; |
156 | if (!bp->hw.bp_target) | 156 | if (!bp->hw.target) |
157 | nr += max_task_bp_pinned(cpu, type); | 157 | nr += max_task_bp_pinned(cpu, type); |
158 | else | 158 | else |
159 | nr += task_bp_pinned(cpu, bp, type); | 159 | nr += task_bp_pinned(cpu, bp, type); |
@@ -210,7 +210,7 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, | |||
210 | weight = -weight; | 210 | weight = -weight; |
211 | 211 | ||
212 | /* Pinned counter cpu profiling */ | 212 | /* Pinned counter cpu profiling */ |
213 | if (!bp->hw.bp_target) { | 213 | if (!bp->hw.target) { |
214 | get_bp_info(bp->cpu, type)->cpu_pinned += weight; | 214 | get_bp_info(bp->cpu, type)->cpu_pinned += weight; |
215 | return; | 215 | return; |
216 | } | 216 | } |