diff options
author | Paul Mackerras <paulus@samba.org> | 2009-06-01 03:52:30 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-02 07:10:54 -0400 |
commit | 3f731ca60afc29f5bcdb5fd2a04391466313a9ac (patch) | |
tree | ca9953e902e5043f62f56db31a0e990eed755e78 /kernel | |
parent | f38b082081bf69a06fffb8b32a175999e2320c5b (diff) |
perf_counter: Fix cpu migration counter
This fixes the cpu migration software counter to count
correctly even when contexts get swapped from one task to
another. Previously the cpu migration counts reported by perf
stat were bogus, ranging from negative to several thousand for
a single "lat_ctx 2 8 32" run. With this patch the cpu
migration count reported for "lat_ctx 2 8 32" is almost always
between 35 and 44.
This fixes the problem by adding a call into the perf_counter
code from set_task_cpu when tasks are migrated. This enables
us to use the generic swcounter code (with some modifications)
for the cpu migration counter.
This modifies the swcounter code to allow a NULL regs pointer
to be passed in to perf_swcounter_ctx_event() etc. The cpu
migration counter does this because there isn't necessarily a
pt_regs struct for the task available. In this case, the
counter will not have interrupt capability - but the migration
counter didn't have interrupt capability before, so this is no
loss.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <18979.35006.819769.416327@cargo.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_counter.c | 74 | ||||
-rw-r--r-- | kernel/sched.c | 1 |
2 files changed, 22 insertions, 53 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 8d2653f137e9..cd94cf3bf9e2 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -2921,11 +2921,13 @@ static int perf_swcounter_match(struct perf_counter *counter, | |||
2921 | if (counter->hw_event.config != event_config) | 2921 | if (counter->hw_event.config != event_config) |
2922 | return 0; | 2922 | return 0; |
2923 | 2923 | ||
2924 | if (counter->hw_event.exclude_user && user_mode(regs)) | 2924 | if (regs) { |
2925 | return 0; | 2925 | if (counter->hw_event.exclude_user && user_mode(regs)) |
2926 | return 0; | ||
2926 | 2927 | ||
2927 | if (counter->hw_event.exclude_kernel && !user_mode(regs)) | 2928 | if (counter->hw_event.exclude_kernel && !user_mode(regs)) |
2928 | return 0; | 2929 | return 0; |
2930 | } | ||
2929 | 2931 | ||
2930 | return 1; | 2932 | return 1; |
2931 | } | 2933 | } |
@@ -2935,7 +2937,7 @@ static void perf_swcounter_add(struct perf_counter *counter, u64 nr, | |||
2935 | { | 2937 | { |
2936 | int neg = atomic64_add_negative(nr, &counter->hw.count); | 2938 | int neg = atomic64_add_negative(nr, &counter->hw.count); |
2937 | 2939 | ||
2938 | if (counter->hw.irq_period && !neg) | 2940 | if (counter->hw.irq_period && !neg && regs) |
2939 | perf_swcounter_overflow(counter, nmi, regs, addr); | 2941 | perf_swcounter_overflow(counter, nmi, regs, addr); |
2940 | } | 2942 | } |
2941 | 2943 | ||
@@ -3151,55 +3153,24 @@ static const struct pmu perf_ops_task_clock = { | |||
3151 | /* | 3153 | /* |
3152 | * Software counter: cpu migrations | 3154 | * Software counter: cpu migrations |
3153 | */ | 3155 | */ |
3154 | 3156 | void perf_counter_task_migration(struct task_struct *task, int cpu) | |
3155 | static inline u64 get_cpu_migrations(struct perf_counter *counter) | ||
3156 | { | ||
3157 | struct task_struct *curr = counter->ctx->task; | ||
3158 | |||
3159 | if (curr) | ||
3160 | return curr->se.nr_migrations; | ||
3161 | return cpu_nr_migrations(smp_processor_id()); | ||
3162 | } | ||
3163 | |||
3164 | static void cpu_migrations_perf_counter_update(struct perf_counter *counter) | ||
3165 | { | ||
3166 | u64 prev, now; | ||
3167 | s64 delta; | ||
3168 | |||
3169 | prev = atomic64_read(&counter->hw.prev_count); | ||
3170 | now = get_cpu_migrations(counter); | ||
3171 | |||
3172 | atomic64_set(&counter->hw.prev_count, now); | ||
3173 | |||
3174 | delta = now - prev; | ||
3175 | |||
3176 | atomic64_add(delta, &counter->count); | ||
3177 | } | ||
3178 | |||
3179 | static void cpu_migrations_perf_counter_read(struct perf_counter *counter) | ||
3180 | { | 3157 | { |
3181 | cpu_migrations_perf_counter_update(counter); | 3158 | struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); |
3182 | } | 3159 | struct perf_counter_context *ctx; |
3183 | 3160 | ||
3184 | static int cpu_migrations_perf_counter_enable(struct perf_counter *counter) | 3161 | perf_swcounter_ctx_event(&cpuctx->ctx, PERF_TYPE_SOFTWARE, |
3185 | { | 3162 | PERF_COUNT_CPU_MIGRATIONS, |
3186 | if (counter->prev_state <= PERF_COUNTER_STATE_OFF) | 3163 | 1, 1, NULL, 0); |
3187 | atomic64_set(&counter->hw.prev_count, | ||
3188 | get_cpu_migrations(counter)); | ||
3189 | return 0; | ||
3190 | } | ||
3191 | 3164 | ||
3192 | static void cpu_migrations_perf_counter_disable(struct perf_counter *counter) | 3165 | ctx = perf_pin_task_context(task); |
3193 | { | 3166 | if (ctx) { |
3194 | cpu_migrations_perf_counter_update(counter); | 3167 | perf_swcounter_ctx_event(ctx, PERF_TYPE_SOFTWARE, |
3168 | PERF_COUNT_CPU_MIGRATIONS, | ||
3169 | 1, 1, NULL, 0); | ||
3170 | perf_unpin_context(ctx); | ||
3171 | } | ||
3195 | } | 3172 | } |
3196 | 3173 | ||
3197 | static const struct pmu perf_ops_cpu_migrations = { | ||
3198 | .enable = cpu_migrations_perf_counter_enable, | ||
3199 | .disable = cpu_migrations_perf_counter_disable, | ||
3200 | .read = cpu_migrations_perf_counter_read, | ||
3201 | }; | ||
3202 | |||
3203 | #ifdef CONFIG_EVENT_PROFILE | 3174 | #ifdef CONFIG_EVENT_PROFILE |
3204 | void perf_tpcounter_event(int event_id) | 3175 | void perf_tpcounter_event(int event_id) |
3205 | { | 3176 | { |
@@ -3272,11 +3243,8 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter) | |||
3272 | case PERF_COUNT_PAGE_FAULTS_MIN: | 3243 | case PERF_COUNT_PAGE_FAULTS_MIN: |
3273 | case PERF_COUNT_PAGE_FAULTS_MAJ: | 3244 | case PERF_COUNT_PAGE_FAULTS_MAJ: |
3274 | case PERF_COUNT_CONTEXT_SWITCHES: | 3245 | case PERF_COUNT_CONTEXT_SWITCHES: |
3275 | pmu = &perf_ops_generic; | ||
3276 | break; | ||
3277 | case PERF_COUNT_CPU_MIGRATIONS: | 3246 | case PERF_COUNT_CPU_MIGRATIONS: |
3278 | if (!counter->hw_event.exclude_kernel) | 3247 | pmu = &perf_ops_generic; |
3279 | pmu = &perf_ops_cpu_migrations; | ||
3280 | break; | 3248 | break; |
3281 | } | 3249 | } |
3282 | 3250 | ||
diff --git a/kernel/sched.c b/kernel/sched.c index 3226cc132e9f..8d43347a0c0d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -1977,6 +1977,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) | |||
1977 | if (task_hot(p, old_rq->clock, NULL)) | 1977 | if (task_hot(p, old_rq->clock, NULL)) |
1978 | schedstat_inc(p, se.nr_forced2_migrations); | 1978 | schedstat_inc(p, se.nr_forced2_migrations); |
1979 | #endif | 1979 | #endif |
1980 | perf_counter_task_migration(p, new_cpu); | ||
1980 | } | 1981 | } |
1981 | p->se.vruntime -= old_cfsrq->min_vruntime - | 1982 | p->se.vruntime -= old_cfsrq->min_vruntime - |
1982 | new_cfsrq->min_vruntime; | 1983 | new_cfsrq->min_vruntime; |