diff options
-rw-r--r-- | include/linux/perf_counter.h | 3 | ||||
-rw-r--r-- | kernel/perf_counter.c | 32 |
2 files changed, 28 insertions, 7 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 6bc250039738..4f9d39ecdc05 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -373,6 +373,9 @@ struct hw_perf_counter { | |||
373 | u64 sample_period; | 373 | u64 sample_period; |
374 | atomic64_t period_left; | 374 | atomic64_t period_left; |
375 | u64 interrupts; | 375 | u64 interrupts; |
376 | |||
377 | u64 freq_count; | ||
378 | u64 freq_interrupts; | ||
376 | #endif | 379 | #endif |
377 | }; | 380 | }; |
378 | 381 | ||
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 | } |