Skip to content

Commit afbde83

Browse files
committed
perf tool_pmu: Use old_count when computing count values for time events
When running in interval mode every third count of a time event isn't showing properly: ``` $ perf stat -e duration_time -a -I 1000 1.001082862 1,002,290,425 duration_time 2.004264262 1,003,183,516 duration_time 3.007381401 <not counted> duration_time 4.011160141 1,003,705,631 duration_time 5.014515385 1,003,290,110 duration_time 6.018539680 <not counted> duration_time 7.022065321 1,003,591,720 duration_time ``` The regression came in with a different fix, found through bisection, commit 68cb156 ("perf tool_pmu: Fix aggregation on duration_time"). The issue is caused by the enabled and running time of the event matching the old_count's and creating a delta of 0, which is indicative of an error. Fixes: 68cb156 ("perf tool_pmu: Fix aggregation on duration_time") Signed-off-by: Ian Rogers <[email protected]>
1 parent cd69558 commit afbde83

File tree

2 files changed

+46
-29
lines changed

2 files changed

+46
-29
lines changed

tools/perf/builtin-stat.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,17 +282,27 @@ static int read_single_counter(struct evsel *counter, int cpu_map_idx, int threa
282282
if (err && cpu_map_idx == 0 &&
283283
(evsel__tool_event(counter) == TOOL_PMU__EVENT_USER_TIME ||
284284
evsel__tool_event(counter) == TOOL_PMU__EVENT_SYSTEM_TIME)) {
285-
u64 val, *start_time;
286285
struct perf_counts_values *count =
287286
perf_counts(counter->counts, cpu_map_idx, thread);
287+
struct perf_counts_values *old_count = NULL;
288+
u64 val;
289+
290+
if (counter->prev_raw_counts)
291+
old_count = perf_counts(counter->prev_raw_counts, cpu_map_idx, thread);
288292

289-
start_time = xyarray__entry(counter->start_times, cpu_map_idx, thread);
290293
if (evsel__tool_event(counter) == TOOL_PMU__EVENT_USER_TIME)
291294
val = ru_stats.ru_utime_usec_stat.mean;
292295
else
293296
val = ru_stats.ru_stime_usec_stat.mean;
294-
count->ena = count->run = *start_time + val;
297+
295298
count->val = val;
299+
if (old_count) {
300+
count->run = old_count->run + 1;
301+
count->ena = old_count->ena + 1;
302+
} else {
303+
count->run++;
304+
count->ena++;
305+
}
296306
return 0;
297307
}
298308
return err;

tools/perf/util/tool_pmu.c

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -434,16 +434,39 @@ bool tool_pmu__read_event(enum tool_pmu_event ev, struct evsel *evsel, u64 *resu
434434
}
435435
}
436436

437+
static void perf_counts__update(struct perf_counts_values *count,
438+
const struct perf_counts_values *old_count,
439+
bool raw, u64 val)
440+
{
441+
/*
442+
* The values of enabled and running must make a ratio of 100%. The
443+
* exact values don't matter as long as they are non-zero to avoid
444+
* issues with evsel__count_has_error.
445+
*/
446+
if (old_count) {
447+
count->val = raw ? val : old_count->val + val;
448+
count->run = old_count->run + 1;
449+
count->ena = old_count->ena + 1;
450+
count->lost = old_count->lost;
451+
} else {
452+
count->val = val;
453+
count->run++;
454+
count->ena++;
455+
count->lost = 0;
456+
}
457+
}
458+
437459
int evsel__tool_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
438460
{
439461
__u64 *start_time, cur_time, delta_start;
440-
u64 val;
441-
int fd, err = 0;
462+
int err = 0;
442463
struct perf_counts_values *count, *old_count = NULL;
443464
bool adjust = false;
444465
enum tool_pmu_event ev = evsel__tool_event(evsel);
445466

446467
count = perf_counts(evsel->counts, cpu_map_idx, thread);
468+
if (evsel->prev_raw_counts)
469+
old_count = perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread);
447470

448471
switch (ev) {
449472
case TOOL_PMU__EVENT_HAS_PMEM:
@@ -454,26 +477,18 @@ int evsel__tool_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
454477
case TOOL_PMU__EVENT_NUM_PACKAGES:
455478
case TOOL_PMU__EVENT_SLOTS:
456479
case TOOL_PMU__EVENT_SMT_ON:
457-
case TOOL_PMU__EVENT_SYSTEM_TSC_FREQ:
458-
if (evsel->prev_raw_counts)
459-
old_count = perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread);
460-
val = 0;
480+
case TOOL_PMU__EVENT_SYSTEM_TSC_FREQ: {
481+
u64 val = 0;
482+
461483
if (cpu_map_idx == 0 && thread == 0) {
462484
if (!tool_pmu__read_event(ev, evsel, &val)) {
463485
count->lost++;
464486
val = 0;
465487
}
466488
}
467-
if (old_count) {
468-
count->val = old_count->val + val;
469-
count->run = old_count->run + 1;
470-
count->ena = old_count->ena + 1;
471-
} else {
472-
count->val = val;
473-
count->run++;
474-
count->ena++;
475-
}
489+
perf_counts__update(count, old_count, /*raw=*/false, val);
476490
return 0;
491+
}
477492
case TOOL_PMU__EVENT_DURATION_TIME:
478493
/*
479494
* Pretend duration_time is only on the first CPU and thread, or
@@ -489,9 +504,9 @@ int evsel__tool_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
489504
case TOOL_PMU__EVENT_USER_TIME:
490505
case TOOL_PMU__EVENT_SYSTEM_TIME: {
491506
bool system = evsel__tool_event(evsel) == TOOL_PMU__EVENT_SYSTEM_TIME;
507+
int fd = FD(evsel, cpu_map_idx, thread);
492508

493509
start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread);
494-
fd = FD(evsel, cpu_map_idx, thread);
495510
lseek(fd, SEEK_SET, 0);
496511
if (evsel->pid_stat) {
497512
/* The event exists solely on 1 CPU. */
@@ -525,17 +540,9 @@ int evsel__tool_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
525540
if (adjust) {
526541
__u64 ticks_per_sec = sysconf(_SC_CLK_TCK);
527542

528-
delta_start *= 1000000000 / ticks_per_sec;
543+
delta_start *= 1e9 / ticks_per_sec;
529544
}
530-
count->val = delta_start;
531-
count->lost = 0;
532-
/*
533-
* The values of enabled and running must make a ratio of 100%. The
534-
* exact values don't matter as long as they are non-zero to avoid
535-
* issues with evsel__count_has_error.
536-
*/
537-
count->ena++;
538-
count->run++;
545+
perf_counts__update(count, old_count, /*raw=*/true, delta_start);
539546
return 0;
540547
}
541548

0 commit comments

Comments
 (0)