|
@@ -3,151 +3,164 @@
|
|
|
#include "../util/hist.h"
|
|
|
#include "../util/util.h"
|
|
|
#include "../util/sort.h"
|
|
|
-
|
|
|
+#include "../util/evsel.h"
|
|
|
|
|
|
/* hist period print (hpp) functions */
|
|
|
-static int hpp__header_overhead(struct perf_hpp *hpp)
|
|
|
-{
|
|
|
- return scnprintf(hpp->buf, hpp->size, "Overhead");
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 8;
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period / hists->stats.total_period;
|
|
|
-
|
|
|
- return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period / hists->stats.total_period;
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
|
|
|
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__header_overhead_sys(struct perf_hpp *hpp)
|
|
|
-{
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
|
|
|
-
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, "sys");
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 7;
|
|
|
-}
|
|
|
+typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
|
|
|
|
|
|
-static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
+static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he,
|
|
|
+ u64 (*get_field)(struct hist_entry *),
|
|
|
+ const char *fmt, hpp_snprint_fn print_fn)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+ double percent = 0.0;
|
|
|
struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
|
|
|
|
|
|
- return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
|
|
|
-}
|
|
|
+ if (hists->stats.total_period)
|
|
|
+ percent = 100.0 * get_field(he) / hists->stats.total_period;
|
|
|
|
|
|
-static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
|
|
|
+ ret = print_fn(hpp->buf, hpp->size, fmt, percent);
|
|
|
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
|
|
-}
|
|
|
+ if (symbol_conf.event_group) {
|
|
|
+ int prev_idx, idx_delta;
|
|
|
+ struct perf_evsel *evsel = hists_to_evsel(hists);
|
|
|
+ struct hist_entry *pair;
|
|
|
+ int nr_members = evsel->nr_members;
|
|
|
|
|
|
-static int hpp__header_overhead_us(struct perf_hpp *hpp)
|
|
|
-{
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
|
|
|
+ if (nr_members <= 1)
|
|
|
+ return ret;
|
|
|
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, "user");
|
|
|
-}
|
|
|
+ prev_idx = perf_evsel__group_idx(evsel);
|
|
|
|
|
|
-static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 7;
|
|
|
-}
|
|
|
+ list_for_each_entry(pair, &he->pairs.head, pairs.node) {
|
|
|
+ u64 period = get_field(pair);
|
|
|
+ u64 total = pair->hists->stats.total_period;
|
|
|
|
|
|
-static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
|
|
|
-
|
|
|
- return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
|
|
|
+ if (!total)
|
|
|
+ continue;
|
|
|
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
|
|
|
-{
|
|
|
- return scnprintf(hpp->buf, hpp->size, "guest sys");
|
|
|
-}
|
|
|
+ evsel = hists_to_evsel(pair->hists);
|
|
|
+ idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
|
|
|
|
|
|
-static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 9;
|
|
|
-}
|
|
|
+ while (idx_delta--) {
|
|
|
+ /*
|
|
|
+ * zero-fill group members in the middle which
|
|
|
+ * have no sample
|
|
|
+ */
|
|
|
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
|
|
|
+ fmt, 0.0);
|
|
|
+ }
|
|
|
|
|
|
-static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
|
|
|
- struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
|
|
|
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
|
|
|
+ fmt, 100.0 * period / total);
|
|
|
|
|
|
- return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
|
|
|
-}
|
|
|
+ prev_idx = perf_evsel__group_idx(evsel);
|
|
|
+ }
|
|
|
|
|
|
-static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
|
|
|
- struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
|
|
|
+ idx_delta = nr_members - prev_idx - 1;
|
|
|
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
|
|
+ while (idx_delta--) {
|
|
|
+ /*
|
|
|
+ * zero-fill group members at last which have no sample
|
|
|
+ */
|
|
|
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
|
|
|
+ fmt, 0.0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
|
|
|
+static int __hpp__raw_fmt(struct perf_hpp *hpp, struct hist_entry *he,
|
|
|
+ u64 (*get_field)(struct hist_entry *),
|
|
|
+ const char *fmt, hpp_snprint_fn print_fn)
|
|
|
{
|
|
|
- return scnprintf(hpp->buf, hpp->size, "guest usr");
|
|
|
-}
|
|
|
+ int ret;
|
|
|
|
|
|
-static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 9;
|
|
|
+ ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
|
|
|
- struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
|
|
|
|
|
|
- return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
|
|
|
-}
|
|
|
+#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
|
|
|
+static int hpp__header_##_type(struct perf_hpp *hpp) \
|
|
|
+{ \
|
|
|
+ int len = _min_width; \
|
|
|
+ \
|
|
|
+ if (symbol_conf.event_group) { \
|
|
|
+ struct perf_evsel *evsel = hpp->ptr; \
|
|
|
+ \
|
|
|
+ len = max(len, evsel->nr_members * _unit_width); \
|
|
|
+ } \
|
|
|
+ return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
|
|
|
+}
|
|
|
+
|
|
|
+#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
|
|
|
+static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
|
|
|
+{ \
|
|
|
+ int len = _min_width; \
|
|
|
+ \
|
|
|
+ if (symbol_conf.event_group) { \
|
|
|
+ struct perf_evsel *evsel = hpp->ptr; \
|
|
|
+ \
|
|
|
+ len = max(len, evsel->nr_members * _unit_width); \
|
|
|
+ } \
|
|
|
+ return len; \
|
|
|
+}
|
|
|
+
|
|
|
+#define __HPP_COLOR_PERCENT_FN(_type, _field) \
|
|
|
+static u64 he_get_##_field(struct hist_entry *he) \
|
|
|
+{ \
|
|
|
+ return he->stat._field; \
|
|
|
+} \
|
|
|
+ \
|
|
|
+static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
|
|
|
+{ \
|
|
|
+ return __hpp__percent_fmt(hpp, he, he_get_##_field, " %6.2f%%", \
|
|
|
+ (hpp_snprint_fn)percent_color_snprintf); \
|
|
|
+}
|
|
|
+
|
|
|
+#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
|
|
|
+static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
|
|
|
+{ \
|
|
|
+ const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
|
|
|
+ return __hpp__percent_fmt(hpp, he, he_get_##_field, fmt, \
|
|
|
+ scnprintf); \
|
|
|
+}
|
|
|
+
|
|
|
+#define __HPP_ENTRY_RAW_FN(_type, _field) \
|
|
|
+static u64 he_get_raw_##_field(struct hist_entry *he) \
|
|
|
+{ \
|
|
|
+ return he->stat._field; \
|
|
|
+} \
|
|
|
+ \
|
|
|
+static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
|
|
|
+{ \
|
|
|
+ const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
|
|
|
+ return __hpp__raw_fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf); \
|
|
|
+}
|
|
|
+
|
|
|
+#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
|
|
|
+__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
|
|
|
+__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
|
|
|
+__HPP_COLOR_PERCENT_FN(_type, _field) \
|
|
|
+__HPP_ENTRY_PERCENT_FN(_type, _field)
|
|
|
+
|
|
|
+#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
|
|
|
+__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
|
|
|
+__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
|
|
|
+__HPP_ENTRY_RAW_FN(_type, _field)
|
|
|
+
|
|
|
+
|
|
|
+HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
|
|
|
+HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
|
|
|
+HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
|
|
|
+HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
|
|
|
+HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
|
|
|
+
|
|
|
+HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
|
|
|
+HPP_RAW_FNS(period, "Period", period, 12, 12)
|
|
|
|
|
|
-static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
|
|
|
- struct hist_entry *he)
|
|
|
-{
|
|
|
- struct hists *hists = he->hists;
|
|
|
- double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
|
|
|
-
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
|
|
-}
|
|
|
|
|
|
static int hpp__header_baseline(struct perf_hpp *hpp)
|
|
|
{
|
|
@@ -179,7 +192,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
{
|
|
|
double percent = baseline_percent(he);
|
|
|
|
|
|
- if (hist_entry__has_pairs(he))
|
|
|
+ if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
|
|
|
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
|
|
|
else
|
|
|
return scnprintf(hpp->buf, hpp->size, " ");
|
|
@@ -196,44 +209,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
return scnprintf(hpp->buf, hpp->size, " ");
|
|
|
}
|
|
|
|
|
|
-static int hpp__header_samples(struct perf_hpp *hpp)
|
|
|
-{
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
|
|
|
-
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 11;
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
|
|
|
-
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__header_period(struct perf_hpp *hpp)
|
|
|
-{
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
|
|
|
-
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, "Period");
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
|
|
|
-{
|
|
|
- return 12;
|
|
|
-}
|
|
|
-
|
|
|
-static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
|
|
|
-{
|
|
|
- const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
|
|
|
-
|
|
|
- return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
|
|
|
-}
|
|
|
-
|
|
|
static int hpp__header_period_baseline(struct perf_hpp *hpp)
|
|
|
{
|
|
|
const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
|
|
@@ -254,6 +229,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h
|
|
|
|
|
|
return scnprintf(hpp->buf, hpp->size, fmt, period);
|
|
|
}
|
|
|
+
|
|
|
static int hpp__header_delta(struct perf_hpp *hpp)
|
|
|
{
|
|
|
const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
|
|
@@ -408,9 +384,20 @@ struct perf_hpp_fmt perf_hpp__format[] = {
|
|
|
|
|
|
LIST_HEAD(perf_hpp__list);
|
|
|
|
|
|
+
|
|
|
#undef HPP__COLOR_PRINT_FNS
|
|
|
#undef HPP__PRINT_FNS
|
|
|
|
|
|
+#undef HPP_PERCENT_FNS
|
|
|
+#undef HPP_RAW_FNS
|
|
|
+
|
|
|
+#undef __HPP_HEADER_FN
|
|
|
+#undef __HPP_WIDTH_FN
|
|
|
+#undef __HPP_COLOR_PERCENT_FN
|
|
|
+#undef __HPP_ENTRY_PERCENT_FN
|
|
|
+#undef __HPP_ENTRY_RAW_FN
|
|
|
+
|
|
|
+
|
|
|
void perf_hpp__init(void)
|
|
|
{
|
|
|
if (symbol_conf.show_cpu_utilization) {
|
|
@@ -508,12 +495,15 @@ unsigned int hists__sort_list_width(struct hists *hists)
|
|
|
struct perf_hpp_fmt *fmt;
|
|
|
struct sort_entry *se;
|
|
|
int i = 0, ret = 0;
|
|
|
+ struct perf_hpp dummy_hpp = {
|
|
|
+ .ptr = hists_to_evsel(hists),
|
|
|
+ };
|
|
|
|
|
|
perf_hpp__for_each_format(fmt) {
|
|
|
if (i)
|
|
|
ret += 2;
|
|
|
|
|
|
- ret += fmt->width(NULL);
|
|
|
+ ret += fmt->width(&dummy_hpp);
|
|
|
}
|
|
|
|
|
|
list_for_each_entry(se, &hist_entry__sort_list, list)
|