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 | |
| 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')
| -rw-r--r-- | kernel/events/core.c | 73 | ||||
| -rw-r--r-- | kernel/events/hw_breakpoint.c | 8 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 10 |
3 files changed, 34 insertions, 57 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 | } |
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 7dc1c8abecd6..996e452e1eb3 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
| @@ -1005,7 +1005,7 @@ __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm) | |||
| 1005 | return true; | 1005 | return true; |
| 1006 | 1006 | ||
| 1007 | list_for_each_entry(event, &filter->perf_events, hw.tp_list) { | 1007 | list_for_each_entry(event, &filter->perf_events, hw.tp_list) { |
| 1008 | if (event->hw.tp_target->mm == mm) | 1008 | if (event->hw.target->mm == mm) |
| 1009 | return true; | 1009 | return true; |
| 1010 | } | 1010 | } |
| 1011 | 1011 | ||
| @@ -1015,7 +1015,7 @@ __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm) | |||
| 1015 | static inline bool | 1015 | static inline bool |
| 1016 | uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) | 1016 | uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) |
| 1017 | { | 1017 | { |
| 1018 | return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm); | 1018 | return __uprobe_perf_filter(&tu->filter, event->hw.target->mm); |
| 1019 | } | 1019 | } |
| 1020 | 1020 | ||
| 1021 | static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) | 1021 | static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) |
| @@ -1023,10 +1023,10 @@ static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) | |||
| 1023 | bool done; | 1023 | bool done; |
| 1024 | 1024 | ||
| 1025 | write_lock(&tu->filter.rwlock); | 1025 | write_lock(&tu->filter.rwlock); |
| 1026 | if (event->hw.tp_target) { | 1026 | if (event->hw.target) { |
| 1027 | list_del(&event->hw.tp_list); | 1027 | list_del(&event->hw.tp_list); |
| 1028 | done = tu->filter.nr_systemwide || | 1028 | done = tu->filter.nr_systemwide || |
| 1029 | (event->hw.tp_target->flags & PF_EXITING) || | 1029 | (event->hw.target->flags & PF_EXITING) || |
| 1030 | uprobe_filter_event(tu, event); | 1030 | uprobe_filter_event(tu, event); |
| 1031 | } else { | 1031 | } else { |
| 1032 | tu->filter.nr_systemwide--; | 1032 | tu->filter.nr_systemwide--; |
| @@ -1046,7 +1046,7 @@ static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) | |||
| 1046 | int err; | 1046 | int err; |
| 1047 | 1047 | ||
| 1048 | write_lock(&tu->filter.rwlock); | 1048 | write_lock(&tu->filter.rwlock); |
| 1049 | if (event->hw.tp_target) { | 1049 | if (event->hw.target) { |
| 1050 | /* | 1050 | /* |
| 1051 | * event->parent != NULL means copy_process(), we can avoid | 1051 | * event->parent != NULL means copy_process(), we can avoid |
| 1052 | * uprobe_apply(). current->mm must be probed and we can rely | 1052 | * uprobe_apply(). current->mm must be probed and we can rely |
