Skip to content

Commit 767209a

Browse files
committed
perf stat-shadow: Read tool events directly
When reading time values for metrics don't use the globals updated in builtin-stat, just read the events as regular events. The only exception is for time events where nanoseconds need converting to seconds as metrics assume time metrics are in seconds. Signed-off-by: Ian Rogers <[email protected]> --- v2. Make sure that tool time events read from the aggregation index for CPU0.
1 parent afbde83 commit 767209a

File tree

1 file changed

+66
-81
lines changed

1 file changed

+66
-81
lines changed

tools/perf/util/stat-shadow.c

Lines changed: 66 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,32 @@ static void print_nsecs(struct perf_stat_config *config,
368368
}
369369
}
370370

371-
static int prepare_metric(const struct metric_expr *mexp,
371+
static bool tool_pmu__is_time_event(const struct perf_stat_config *config,
372+
const struct evsel *evsel, int *tool_aggr_idx)
373+
{
374+
enum tool_pmu_event event = evsel__tool_event(evsel);
375+
int aggr_idx;
376+
377+
if (event != TOOL_PMU__EVENT_DURATION_TIME &&
378+
event != TOOL_PMU__EVENT_USER_TIME &&
379+
event != TOOL_PMU__EVENT_SYSTEM_TIME)
380+
return false;
381+
382+
if (config) {
383+
cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
384+
if (config->aggr_map->map[aggr_idx].cpu.cpu == 0) {
385+
*tool_aggr_idx = aggr_idx;
386+
return true;
387+
}
388+
}
389+
pr_debug("Unexpected CPU0 missing in aggregation for tool event.\n");
390+
}
391+
*tool_aggr_idx = 0; /* Assume the first aggregation index works. */
392+
return true;
393+
}
394+
395+
static int prepare_metric(const struct perf_stat_config *config,
396+
const struct metric_expr *mexp,
372397
const struct evsel *evsel,
373398
struct expr_parse_ctx *pctx,
374399
int aggr_idx)
@@ -378,91 +403,51 @@ static int prepare_metric(const struct metric_expr *mexp,
378403
int i;
379404

380405
for (i = 0; metric_events[i]; i++) {
406+
int source_count = 0, tool_aggr_idx;
407+
bool is_tool_time =
408+
tool_pmu__is_time_event(config, metric_events[i], &tool_aggr_idx);
409+
struct perf_stat_evsel *ps = metric_events[i]->stats;
410+
struct perf_stat_aggr *aggr;
381411
char *n;
382412
double val;
383-
int source_count = 0;
384413

385-
if (evsel__is_tool(metric_events[i])) {
386-
struct stats *stats;
387-
double scale;
388-
389-
switch (evsel__tool_event(metric_events[i])) {
390-
case TOOL_PMU__EVENT_DURATION_TIME:
391-
stats = &walltime_nsecs_stats;
392-
scale = 1e-9;
393-
break;
394-
case TOOL_PMU__EVENT_USER_TIME:
395-
stats = &ru_stats.ru_utime_usec_stat;
396-
scale = 1e-6;
397-
break;
398-
case TOOL_PMU__EVENT_SYSTEM_TIME:
399-
stats = &ru_stats.ru_stime_usec_stat;
400-
scale = 1e-6;
414+
/*
415+
* If there are multiple uncore PMUs and we're not reading the
416+
* leader's stats, determine the stats for the appropriate
417+
* uncore PMU.
418+
*/
419+
if (evsel && evsel->metric_leader &&
420+
evsel->pmu != evsel->metric_leader->pmu &&
421+
mexp->metric_events[i]->pmu == evsel->metric_leader->pmu) {
422+
struct evsel *pos;
423+
424+
evlist__for_each_entry(evsel->evlist, pos) {
425+
if (pos->pmu != evsel->pmu)
426+
continue;
427+
if (pos->metric_leader != mexp->metric_events[i])
428+
continue;
429+
ps = pos->stats;
430+
source_count = 1;
401431
break;
402-
case TOOL_PMU__EVENT_NONE:
403-
pr_err("Invalid tool event 'none'");
404-
abort();
405-
case TOOL_PMU__EVENT_MAX:
406-
pr_err("Invalid tool event 'max'");
407-
abort();
408-
case TOOL_PMU__EVENT_HAS_PMEM:
409-
case TOOL_PMU__EVENT_NUM_CORES:
410-
case TOOL_PMU__EVENT_NUM_CPUS:
411-
case TOOL_PMU__EVENT_NUM_CPUS_ONLINE:
412-
case TOOL_PMU__EVENT_NUM_DIES:
413-
case TOOL_PMU__EVENT_NUM_PACKAGES:
414-
case TOOL_PMU__EVENT_SLOTS:
415-
case TOOL_PMU__EVENT_SMT_ON:
416-
case TOOL_PMU__EVENT_SYSTEM_TSC_FREQ:
417-
default:
418-
pr_err("Unexpected tool event '%s'", evsel__name(metric_events[i]));
419-
abort();
420432
}
421-
val = avg_stats(stats) * scale;
422-
source_count = 1;
423-
} else {
424-
struct perf_stat_evsel *ps = metric_events[i]->stats;
425-
struct perf_stat_aggr *aggr;
426-
433+
}
434+
/* Time events are always on CPU0, the first aggregation index. */
435+
aggr = &ps->aggr[is_tool_time ? tool_aggr_idx : aggr_idx];
436+
if (!aggr || !metric_events[i]->supported) {
427437
/*
428-
* If there are multiple uncore PMUs and we're not
429-
* reading the leader's stats, determine the stats for
430-
* the appropriate uncore PMU.
438+
* Not supported events will have a count of 0, which
439+
* can be confusing in a metric. Explicitly set the
440+
* value to NAN. Not counted events (enable time of 0)
441+
* are read as 0.
431442
*/
432-
if (evsel && evsel->metric_leader &&
433-
evsel->pmu != evsel->metric_leader->pmu &&
434-
mexp->metric_events[i]->pmu == evsel->metric_leader->pmu) {
435-
struct evsel *pos;
436-
437-
evlist__for_each_entry(evsel->evlist, pos) {
438-
if (pos->pmu != evsel->pmu)
439-
continue;
440-
if (pos->metric_leader != mexp->metric_events[i])
441-
continue;
442-
ps = pos->stats;
443-
source_count = 1;
444-
break;
445-
}
446-
}
447-
aggr = &ps->aggr[aggr_idx];
448-
if (!aggr)
449-
break;
450-
451-
if (!metric_events[i]->supported) {
452-
/*
453-
* Not supported events will have a count of 0,
454-
* which can be confusing in a
455-
* metric. Explicitly set the value to NAN. Not
456-
* counted events (enable time of 0) are read as
457-
* 0.
458-
*/
459-
val = NAN;
460-
source_count = 0;
461-
} else {
462-
val = aggr->counts.val;
463-
if (!source_count)
464-
source_count = evsel__source_count(metric_events[i]);
465-
}
443+
val = NAN;
444+
source_count = 0;
445+
} else {
446+
val = aggr->counts.val;
447+
if (is_tool_time)
448+
val *= 1e-9; /* Convert time event nanoseconds to seconds. */
449+
if (!source_count)
450+
source_count = evsel__source_count(metric_events[i]);
466451
}
467452
n = strdup(evsel__metric_id(metric_events[i]));
468453
if (!n)
@@ -508,7 +493,7 @@ static void generic_metric(struct perf_stat_config *config,
508493
pctx->sctx.user_requested_cpu_list = strdup(config->user_requested_cpu_list);
509494
pctx->sctx.runtime = runtime;
510495
pctx->sctx.system_wide = config->system_wide;
511-
i = prepare_metric(mexp, evsel, pctx, aggr_idx);
496+
i = prepare_metric(config, mexp, evsel, pctx, aggr_idx);
512497
if (i < 0) {
513498
expr__ctx_free(pctx);
514499
return;
@@ -569,7 +554,7 @@ double test_generic_metric(struct metric_expr *mexp, int aggr_idx)
569554
if (!pctx)
570555
return NAN;
571556

572-
if (prepare_metric(mexp, /*evsel=*/NULL, pctx, aggr_idx) < 0)
557+
if (prepare_metric(/*config=*/NULL, mexp, /*evsel=*/NULL, pctx, aggr_idx) < 0)
573558
goto out;
574559

575560
if (expr__parse(&ratio, pctx, mexp->metric_expr))

0 commit comments

Comments
 (0)