1 // SPDX-License-Identifier: GPL-2.0
12 #include "metricgroup.h"
15 #include <linux/zalloc.h>
17 #include "util/hashmap.h"
20 struct stats walltime_nsecs_stats
;
21 struct rusage_stats ru_stats
;
24 CTX_BIT_USER
= 1 << 0,
25 CTX_BIT_KERNEL
= 1 << 1,
27 CTX_BIT_HOST
= 1 << 3,
28 CTX_BIT_IDLE
= 1 << 4,
37 STAT_STALLED_CYCLES_FRONT
,
38 STAT_STALLED_CYCLES_BACK
,
56 static int evsel_context(const struct evsel
*evsel
)
60 if (evsel
->core
.attr
.exclude_kernel
)
61 ctx
|= CTX_BIT_KERNEL
;
62 if (evsel
->core
.attr
.exclude_user
)
64 if (evsel
->core
.attr
.exclude_hv
)
66 if (evsel
->core
.attr
.exclude_host
)
68 if (evsel
->core
.attr
.exclude_idle
)
74 void perf_stat__reset_shadow_stats(void)
76 memset(&walltime_nsecs_stats
, 0, sizeof(walltime_nsecs_stats
));
77 memset(&ru_stats
, 0, sizeof(ru_stats
));
80 static enum stat_type
evsel__stat_type(struct evsel
*evsel
)
82 /* Fake perf_hw_cache_op_id values for use with evsel__match. */
83 u64 PERF_COUNT_hw_cache_l1d_miss
= PERF_COUNT_HW_CACHE_L1D
|
84 ((PERF_COUNT_HW_CACHE_OP_READ
) << 8) |
85 ((PERF_COUNT_HW_CACHE_RESULT_MISS
) << 16);
86 u64 PERF_COUNT_hw_cache_l1i_miss
= PERF_COUNT_HW_CACHE_L1I
|
87 ((PERF_COUNT_HW_CACHE_OP_READ
) << 8) |
88 ((PERF_COUNT_HW_CACHE_RESULT_MISS
) << 16);
89 u64 PERF_COUNT_hw_cache_ll_miss
= PERF_COUNT_HW_CACHE_LL
|
90 ((PERF_COUNT_HW_CACHE_OP_READ
) << 8) |
91 ((PERF_COUNT_HW_CACHE_RESULT_MISS
) << 16);
92 u64 PERF_COUNT_hw_cache_dtlb_miss
= PERF_COUNT_HW_CACHE_DTLB
|
93 ((PERF_COUNT_HW_CACHE_OP_READ
) << 8) |
94 ((PERF_COUNT_HW_CACHE_RESULT_MISS
) << 16);
95 u64 PERF_COUNT_hw_cache_itlb_miss
= PERF_COUNT_HW_CACHE_ITLB
|
96 ((PERF_COUNT_HW_CACHE_OP_READ
) << 8) |
97 ((PERF_COUNT_HW_CACHE_RESULT_MISS
) << 16);
99 if (evsel__is_clock(evsel
))
101 else if (evsel__match(evsel
, HARDWARE
, HW_CPU_CYCLES
))
103 else if (evsel__match(evsel
, HARDWARE
, HW_INSTRUCTIONS
))
104 return STAT_INSTRUCTIONS
;
105 else if (evsel__match(evsel
, HARDWARE
, HW_STALLED_CYCLES_FRONTEND
))
106 return STAT_STALLED_CYCLES_FRONT
;
107 else if (evsel__match(evsel
, HARDWARE
, HW_STALLED_CYCLES_BACKEND
))
108 return STAT_STALLED_CYCLES_BACK
;
109 else if (evsel__match(evsel
, HARDWARE
, HW_BRANCH_INSTRUCTIONS
))
110 return STAT_BRANCHES
;
111 else if (evsel__match(evsel
, HARDWARE
, HW_BRANCH_MISSES
))
112 return STAT_BRANCH_MISS
;
113 else if (evsel__match(evsel
, HARDWARE
, HW_CACHE_REFERENCES
))
114 return STAT_CACHE_REFS
;
115 else if (evsel__match(evsel
, HARDWARE
, HW_CACHE_MISSES
))
116 return STAT_CACHE_MISSES
;
117 else if (evsel__match(evsel
, HW_CACHE
, HW_CACHE_L1D
))
118 return STAT_L1_DCACHE
;
119 else if (evsel__match(evsel
, HW_CACHE
, HW_CACHE_L1I
))
120 return STAT_L1_ICACHE
;
121 else if (evsel__match(evsel
, HW_CACHE
, HW_CACHE_LL
))
122 return STAT_LL_CACHE
;
123 else if (evsel__match(evsel
, HW_CACHE
, HW_CACHE_DTLB
))
124 return STAT_DTLB_CACHE
;
125 else if (evsel__match(evsel
, HW_CACHE
, HW_CACHE_ITLB
))
126 return STAT_ITLB_CACHE
;
127 else if (evsel__match(evsel
, HW_CACHE
, hw_cache_l1d_miss
))
128 return STAT_L1D_MISS
;
129 else if (evsel__match(evsel
, HW_CACHE
, hw_cache_l1i_miss
))
130 return STAT_L1I_MISS
;
131 else if (evsel__match(evsel
, HW_CACHE
, hw_cache_ll_miss
))
133 else if (evsel__match(evsel
, HW_CACHE
, hw_cache_dtlb_miss
))
134 return STAT_DTLB_MISS
;
135 else if (evsel__match(evsel
, HW_CACHE
, hw_cache_itlb_miss
))
136 return STAT_ITLB_MISS
;
140 static enum metric_threshold_classify
get_ratio_thresh(const double ratios
[3], double val
)
142 assert(ratios
[0] > ratios
[1]);
143 assert(ratios
[1] > ratios
[2]);
145 return val
> ratios
[1]
146 ? (val
> ratios
[0] ? METRIC_THRESHOLD_BAD
: METRIC_THRESHOLD_NEARLY_BAD
)
147 : (val
> ratios
[2] ? METRIC_THRESHOLD_LESS_GOOD
: METRIC_THRESHOLD_GOOD
);
150 static double find_stat(const struct evsel
*evsel
, int aggr_idx
, enum stat_type type
)
153 int evsel_ctx
= evsel_context(evsel
);
155 evlist__for_each_entry(evsel
->evlist
, cur
) {
156 struct perf_stat_aggr
*aggr
;
158 /* Ignore the evsel that is being searched from. */
162 /* Ignore evsels that are part of different groups. */
163 if (evsel
->core
.leader
->nr_members
> 1 &&
164 evsel
->core
.leader
!= cur
->core
.leader
)
166 /* Ignore evsels with mismatched modifiers. */
167 if (evsel_ctx
!= evsel_context(cur
))
169 /* Ignore if not the cgroup we're looking for. */
170 if (evsel
->cgrp
!= cur
->cgrp
)
172 /* Ignore if not the stat we're looking for. */
173 if (type
!= evsel__stat_type(cur
))
177 * Except the SW CLOCK events,
178 * ignore if not the PMU we're looking for.
180 if ((type
!= STAT_NSECS
) && (evsel
->pmu
!= cur
->pmu
))
183 aggr
= &cur
->stats
->aggr
[aggr_idx
];
184 if (type
== STAT_NSECS
)
185 return aggr
->counts
.val
;
186 return aggr
->counts
.val
* cur
->scale
;
191 static void print_ratio(struct perf_stat_config
*config
,
192 const struct evsel
*evsel
, int aggr_idx
,
193 double numerator
, struct perf_stat_output_ctx
*out
,
194 enum stat_type denominator_type
,
195 const double thresh_ratios
[3], const char *_unit
)
197 double denominator
= find_stat(evsel
, aggr_idx
, denominator_type
);
199 enum metric_threshold_classify thresh
= METRIC_THRESHOLD_UNKNOWN
;
200 const char *fmt
= NULL
;
201 const char *unit
= NULL
;
203 if (numerator
&& denominator
) {
204 ratio
= numerator
/ denominator
* 100.0;
205 thresh
= get_ratio_thresh(thresh_ratios
, ratio
);
209 out
->print_metric(config
, out
->ctx
, thresh
, fmt
, unit
, ratio
);
212 static void print_stalled_cycles_front(struct perf_stat_config
*config
,
213 const struct evsel
*evsel
,
214 int aggr_idx
, double stalled
,
215 struct perf_stat_output_ctx
*out
)
217 const double thresh_ratios
[3] = {50.0, 30.0, 10.0};
219 print_ratio(config
, evsel
, aggr_idx
, stalled
, out
, STAT_CYCLES
, thresh_ratios
,
220 "frontend cycles idle");
223 static void print_stalled_cycles_back(struct perf_stat_config
*config
,
224 const struct evsel
*evsel
,
225 int aggr_idx
, double stalled
,
226 struct perf_stat_output_ctx
*out
)
228 const double thresh_ratios
[3] = {75.0, 50.0, 20.0};
230 print_ratio(config
, evsel
, aggr_idx
, stalled
, out
, STAT_CYCLES
, thresh_ratios
,
231 "backend cycles idle");
234 static void print_branch_miss(struct perf_stat_config
*config
,
235 const struct evsel
*evsel
,
236 int aggr_idx
, double misses
,
237 struct perf_stat_output_ctx
*out
)
239 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
241 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_BRANCHES
, thresh_ratios
,
245 static void print_l1d_miss(struct perf_stat_config
*config
,
246 const struct evsel
*evsel
,
247 int aggr_idx
, double misses
,
248 struct perf_stat_output_ctx
*out
)
250 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
252 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_L1_DCACHE
, thresh_ratios
,
253 "of all L1-dcache accesses");
256 static void print_l1i_miss(struct perf_stat_config
*config
,
257 const struct evsel
*evsel
,
258 int aggr_idx
, double misses
,
259 struct perf_stat_output_ctx
*out
)
261 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
263 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_L1_ICACHE
, thresh_ratios
,
264 "of all L1-icache accesses");
267 static void print_ll_miss(struct perf_stat_config
*config
,
268 const struct evsel
*evsel
,
269 int aggr_idx
, double misses
,
270 struct perf_stat_output_ctx
*out
)
272 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
274 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_LL_CACHE
, thresh_ratios
,
275 "of all LL-cache accesses");
278 static void print_dtlb_miss(struct perf_stat_config
*config
,
279 const struct evsel
*evsel
,
280 int aggr_idx
, double misses
,
281 struct perf_stat_output_ctx
*out
)
283 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
285 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_DTLB_CACHE
, thresh_ratios
,
286 "of all dTLB cache accesses");
289 static void print_itlb_miss(struct perf_stat_config
*config
,
290 const struct evsel
*evsel
,
291 int aggr_idx
, double misses
,
292 struct perf_stat_output_ctx
*out
)
294 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
296 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_ITLB_CACHE
, thresh_ratios
,
297 "of all iTLB cache accesses");
300 static void print_cache_miss(struct perf_stat_config
*config
,
301 const struct evsel
*evsel
,
302 int aggr_idx
, double misses
,
303 struct perf_stat_output_ctx
*out
)
305 const double thresh_ratios
[3] = {20.0, 10.0, 5.0};
307 print_ratio(config
, evsel
, aggr_idx
, misses
, out
, STAT_CACHE_REFS
, thresh_ratios
,
308 "of all cache refs");
311 static void print_instructions(struct perf_stat_config
*config
,
312 const struct evsel
*evsel
,
313 int aggr_idx
, double instructions
,
314 struct perf_stat_output_ctx
*out
)
316 print_metric_t print_metric
= out
->print_metric
;
317 void *ctxp
= out
->ctx
;
318 double cycles
= find_stat(evsel
, aggr_idx
, STAT_CYCLES
);
319 double max_stalled
= max(find_stat(evsel
, aggr_idx
, STAT_STALLED_CYCLES_FRONT
),
320 find_stat(evsel
, aggr_idx
, STAT_STALLED_CYCLES_BACK
));
323 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
, "%7.2f ",
324 "insn per cycle", instructions
/ cycles
);
326 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
, /*fmt=*/NULL
,
327 "insn per cycle", 0);
329 if (max_stalled
&& instructions
) {
330 out
->new_line(config
, ctxp
);
331 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
, "%7.2f ",
332 "stalled cycles per insn", max_stalled
/ instructions
);
336 static void print_cycles(struct perf_stat_config
*config
,
337 const struct evsel
*evsel
,
338 int aggr_idx
, double cycles
,
339 struct perf_stat_output_ctx
*out
)
341 double nsecs
= find_stat(evsel
, aggr_idx
, STAT_NSECS
);
343 if (cycles
&& nsecs
) {
344 double ratio
= cycles
/ nsecs
;
346 out
->print_metric(config
, out
->ctx
, METRIC_THRESHOLD_UNKNOWN
, "%8.3f",
349 out
->print_metric(config
, out
->ctx
, METRIC_THRESHOLD_UNKNOWN
, /*fmt=*/NULL
,
354 static void print_nsecs(struct perf_stat_config
*config
,
355 const struct evsel
*evsel
,
356 int aggr_idx __maybe_unused
, double nsecs
,
357 struct perf_stat_output_ctx
*out
)
359 print_metric_t print_metric
= out
->print_metric
;
360 void *ctxp
= out
->ctx
;
361 double wall_time
= avg_stats(&walltime_nsecs_stats
);
364 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
, "%8.3f", "CPUs utilized",
365 nsecs
/ (wall_time
* evsel
->scale
));
367 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
, /*fmt=*/NULL
,
372 static int prepare_metric(const struct metric_expr
*mexp
,
373 const struct evsel
*evsel
,
374 struct expr_parse_ctx
*pctx
,
377 struct evsel
* const *metric_events
= mexp
->metric_events
;
378 struct metric_ref
*metric_refs
= mexp
->metric_refs
;
381 for (i
= 0; metric_events
[i
]; i
++) {
384 int source_count
= 0;
386 if (evsel__is_tool(metric_events
[i
])) {
390 switch (evsel__tool_event(metric_events
[i
])) {
391 case TOOL_PMU__EVENT_DURATION_TIME
:
392 stats
= &walltime_nsecs_stats
;
395 case TOOL_PMU__EVENT_USER_TIME
:
396 stats
= &ru_stats
.ru_utime_usec_stat
;
399 case TOOL_PMU__EVENT_SYSTEM_TIME
:
400 stats
= &ru_stats
.ru_stime_usec_stat
;
403 case TOOL_PMU__EVENT_NONE
:
404 pr_err("Invalid tool event 'none'");
406 case TOOL_PMU__EVENT_MAX
:
407 pr_err("Invalid tool event 'max'");
409 case TOOL_PMU__EVENT_HAS_PMEM
:
410 case TOOL_PMU__EVENT_NUM_CORES
:
411 case TOOL_PMU__EVENT_NUM_CPUS
:
412 case TOOL_PMU__EVENT_NUM_CPUS_ONLINE
:
413 case TOOL_PMU__EVENT_NUM_DIES
:
414 case TOOL_PMU__EVENT_NUM_PACKAGES
:
415 case TOOL_PMU__EVENT_SLOTS
:
416 case TOOL_PMU__EVENT_SMT_ON
:
417 case TOOL_PMU__EVENT_SYSTEM_TSC_FREQ
:
419 pr_err("Unexpected tool event '%s'", evsel__name(metric_events
[i
]));
422 val
= avg_stats(stats
) * scale
;
425 struct perf_stat_evsel
*ps
= metric_events
[i
]->stats
;
426 struct perf_stat_aggr
*aggr
;
429 * If there are multiple uncore PMUs and we're not
430 * reading the leader's stats, determine the stats for
431 * the appropriate uncore PMU.
433 if (evsel
&& evsel
->metric_leader
&&
434 evsel
->pmu
!= evsel
->metric_leader
->pmu
&&
435 mexp
->metric_events
[i
]->pmu
== evsel
->metric_leader
->pmu
) {
438 evlist__for_each_entry(evsel
->evlist
, pos
) {
439 if (pos
->pmu
!= evsel
->pmu
)
441 if (pos
->metric_leader
!= mexp
->metric_events
[i
])
448 aggr
= &ps
->aggr
[aggr_idx
];
452 if (!metric_events
[i
]->supported
) {
454 * Not supported events will have a count of 0,
455 * which can be confusing in a
456 * metric. Explicitly set the value to NAN. Not
457 * counted events (enable time of 0) are read as
463 val
= aggr
->counts
.val
;
465 source_count
= evsel__source_count(metric_events
[i
]);
468 n
= strdup(evsel__metric_id(metric_events
[i
]));
472 expr__add_id_val_source_count(pctx
, n
, val
, source_count
);
475 for (int j
= 0; metric_refs
&& metric_refs
[j
].metric_name
; j
++) {
476 int ret
= expr__add_ref(pctx
, &metric_refs
[j
]);
485 static void generic_metric(struct perf_stat_config
*config
,
486 struct metric_expr
*mexp
,
489 struct perf_stat_output_ctx
*out
)
491 print_metric_t print_metric
= out
->print_metric
;
492 const char *metric_name
= mexp
->metric_name
;
493 const char *metric_expr
= mexp
->metric_expr
;
494 const char *metric_threshold
= mexp
->metric_threshold
;
495 const char *metric_unit
= mexp
->metric_unit
;
496 struct evsel
* const *metric_events
= mexp
->metric_events
;
497 int runtime
= mexp
->runtime
;
498 struct expr_parse_ctx
*pctx
;
499 double ratio
, scale
, threshold
;
501 void *ctxp
= out
->ctx
;
502 enum metric_threshold_classify thresh
= METRIC_THRESHOLD_UNKNOWN
;
504 pctx
= expr__ctx_new();
508 if (config
->user_requested_cpu_list
)
509 pctx
->sctx
.user_requested_cpu_list
= strdup(config
->user_requested_cpu_list
);
510 pctx
->sctx
.runtime
= runtime
;
511 pctx
->sctx
.system_wide
= config
->system_wide
;
512 i
= prepare_metric(mexp
, evsel
, pctx
, aggr_idx
);
514 expr__ctx_free(pctx
);
517 if (!metric_events
[i
]) {
518 if (expr__parse(&ratio
, pctx
, metric_expr
) == 0) {
522 if (metric_threshold
&&
523 expr__parse(&threshold
, pctx
, metric_threshold
) == 0 &&
525 thresh
= fpclassify(threshold
) == FP_ZERO
526 ? METRIC_THRESHOLD_GOOD
: METRIC_THRESHOLD_BAD
;
529 if (metric_unit
&& metric_name
) {
530 if (perf_pmu__convert_scale(metric_unit
,
531 &unit
, &scale
) >= 0) {
534 if (strstr(metric_expr
, "?"))
535 scnprintf(metric_bf
, sizeof(metric_bf
),
536 "%s %s_%d", unit
, metric_name
, runtime
);
538 scnprintf(metric_bf
, sizeof(metric_bf
),
539 "%s %s", unit
, metric_name
);
541 print_metric(config
, ctxp
, thresh
, "%8.1f",
544 print_metric(config
, ctxp
, thresh
, "%8.2f",
547 out
->force_header
? evsel
->name
: "",
551 print_metric(config
, ctxp
, thresh
, /*fmt=*/NULL
,
553 (metric_name
?: evsel
->name
) : "", 0);
556 print_metric(config
, ctxp
, thresh
, /*fmt=*/NULL
,
558 (metric_name
?: evsel
->name
) : "", 0);
561 expr__ctx_free(pctx
);
564 double test_generic_metric(struct metric_expr
*mexp
, int aggr_idx
)
566 struct expr_parse_ctx
*pctx
;
569 pctx
= expr__ctx_new();
573 if (prepare_metric(mexp
, /*evsel=*/NULL
, pctx
, aggr_idx
) < 0)
576 if (expr__parse(&ratio
, pctx
, mexp
->metric_expr
))
580 expr__ctx_free(pctx
);
584 static void perf_stat__print_metricgroup_header(struct perf_stat_config
*config
,
588 struct perf_stat_output_ctx
*out
)
590 bool need_full_name
= perf_pmus__num_core_pmus() > 1;
591 static const char *last_name
;
592 static const struct perf_pmu
*last_pmu
;
596 * A metricgroup may have several metric events,
597 * e.g.,TopdownL1 on e-core of ADL.
598 * The name has been output by the first metric
599 * event. Only align with other metics from
600 * different metric events.
602 if (last_name
&& !strcmp(last_name
, name
)) {
603 if (!need_full_name
|| last_pmu
!= evsel
->pmu
) {
604 out
->print_metricgroup_header(config
, ctxp
, NULL
);
609 if (need_full_name
&& evsel
->pmu
)
610 scnprintf(full_name
, sizeof(full_name
), "%s (%s)", name
, evsel
->pmu
->name
);
612 scnprintf(full_name
, sizeof(full_name
), "%s", name
);
614 out
->print_metricgroup_header(config
, ctxp
, full_name
);
617 last_pmu
= evsel
->pmu
;
621 * perf_stat__print_shadow_stats_metricgroup - Print out metrics associated with the evsel
622 * For the non-default, all metrics associated
623 * with the evsel are printed.
624 * For the default mode, only the metrics from
625 * the same metricgroup and the name of the
626 * metricgroup are printed. To print the metrics
627 * from the next metricgroup (if available),
628 * invoke the function with correspoinding
631 void *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config
*config
,
636 struct perf_stat_output_ctx
*out
,
637 struct rblist
*metric_events
)
639 struct metric_event
*me
;
640 struct metric_expr
*mexp
= from
;
641 void *ctxp
= out
->ctx
;
642 bool header_printed
= false;
643 const char *name
= NULL
;
645 me
= metricgroup__lookup(metric_events
, evsel
, false);
650 mexp
= list_first_entry(&me
->head
, typeof(*mexp
), nd
);
652 list_for_each_entry_from(mexp
, &me
->head
, nd
) {
653 /* Print the display name of the Default metricgroup */
654 if (!config
->metric_only
&& me
->is_default
) {
656 name
= mexp
->default_metricgroup_name
;
658 * Two or more metricgroup may share the same metric
659 * event, e.g., TopdownL1 and TopdownL2 on SPR.
660 * Return and print the prefix, e.g., noise, running
661 * for the next metricgroup.
663 if (strcmp(name
, mexp
->default_metricgroup_name
))
665 /* Only print the name of the metricgroup once */
666 if (!header_printed
) {
667 header_printed
= true;
668 perf_stat__print_metricgroup_header(config
, evsel
, ctxp
,
674 out
->new_line(config
, ctxp
);
675 generic_metric(config
, mexp
, evsel
, aggr_idx
, out
);
681 void perf_stat__print_shadow_stats(struct perf_stat_config
*config
,
683 double avg
, int aggr_idx
,
684 struct perf_stat_output_ctx
*out
,
685 struct rblist
*metric_events
)
687 typedef void (*stat_print_function_t
)(struct perf_stat_config
*config
,
688 const struct evsel
*evsel
,
689 int aggr_idx
, double misses
,
690 struct perf_stat_output_ctx
*out
);
691 static const stat_print_function_t stat_print_function
[STAT_MAX
] = {
692 [STAT_INSTRUCTIONS
] = print_instructions
,
693 [STAT_BRANCH_MISS
] = print_branch_miss
,
694 [STAT_L1D_MISS
] = print_l1d_miss
,
695 [STAT_L1I_MISS
] = print_l1i_miss
,
696 [STAT_DTLB_MISS
] = print_dtlb_miss
,
697 [STAT_ITLB_MISS
] = print_itlb_miss
,
698 [STAT_LL_MISS
] = print_ll_miss
,
699 [STAT_CACHE_MISSES
] = print_cache_miss
,
700 [STAT_STALLED_CYCLES_FRONT
] = print_stalled_cycles_front
,
701 [STAT_STALLED_CYCLES_BACK
] = print_stalled_cycles_back
,
702 [STAT_CYCLES
] = print_cycles
,
703 [STAT_NSECS
] = print_nsecs
,
705 print_metric_t print_metric
= out
->print_metric
;
706 void *ctxp
= out
->ctx
;
709 if (config
->iostat_run
) {
710 iostat_print_metric(config
, evsel
, out
);
712 stat_print_function_t fn
= stat_print_function
[evsel__stat_type(evsel
)];
715 fn(config
, evsel
, aggr_idx
, avg
, out
);
717 double nsecs
= find_stat(evsel
, aggr_idx
, STAT_NSECS
);
721 char unit_buf
[10] = "/sec";
722 double ratio
= convert_unit_double(1000000000.0 * avg
/ nsecs
,
726 snprintf(unit_buf
, sizeof(unit_buf
), "%c/sec", unit
);
727 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
, "%8.3f",
735 perf_stat__print_shadow_stats_metricgroup(config
, evsel
, aggr_idx
,
736 &num
, NULL
, out
, metric_events
);
739 print_metric(config
, ctxp
, METRIC_THRESHOLD_UNKNOWN
,
740 /*fmt=*/NULL
, /*unit=*/NULL
, 0);
745 * perf_stat__skip_metric_event - Skip the evsel in the Default metricgroup,
746 * if it's not running or not the metric event.
748 bool perf_stat__skip_metric_event(struct evsel
*evsel
,
749 struct rblist
*metric_events
,
752 if (!evsel
->default_metricgroup
)
758 return !metricgroup__lookup(metric_events
, evsel
, false);