diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-06-05 12:01:29 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-05 12:07:48 -0400 |
commit | 6a24ed6c6082ec65d19331a4bfa30c0512a1a822 (patch) | |
tree | 0d8beed316cf34cd8e986eb2f9b230a29caa6c88 /kernel/perf_counter.c | |
parent | 689802b2d0536e72281dc959ab9cb34fb3c304cf (diff) |
perf_counter: Fix frequency adjustment for < HZ
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index f8390668c391..47c92fb927f2 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1187,8 +1187,9 @@ static void perf_log_period(struct perf_counter *counter, u64 period); | |||
1187 | static void perf_adjust_freq(struct perf_counter_context *ctx) | 1187 | static void perf_adjust_freq(struct perf_counter_context *ctx) |
1188 | { | 1188 | { |
1189 | struct perf_counter *counter; | 1189 | struct perf_counter *counter; |
1190 | struct hw_perf_counter *hwc; | ||
1190 | u64 interrupts, sample_period; | 1191 | u64 interrupts, sample_period; |
1191 | u64 events, period; | 1192 | u64 events, period, freq; |
1192 | s64 delta; | 1193 | s64 delta; |
1193 | 1194 | ||
1194 | spin_lock(&ctx->lock); | 1195 | spin_lock(&ctx->lock); |
@@ -1196,8 +1197,10 @@ static void perf_adjust_freq(struct perf_counter_context *ctx) | |||
1196 | if (counter->state != PERF_COUNTER_STATE_ACTIVE) | 1197 | if (counter->state != PERF_COUNTER_STATE_ACTIVE) |
1197 | continue; | 1198 | continue; |
1198 | 1199 | ||
1199 | interrupts = counter->hw.interrupts; | 1200 | hwc = &counter->hw; |
1200 | counter->hw.interrupts = 0; | 1201 | |
1202 | interrupts = hwc->interrupts; | ||
1203 | hwc->interrupts = 0; | ||
1201 | 1204 | ||
1202 | if (interrupts == MAX_INTERRUPTS) { | 1205 | if (interrupts == MAX_INTERRUPTS) { |
1203 | perf_log_throttle(counter, 1); | 1206 | perf_log_throttle(counter, 1); |
@@ -1208,20 +1211,35 @@ static void perf_adjust_freq(struct perf_counter_context *ctx) | |||
1208 | if (!counter->attr.freq || !counter->attr.sample_freq) | 1211 | if (!counter->attr.freq || !counter->attr.sample_freq) |
1209 | continue; | 1212 | continue; |
1210 | 1213 | ||
1211 | events = HZ * interrupts * counter->hw.sample_period; | 1214 | if (counter->attr.sample_freq < HZ) { |
1215 | freq = counter->attr.sample_freq; | ||
1216 | |||
1217 | hwc->freq_count += freq; | ||
1218 | hwc->freq_interrupts += interrupts; | ||
1219 | |||
1220 | if (hwc->freq_count < HZ) | ||
1221 | continue; | ||
1222 | |||
1223 | interrupts = hwc->freq_interrupts; | ||
1224 | hwc->freq_interrupts = 0; | ||
1225 | hwc->freq_count -= HZ; | ||
1226 | } else | ||
1227 | freq = HZ; | ||
1228 | |||
1229 | events = freq * interrupts * hwc->sample_period; | ||
1212 | period = div64_u64(events, counter->attr.sample_freq); | 1230 | period = div64_u64(events, counter->attr.sample_freq); |
1213 | 1231 | ||
1214 | delta = (s64)(1 + period - counter->hw.sample_period); | 1232 | delta = (s64)(1 + period - hwc->sample_period); |
1215 | delta >>= 1; | 1233 | delta >>= 1; |
1216 | 1234 | ||
1217 | sample_period = counter->hw.sample_period + delta; | 1235 | sample_period = hwc->sample_period + delta; |
1218 | 1236 | ||
1219 | if (!sample_period) | 1237 | if (!sample_period) |
1220 | sample_period = 1; | 1238 | sample_period = 1; |
1221 | 1239 | ||
1222 | perf_log_period(counter, sample_period); | 1240 | perf_log_period(counter, sample_period); |
1223 | 1241 | ||
1224 | counter->hw.sample_period = sample_period; | 1242 | hwc->sample_period = sample_period; |
1225 | } | 1243 | } |
1226 | spin_unlock(&ctx->lock); | 1244 | spin_unlock(&ctx->lock); |
1227 | } | 1245 | } |