@@ -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