* [PATCH 1/8] perf, tools, stat: Abstract stat metrics printing
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 2/8] perf, tools, stat: Add support for metrics in interval mode Andi Kleen
` (7 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Abstract the printing of shadow metrics. Instead of every
metric calling fprintf directly and taking care of indentation,
use two call backs: one to print metrics and another to
start a new line.
This will allow adding metrics to CSV mode and also
using them for other purposes.
The computation of padding is now done in the central
callback, instead of every metric doing it manually.
This makes it easier to add new metrics.
v2: Refactor functions, printout now does more. Move
shadow printing. Improve fallback callbacks. Don't
use void * callback data.
v3: Remove unnecessary hunk. Add typedef for new_line
v4: Remove unnecessary hunk. Don't print metrics for CSV/interval
mode yet. Move printout change to separate patch.
v5: Fix bisect bugs. Avoid bogus frontend cycles printing.
Fix indentation in different aggregation modes.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 59 ++++++++++--
tools/perf/util/stat-shadow.c | 211 +++++++++++++++++++++++-------------------
tools/perf/util/stat.h | 15 ++-
3 files changed, 182 insertions(+), 103 deletions(-)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 7f56824..cba9753 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -735,6 +735,46 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
}
}
+struct outstate {
+ FILE *fh;
+};
+
+#define METRIC_LEN 35
+
+static void new_line_std(void *ctx)
+{
+ struct outstate *os = ctx;
+
+ fputc('\n', os->fh);
+ if (stat_config.aggr_mode == AGGR_NONE)
+ fprintf(os->fh, " ");
+ if (stat_config.aggr_mode == AGGR_CORE)
+ fprintf(os->fh, " ");
+ if (stat_config.aggr_mode == AGGR_SOCKET)
+ fprintf(os->fh, " ");
+ fprintf(os->fh, " ");
+}
+
+static void print_metric_std(void *ctx, const char *color, const char *fmt,
+ const char *unit, double val)
+{
+ struct outstate *os = ctx;
+ FILE *out = os->fh;
+ int n;
+
+ if (unit == NULL || fmt == NULL) {
+ fprintf(out, "%-*s", METRIC_LEN, "");
+ return;
+ }
+
+ n = fprintf(out, " # ");
+ if (color)
+ n += color_fprintf(out, color, fmt, val);
+ else
+ n += fprintf(out, fmt, val);
+ fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
+}
+
static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
FILE *output = stat_config.output;
@@ -795,20 +835,27 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
static void printout(int id, int nr, struct perf_evsel *counter, double uval)
{
- int cpu = cpu_map__id_to_cpu(id);
+ struct outstate os = { .fh = stat_config.output };
+ struct perf_stat_output_ctx out;
+ print_metric_t pm = print_metric_std;
+ void (*nl)(void *);
- if (stat_config.aggr_mode == AGGR_GLOBAL)
- cpu = 0;
+ nl = new_line_std;
if (nsec_counter(counter))
nsec_printout(id, nr, counter, uval);
else
abs_printout(id, nr, counter, uval);
+ out.print_metric = pm;
+ out.new_line = nl;
+ out.ctx = &os;
+
if (!csv_output && !stat_config.interval)
- perf_stat__print_shadow_stats(stat_config.output, counter,
- uval, cpu,
- stat_config.aggr_mode);
+ perf_stat__print_shadow_stats(counter, uval,
+ stat_config.aggr_mode == AGGR_GLOBAL ? 0 :
+ cpu_map__id_to_cpu(id),
+ &out);
}
static void print_aggr(char *prefix)
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 6ac0314..4d8f185 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -137,9 +137,10 @@ static const char *get_ratio_color(enum grc_type type, double ratio)
return color;
}
-static void print_stalled_cycles_frontend(FILE *out, int cpu,
+static void print_stalled_cycles_frontend(int cpu,
struct perf_evsel *evsel
- __maybe_unused, double avg)
+ __maybe_unused, double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -152,14 +153,17 @@ static void print_stalled_cycles_frontend(FILE *out, int cpu,
color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " frontend cycles idle ");
+ if (ratio)
+ out->print_metric(out->ctx, color, "%7.2f%%", "frontend cycles idle",
+ ratio);
+ else
+ out->print_metric(out->ctx, NULL, NULL, "frontend cycles idle", 0);
}
-static void print_stalled_cycles_backend(FILE *out, int cpu,
+static void print_stalled_cycles_backend(int cpu,
struct perf_evsel *evsel
- __maybe_unused, double avg)
+ __maybe_unused, double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -172,14 +176,13 @@ static void print_stalled_cycles_backend(FILE *out, int cpu,
color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " backend cycles idle ");
+ out->print_metric(out->ctx, color, "%6.2f%%", "backend cycles idle", ratio);
}
-static void print_branch_misses(FILE *out, int cpu,
+static void print_branch_misses(int cpu,
struct perf_evsel *evsel __maybe_unused,
- double avg)
+ double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -192,14 +195,13 @@ static void print_branch_misses(FILE *out, int cpu,
color = get_ratio_color(GRC_CACHE_MISSES, ratio);
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " of all branches ");
+ out->print_metric(out->ctx, color, "%7.2f%%", "of all branches", ratio);
}
-static void print_l1_dcache_misses(FILE *out, int cpu,
+static void print_l1_dcache_misses(int cpu,
struct perf_evsel *evsel __maybe_unused,
- double avg)
+ double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -212,14 +214,13 @@ static void print_l1_dcache_misses(FILE *out, int cpu,
color = get_ratio_color(GRC_CACHE_MISSES, ratio);
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " of all L1-dcache hits ");
+ out->print_metric(out->ctx, color, "%7.2f%%", "of all L1-dcache hits", ratio);
}
-static void print_l1_icache_misses(FILE *out, int cpu,
+static void print_l1_icache_misses(int cpu,
struct perf_evsel *evsel __maybe_unused,
- double avg)
+ double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -231,15 +232,13 @@ static void print_l1_icache_misses(FILE *out, int cpu,
ratio = avg / total * 100.0;
color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " of all L1-icache hits ");
+ out->print_metric(out->ctx, color, "%7.2f%%", "of all L1-icache hits", ratio);
}
-static void print_dtlb_cache_misses(FILE *out, int cpu,
+static void print_dtlb_cache_misses(int cpu,
struct perf_evsel *evsel __maybe_unused,
- double avg)
+ double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -251,15 +250,13 @@ static void print_dtlb_cache_misses(FILE *out, int cpu,
ratio = avg / total * 100.0;
color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " of all dTLB cache hits ");
+ out->print_metric(out->ctx, color, "%7.2f%%", "of all dTLB cache hits", ratio);
}
-static void print_itlb_cache_misses(FILE *out, int cpu,
+static void print_itlb_cache_misses(int cpu,
struct perf_evsel *evsel __maybe_unused,
- double avg)
+ double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -271,15 +268,13 @@ static void print_itlb_cache_misses(FILE *out, int cpu,
ratio = avg / total * 100.0;
color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " of all iTLB cache hits ");
+ out->print_metric(out->ctx, color, "%7.2f%%", "of all iTLB cache hits", ratio);
}
-static void print_ll_cache_misses(FILE *out, int cpu,
+static void print_ll_cache_misses(int cpu,
struct perf_evsel *evsel __maybe_unused,
- double avg)
+ double avg,
+ struct perf_stat_output_ctx *out)
{
double total, ratio = 0.0;
const char *color;
@@ -291,15 +286,15 @@ static void print_ll_cache_misses(FILE *out, int cpu,
ratio = avg / total * 100.0;
color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-
- fprintf(out, " # ");
- color_fprintf(out, color, "%6.2f%%", ratio);
- fprintf(out, " of all LL-cache hits ");
+ out->print_metric(out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio);
}
-void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
- double avg, int cpu, enum aggr_mode aggr)
+void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
+ double avg, int cpu,
+ struct perf_stat_output_ctx *out)
{
+ void *ctxp = out->ctx;
+ print_metric_t print_metric = out->print_metric;
double total, ratio = 0.0, total2;
int ctx = evsel_context(evsel);
@@ -307,119 +302,145 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
if (total) {
ratio = avg / total;
- fprintf(out, " # %5.2f insns per cycle ", ratio);
+ print_metric(ctxp, NULL, "%7.2f ",
+ "insn per cycle", ratio);
} else {
- fprintf(out, " ");
+ print_metric(ctxp, NULL, NULL, "insn per cycle", 0);
}
total = avg_stats(&runtime_stalled_cycles_front_stats[ctx][cpu]);
total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[ctx][cpu]));
+ out->new_line(ctxp);
if (total && avg) {
ratio = total / avg;
- fprintf(out, "\n");
- if (aggr == AGGR_NONE)
- fprintf(out, " ");
- fprintf(out, " # %5.2f stalled cycles per insn", ratio);
+ print_metric(ctxp, NULL, "%7.2f ",
+ "stalled cycles per insn",
+ ratio);
+ } else {
+ print_metric(ctxp, NULL, NULL,
+ "stalled cycles per insn", 0);
}
-
- } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
- runtime_branches_stats[ctx][cpu].n != 0) {
- print_branch_misses(out, cpu, evsel, avg);
+ } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
+ if (runtime_branches_stats[ctx][cpu].n != 0)
+ print_branch_misses(cpu, evsel, avg, out);
+ else
+ print_metric(ctxp, NULL, NULL, "of all branches", 0);
} else if (
evsel->attr.type == PERF_TYPE_HW_CACHE &&
evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
- ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
- runtime_l1_dcache_stats[ctx][cpu].n != 0) {
- print_l1_dcache_misses(out, cpu, evsel, avg);
+ ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
+ if (runtime_l1_dcache_stats[ctx][cpu].n != 0)
+ print_l1_dcache_misses(cpu, evsel, avg, out);
+ else
+ print_metric(ctxp, NULL, NULL, "of all L1-dcache hits", 0);
} else if (
evsel->attr.type == PERF_TYPE_HW_CACHE &&
evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
- ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
- runtime_l1_icache_stats[ctx][cpu].n != 0) {
- print_l1_icache_misses(out, cpu, evsel, avg);
+ ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
+ if (runtime_l1_icache_stats[ctx][cpu].n != 0)
+ print_l1_icache_misses(cpu, evsel, avg, out);
+ else
+ print_metric(ctxp, NULL, NULL, "of all L1-icache hits", 0);
} else if (
evsel->attr.type == PERF_TYPE_HW_CACHE &&
evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
- ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
- runtime_dtlb_cache_stats[ctx][cpu].n != 0) {
- print_dtlb_cache_misses(out, cpu, evsel, avg);
+ ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
+ if (runtime_dtlb_cache_stats[ctx][cpu].n != 0)
+ print_dtlb_cache_misses(cpu, evsel, avg, out);
+ else
+ print_metric(ctxp, NULL, NULL, "of all dTLB cache hits", 0);
} else if (
evsel->attr.type == PERF_TYPE_HW_CACHE &&
evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
- ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
- runtime_itlb_cache_stats[ctx][cpu].n != 0) {
- print_itlb_cache_misses(out, cpu, evsel, avg);
+ ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
+ if (runtime_itlb_cache_stats[ctx][cpu].n != 0)
+ print_itlb_cache_misses(cpu, evsel, avg, out);
+ else
+ print_metric(ctxp, NULL, NULL, "of all iTLB cache hits", 0);
} else if (
evsel->attr.type == PERF_TYPE_HW_CACHE &&
evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
- ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
- runtime_ll_cache_stats[ctx][cpu].n != 0) {
- print_ll_cache_misses(out, cpu, evsel, avg);
- } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) &&
- runtime_cacherefs_stats[ctx][cpu].n != 0) {
+ ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
+ if (runtime_ll_cache_stats[ctx][cpu].n != 0)
+ print_ll_cache_misses(cpu, evsel, avg, out);
+ else
+ print_metric(ctxp, NULL, NULL, "of all LL-cache hits", 0);
+ } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
total = avg_stats(&runtime_cacherefs_stats[ctx][cpu]);
if (total)
ratio = avg * 100 / total;
- fprintf(out, " # %8.3f %% of all cache refs ", ratio);
-
+ if (runtime_cacherefs_stats[ctx][cpu].n != 0)
+ print_metric(ctxp, NULL, "%8.3f %%",
+ "of all cache refs", ratio);
+ else
+ print_metric(ctxp, NULL, NULL, "of all cache refs", 0);
} else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
- print_stalled_cycles_frontend(out, cpu, evsel, avg);
+ print_stalled_cycles_frontend(cpu, evsel, avg, out);
} else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
- print_stalled_cycles_backend(out, cpu, evsel, avg);
+ print_stalled_cycles_backend(cpu, evsel, avg, out);
} else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
total = avg_stats(&runtime_nsecs_stats[cpu]);
if (total) {
ratio = avg / total;
- fprintf(out, " # %8.3f GHz ", ratio);
+ print_metric(ctxp, NULL, "%8.3f", "GHz", ratio);
} else {
- fprintf(out, " ");
+ print_metric(ctxp, NULL, NULL, "Ghz", 0);
}
} else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) {
total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
if (total)
- fprintf(out,
- " # %5.2f%% transactional cycles ",
- 100.0 * (avg / total));
+ print_metric(ctxp, NULL,
+ "%7.2f%%", "transactional cycles",
+ 100.0 * (avg / total));
+ else
+ print_metric(ctxp, NULL, NULL, "transactional cycles",
+ 0);
} else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) {
total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
total2 = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
if (total2 < avg)
total2 = avg;
if (total)
- fprintf(out,
- " # %5.2f%% aborted cycles ",
+ print_metric(ctxp, NULL, "%7.2f%%", "aborted cycles",
100.0 * ((total2-avg) / total));
- } else if (perf_stat_evsel__is(evsel, TRANSACTION_START) &&
- runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
+ else
+ print_metric(ctxp, NULL, NULL, "aborted cycles", 0);
+ } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) {
total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
if (avg)
ratio = total / avg;
- fprintf(out, " # %8.0f cycles / transaction ", ratio);
- } else if (perf_stat_evsel__is(evsel, ELISION_START) &&
- runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
+ if (runtime_cycles_in_tx_stats[ctx][cpu].n != 0)
+ print_metric(ctxp, NULL, "%8.0f",
+ "cycles / transaction", ratio);
+ else
+ print_metric(ctxp, NULL, NULL, "cycles / transaction",
+ 0);
+ } else if (perf_stat_evsel__is(evsel, ELISION_START)) {
total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
if (avg)
ratio = total / avg;
- fprintf(out, " # %8.0f cycles / elision ", ratio);
+ print_metric(ctxp, NULL, "%8.0f", "cycles / elision", ratio);
} else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) {
if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
- fprintf(out, " # %8.3f CPUs utilized ", avg / ratio);
+ print_metric(ctxp, NULL, "%8.3f", "CPUs utilized",
+ avg / ratio);
else
- fprintf(out, " ");
+ print_metric(ctxp, NULL, NULL, "CPUs utilized", 0);
} else if (runtime_nsecs_stats[cpu].n != 0) {
char unit = 'M';
+ char unit_buf[10];
total = avg_stats(&runtime_nsecs_stats[cpu]);
@@ -429,9 +450,9 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
ratio *= 1000;
unit = 'K';
}
-
- fprintf(out, " # %8.3f %c/sec ", ratio, unit);
+ snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
+ print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio);
} else {
- fprintf(out, " ");
+ print_metric(ctxp, NULL, NULL, NULL, 0);
}
}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 086f4e1..f14c0f4 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -68,11 +68,22 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel);
extern struct stats walltime_nsecs_stats;
+typedef void (*print_metric_t)(void *ctx, const char *color, const char *unit,
+ const char *fmt, double val);
+typedef void (*new_line_t )(void *ctx);
+
void perf_stat__reset_shadow_stats(void);
void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
int cpu);
-void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
- double avg, int cpu, enum aggr_mode aggr);
+struct perf_stat_output_ctx {
+ void *ctx;
+ print_metric_t print_metric;
+ new_line_t new_line;
+};
+
+void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
+ double avg, int cpu,
+ struct perf_stat_output_ctx *out);
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel);
int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel);
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/8] perf, tools, stat: Add support for metrics in interval mode
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
2016-01-16 1:11 ` [PATCH 1/8] perf, tools, stat: Abstract stat metrics printing Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 3/8] perf, tools, stat: Move noise/running printing into printout Andi Kleen
` (6 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Now that we can modify the metrics printout functions easily,
it's straight forward to support metric printing for interval mode.
All that is needed is to print the time stamp on every new line.
Pass the prefix into the context and print it out.
v2: Move wrong hunk to here.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index cba9753..648a8af 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -737,6 +737,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
struct outstate {
FILE *fh;
+ const char *prefix;
};
#define METRIC_LEN 35
@@ -746,6 +747,7 @@ static void new_line_std(void *ctx)
struct outstate *os = ctx;
fputc('\n', os->fh);
+ fputs(os->prefix, os->fh);
if (stat_config.aggr_mode == AGGR_NONE)
fprintf(os->fh, " ");
if (stat_config.aggr_mode == AGGR_CORE)
@@ -833,10 +835,14 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
}
-static void printout(int id, int nr, struct perf_evsel *counter, double uval)
+static void printout(int id, int nr, struct perf_evsel *counter, double uval,
+ char *prefix)
{
- struct outstate os = { .fh = stat_config.output };
struct perf_stat_output_ctx out;
+ struct outstate os = {
+ .fh = stat_config.output,
+ .prefix = prefix ? prefix : ""
+ };
print_metric_t pm = print_metric_std;
void (*nl)(void *);
@@ -851,7 +857,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval)
out.new_line = nl;
out.ctx = &os;
- if (!csv_output && !stat_config.interval)
+ if (!csv_output)
perf_stat__print_shadow_stats(counter, uval,
stat_config.aggr_mode == AGGR_GLOBAL ? 0 :
cpu_map__id_to_cpu(id),
@@ -911,7 +917,7 @@ static void print_aggr(char *prefix)
continue;
}
uval = val * counter->scale;
- printout(id, nr, counter, uval);
+ printout(id, nr, counter, uval, prefix);
if (!csv_output)
print_noise(counter, 1.0);
@@ -942,7 +948,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
fprintf(output, "%s", prefix);
uval = val * counter->scale;
- printout(thread, 0, counter, uval);
+ printout(thread, 0, counter, uval, prefix);
if (!csv_output)
print_noise(counter, 1.0);
@@ -992,7 +998,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
}
uval = avg * counter->scale;
- printout(-1, 0, counter, uval);
+ printout(-1, 0, counter, uval, prefix);
print_noise(counter, avg);
@@ -1045,7 +1051,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
}
uval = val * counter->scale;
- printout(cpu, 0, counter, uval);
+ printout(cpu, 0, counter, uval, prefix);
if (!csv_output)
print_noise(counter, 1.0);
print_running(run, ena);
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 3/8] perf, tools, stat: Move noise/running printing into printout
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
2016-01-16 1:11 ` [PATCH 1/8] perf, tools, stat: Abstract stat metrics printing Andi Kleen
2016-01-16 1:11 ` [PATCH 2/8] perf, tools, stat: Add support for metrics in interval mode Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 4/8] perf, tools, stat: Implement CSV metrics output Andi Kleen
` (5 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Move the running/noise printing into printout to avoid
duplicated code in the callers.
v2: Merged with other patches. Remove unnecessary hunk.
Readd hunk that ended in earlier patch.
v3: Fix noise/running output in CSV mode
v4: Merge with later patch that also moves not supported printing.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 123 ++++++++++++----------------------------------
1 file changed, 32 insertions(+), 91 deletions(-)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 648a8af..fe22d20 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -836,7 +836,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
}
static void printout(int id, int nr, struct perf_evsel *counter, double uval,
- char *prefix)
+ char *prefix, u64 run, u64 ena, double noise)
{
struct perf_stat_output_ctx out;
struct outstate os = {
@@ -848,6 +848,30 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
nl = new_line_std;
+ if (run == 0 || ena == 0) {
+ aggr_printout(counter, id, nr);
+
+ fprintf(stat_config.output, "%*s%s",
+ csv_output ? 0 : 18,
+ counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
+ csv_sep);
+
+ fprintf(stat_config.output, "%-*s%s",
+ csv_output ? 0 : unit_width,
+ counter->unit, csv_sep);
+
+ fprintf(stat_config.output, "%*s",
+ csv_output ? 0 : -25,
+ perf_evsel__name(counter));
+
+ if (counter->cgrp)
+ fprintf(stat_config.output, "%s%s",
+ csv_sep, counter->cgrp->name);
+
+ print_running(run, ena);
+ return;
+ }
+
if (nsec_counter(counter))
nsec_printout(id, nr, counter, uval);
else
@@ -862,6 +886,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
stat_config.aggr_mode == AGGR_GLOBAL ? 0 :
cpu_map__id_to_cpu(id),
&out);
+
+ print_noise(counter, noise);
+ print_running(run, ena);
}
static void print_aggr(char *prefix)
@@ -892,36 +919,8 @@ static void print_aggr(char *prefix)
if (prefix)
fprintf(output, "%s", prefix);
- if (run == 0 || ena == 0) {
- aggr_printout(counter, id, nr);
-
- fprintf(output, "%*s%s",
- csv_output ? 0 : 18,
- counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
- csv_sep);
-
- fprintf(output, "%-*s%s",
- csv_output ? 0 : unit_width,
- counter->unit, csv_sep);
-
- fprintf(output, "%*s",
- csv_output ? 0 : -25,
- perf_evsel__name(counter));
-
- if (counter->cgrp)
- fprintf(output, "%s%s",
- csv_sep, counter->cgrp->name);
-
- print_running(run, ena);
- fputc('\n', output);
- continue;
- }
uval = val * counter->scale;
- printout(id, nr, counter, uval, prefix);
- if (!csv_output)
- print_noise(counter, 1.0);
-
- print_running(run, ena);
+ printout(id, nr, counter, uval, prefix, run, ena, 1.0);
fputc('\n', output);
}
}
@@ -948,12 +947,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
fprintf(output, "%s", prefix);
uval = val * counter->scale;
- printout(thread, 0, counter, uval, prefix);
-
- if (!csv_output)
- print_noise(counter, 1.0);
-
- print_running(run, ena);
+ printout(thread, 0, counter, uval, prefix, run, ena, 1.0);
fputc('\n', output);
}
}
@@ -967,7 +961,6 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
FILE *output = stat_config.output;
struct perf_stat_evsel *ps = counter->priv;
double avg = avg_stats(&ps->res_stats[0]);
- int scaled = counter->counts->scaled;
double uval;
double avg_enabled, avg_running;
@@ -977,32 +970,8 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
if (prefix)
fprintf(output, "%s", prefix);
- if (scaled == -1 || !counter->supported) {
- fprintf(output, "%*s%s",
- csv_output ? 0 : 18,
- counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
- csv_sep);
- fprintf(output, "%-*s%s",
- csv_output ? 0 : unit_width,
- counter->unit, csv_sep);
- fprintf(output, "%*s",
- csv_output ? 0 : -25,
- perf_evsel__name(counter));
-
- if (counter->cgrp)
- fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
-
- print_running(avg_running, avg_enabled);
- fputc('\n', output);
- return;
- }
-
uval = avg * counter->scale;
- printout(-1, 0, counter, uval, prefix);
-
- print_noise(counter, avg);
-
- print_running(avg_running, avg_enabled);
+ printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg);
fprintf(output, "\n");
}
@@ -1025,36 +994,8 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
if (prefix)
fprintf(output, "%s", prefix);
- if (run == 0 || ena == 0) {
- fprintf(output, "CPU%*d%s%*s%s",
- csv_output ? 0 : -4,
- perf_evsel__cpus(counter)->map[cpu], csv_sep,
- csv_output ? 0 : 18,
- counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
- csv_sep);
-
- fprintf(output, "%-*s%s",
- csv_output ? 0 : unit_width,
- counter->unit, csv_sep);
-
- fprintf(output, "%*s",
- csv_output ? 0 : -25,
- perf_evsel__name(counter));
-
- if (counter->cgrp)
- fprintf(output, "%s%s",
- csv_sep, counter->cgrp->name);
-
- print_running(run, ena);
- fputc('\n', output);
- continue;
- }
-
uval = val * counter->scale;
- printout(cpu, 0, counter, uval, prefix);
- if (!csv_output)
- print_noise(counter, 1.0);
- print_running(run, ena);
+ printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
fputc('\n', output);
}
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 4/8] perf, tools, stat: Implement CSV metrics output
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
` (2 preceding siblings ...)
2016-01-16 1:11 ` [PATCH 3/8] perf, tools, stat: Move noise/running printing into printout Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 5/8] perf, tools: Support metrics in --per-core/socket mode Andi Kleen
` (4 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Now support CSV output for metrics. With the new output callbacks
this is relatively straight forward by creating new callbacks.
The new line callback needs to know the number of fields to skip them
correctly
v2: Split out function argument changes
v3: Reenable metrics for real.
v4: Fix wrong hunk from refactoring.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 66 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index fe22d20..a9bdb4a 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -738,6 +738,8 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
struct outstate {
FILE *fh;
const char *prefix;
+ int nfields;
+ u64 run, ena;
};
#define METRIC_LEN 35
@@ -777,6 +779,49 @@ static void print_metric_std(void *ctx, const char *color, const char *fmt,
fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
}
+static void new_line_csv(void *ctx)
+{
+ struct outstate *os = ctx;
+ int i;
+
+ fputc('\n', os->fh);
+ if (os->prefix)
+ fprintf(os->fh, "%s%s", os->prefix, csv_sep);
+ for (i = 0; i < os->nfields; i++)
+ fputs(csv_sep, os->fh);
+}
+
+static void print_metric_csv(void *ctx,
+ const char *color __maybe_unused,
+ const char *fmt, const char *unit, double val)
+{
+ struct outstate *os = ctx;
+ FILE *out = os->fh;
+ char buf[64], *vals, *ends;
+
+ if (unit == NULL) {
+ fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep);
+ return;
+ }
+ fprintf(out, "%s%" PRIu64 "%s%.2f%s",
+ csv_sep,
+ os->run,
+ csv_sep,
+ os->ena ? 100.0 * os->run / os->ena : 100.0,
+ csv_sep);
+ snprintf(buf, sizeof(buf), fmt, val);
+ vals = buf;
+ while (isspace(*vals))
+ vals++;
+ ends = vals;
+ while (isdigit(*ends) || *ends == '.')
+ ends++;
+ *ends = 0;
+ while (isspace(*unit))
+ unit++;
+ fprintf(out, "%s%s%s", vals, csv_sep, unit);
+}
+
static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
FILE *output = stat_config.output;
@@ -848,6 +893,24 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
nl = new_line_std;
+ if (csv_output) {
+ static int aggr_fields[] = {
+ [AGGR_GLOBAL] = 0,
+ [AGGR_THREAD] = 1,
+ [AGGR_NONE] = 1,
+ [AGGR_SOCKET] = 2,
+ [AGGR_CORE] = 2,
+ };
+
+ pm = print_metric_csv;
+ nl = new_line_csv;
+ os.nfields = 1;
+ os.nfields += aggr_fields[stat_config.aggr_mode];
+ if (counter->cgrp)
+ os.nfields++;
+ os.run = run;
+ os.ena = ena;
+ }
if (run == 0 || ena == 0) {
aggr_printout(counter, id, nr);
@@ -881,8 +944,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
out.new_line = nl;
out.ctx = &os;
- if (!csv_output)
- perf_stat__print_shadow_stats(counter, uval,
+ perf_stat__print_shadow_stats(counter, uval,
stat_config.aggr_mode == AGGR_GLOBAL ? 0 :
cpu_map__id_to_cpu(id),
&out);
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 5/8] perf, tools: Support metrics in --per-core/socket mode
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
` (3 preceding siblings ...)
2016-01-16 1:11 ` [PATCH 4/8] perf, tools, stat: Implement CSV metrics output Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 6/8] perf, tools, stat: Document CSV format in manpage Andi Kleen
` (3 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Enable metrics printing in --per-core / --per-socket mode. We need
to save the shadow metrics in a unique place. Always use the first
CPU in the aggregation. Then use the same CPU to retrieve the
shadow value later.
Example output:
% perf stat --per-core -a ./BC1s
Performance counter stats for 'system wide':
S0-C0 2 2966.020381 task-clock (msec) # 2.004 CPUs utilized (100.00%)
S0-C0 2 49 context-switches # 0.017 K/sec (100.00%)
S0-C0 2 4 cpu-migrations # 0.001 K/sec (100.00%)
S0-C0 2 467 page-faults # 0.157 K/sec
S0-C0 2 4,599,061,773 cycles # 1.551 GHz (100.00%)
S0-C0 2 9,755,886,883 instructions # 2.12 insn per cycle (100.00%)
S0-C0 2 1,906,272,125 branches # 642.704 M/sec (100.00%)
S0-C0 2 81,180,867 branch-misses # 4.26% of all branches
S0-C1 2 2965.995373 task-clock (msec) # 2.003 CPUs utilized (100.00%)
S0-C1 2 62 context-switches # 0.021 K/sec (100.00%)
S0-C1 2 8 cpu-migrations # 0.003 K/sec (100.00%)
S0-C1 2 281 page-faults # 0.095 K/sec
S0-C1 2 6,347,290 cycles # 0.002 GHz (100.00%)
S0-C1 2 4,654,156 instructions # 0.73 insn per cycle (100.00%)
S0-C1 2 947,121 branches # 0.319 M/sec (100.00%)
S0-C1 2 37,322 branch-misses # 3.94% of all branches
1.480409747 seconds time elapsed
v2: Rebase to older patches
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 58 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 51 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a9bdb4a..304127a 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -740,6 +740,8 @@ struct outstate {
const char *prefix;
int nfields;
u64 run, ena;
+ int id, nr;
+ struct perf_evsel *evsel;
};
#define METRIC_LEN 35
@@ -750,12 +752,9 @@ static void new_line_std(void *ctx)
fputc('\n', os->fh);
fputs(os->prefix, os->fh);
+ aggr_printout(os->evsel, os->id, os->nr);
if (stat_config.aggr_mode == AGGR_NONE)
fprintf(os->fh, " ");
- if (stat_config.aggr_mode == AGGR_CORE)
- fprintf(os->fh, " ");
- if (stat_config.aggr_mode == AGGR_SOCKET)
- fprintf(os->fh, " ");
fprintf(os->fh, " ");
}
@@ -787,6 +786,7 @@ static void new_line_csv(void *ctx)
fputc('\n', os->fh);
if (os->prefix)
fprintf(os->fh, "%s%s", os->prefix, csv_sep);
+ aggr_printout(os->evsel, os->id, os->nr);
for (i = 0; i < os->nfields; i++)
fputs(csv_sep, os->fh);
}
@@ -850,6 +850,22 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
}
+static int first_shadow_cpu(struct perf_evsel *evsel, int id)
+{
+ int i;
+
+ if (aggr_get_id == NULL)
+ return 0;
+
+ for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
+ int cpu2 = perf_evsel__cpus(evsel)->map[i];
+
+ if (aggr_get_id(evsel_list->cpus, cpu2) == id)
+ return cpu2;
+ }
+ return 0;
+}
+
static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
FILE *output = stat_config.output;
@@ -886,7 +902,10 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
struct perf_stat_output_ctx out;
struct outstate os = {
.fh = stat_config.output,
- .prefix = prefix ? prefix : ""
+ .prefix = prefix ? prefix : "",
+ .id = id,
+ .nr = nr,
+ .evsel = counter,
};
print_metric_t pm = print_metric_std;
void (*nl)(void *);
@@ -946,13 +965,36 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
perf_stat__print_shadow_stats(counter, uval,
stat_config.aggr_mode == AGGR_GLOBAL ? 0 :
- cpu_map__id_to_cpu(id),
+ first_shadow_cpu(counter, id),
&out);
-
print_noise(counter, noise);
print_running(run, ena);
}
+static void aggr_update_shadow(void)
+{
+ int cpu, cpu2, s2, id, s;
+ u64 val;
+ struct perf_evsel *counter;
+
+ for (s = 0; s < aggr_map->nr; s++) {
+ id = aggr_map->map[s];
+ evlist__for_each(evsel_list, counter) {
+ val = 0;
+ for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
+ cpu2 = perf_evsel__cpus(counter)->map[cpu];
+ s2 = aggr_get_id(evsel_list->cpus, cpu2);
+ if (s2 != id)
+ continue;
+ val += perf_counts(counter->counts, cpu, 0)->val;
+ }
+ val = val * counter->scale;
+ perf_stat__update_shadow_stats(counter, &val,
+ first_shadow_cpu(counter, id));
+ }
+ }
+}
+
static void print_aggr(char *prefix)
{
FILE *output = stat_config.output;
@@ -964,6 +1006,8 @@ static void print_aggr(char *prefix)
if (!(aggr_map || aggr_get_id))
return;
+ aggr_update_shadow();
+
for (s = 0; s < aggr_map->nr; s++) {
id = aggr_map->map[s];
evlist__for_each(evsel_list, counter) {
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 6/8] perf, tools, stat: Document CSV format in manpage
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
` (4 preceding siblings ...)
2016-01-16 1:11 ` [PATCH 5/8] perf, tools: Support metrics in --per-core/socket mode Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 7/8] perf, tools, stat: Implement --metric-only mode Andi Kleen
` (2 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
With all the recently added fields in the perf stat CSV output
we should finally document them in the man page. Do this here.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/Documentation/perf-stat.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 52ef7a9..6629a8e 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -211,6 +211,25 @@ $ perf stat -- make -j
Wall-clock time elapsed: 719.554352 msecs
+CSV FORMAT
+----------
+
+With -x, perf stat is able to output a not-quite-CSV format output
+(commas in the output are not put into "")
+
+The fields are in this order:
+
+ - optional usec time stamp in fractions of second (with -I xxx)
+ - unit of the counter value or empty
+ - event name
+ - counter value
+ - run time of counter
+ - percentage of measurement time the counter was running
+ - optional metric value
+ - optional unit of metric
+
+Additional metrics may be printed with all earlier fields being empty.
+
SEE ALSO
--------
linkperf:perf-top[1], linkperf:perf-list[1]
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 7/8] perf, tools, stat: Implement --metric-only mode
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
` (5 preceding siblings ...)
2016-01-16 1:11 ` [PATCH 6/8] perf, tools, stat: Document CSV format in manpage Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 1:11 ` [PATCH 8/8] perf, tools, stat: Fix indentation of counter running printout Andi Kleen
2016-01-16 20:21 ` perf, tools: Refactor and support interval and CSV metrics Jiri Olsa
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Add a new mode to only print metrics. Sometimes we don't care about
the raw values, just want the computed metrics. This allows more
compact printing, so with -I each sample is only a single line.
This also allows easier plotting and processing with other tools.
The main target is with using --topdown, but it also works with
-T and standard perf stat. A few metrics are not supported.
To avoiding having to hardcode all the metrics in the code it uses
a two pass approach: first compute dummy metrics and only
print the headers in the print_metric callback. Then use the callback
to print the actual values. There are some additional changes
in the stat printout code to handle all metrics being on a single line.
Example:
% perf stat -a -I 1000 --metric-only
1.000604977 frontend cycles idle backend cycles idle insn per cycle stalled cycles per insn branch-misses of all branches
1.000604977 0.76 2.35%
2.000924680 0.72 2.34%
3.001139592 0.76 2.57%
4.001358452 0.73 2.44%
The output is fairly wide, but that's a trade off for the concise format.
v2: Lots of updates.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/Documentation/perf-stat.txt | 4 +
tools/perf/builtin-stat.c | 210 +++++++++++++++++++++++++++++++--
2 files changed, 204 insertions(+), 10 deletions(-)
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 6629a8e..51e3c5a 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -139,6 +139,10 @@ Print count deltas every N milliseconds (minimum: 10ms)
The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution.
example: 'perf stat -I 1000 -e cycles -a sleep 5'
+--metric-only::
+Only print computed metrics. Print them in a single line.
+Don't show any raw values. Not supported with -A or --per-thread.
+
--per-socket::
Aggregate counts per processor socket for system-wide mode measurements. This
is a useful mode to detect imbalance between sockets. To enable this mode,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 304127a..7f2ed13 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -122,6 +122,7 @@ static bool sync_run = false;
static unsigned int initial_delay = 0;
static unsigned int unit_width = 4; /* strlen("unit") */
static bool forever = false;
+static bool metric_only = false;
static struct timespec ref_time;
static struct cpu_map *aggr_map;
static aggr_get_id_t aggr_get_id;
@@ -822,6 +823,99 @@ static void print_metric_csv(void *ctx,
fprintf(out, "%s%s%s", vals, csv_sep, unit);
}
+#define METRIC_ONLY_LEN 24
+
+/* Filter out some columns that don't work well in metrics only mode */
+
+static bool valid_only_metric(const char *unit)
+{
+ if (!unit)
+ return false;
+ if (strstr(unit, "/sec") ||
+ strstr(unit, "hz") ||
+ strstr(unit, "Hz") ||
+ strstr(unit, "CPUs utilized"))
+ return false;
+ return true;
+}
+
+static const char *fixunit(char *buf, struct perf_evsel *evsel,
+ const char *unit)
+{
+ if (!strncmp(unit, "of all", 6)) {
+ snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
+ unit);
+ return buf;
+ }
+ return unit;
+}
+
+static void print_metric_only(void *ctx, const char *color, const char *fmt,
+ const char *unit, double val)
+{
+ struct outstate *os = ctx;
+ FILE *out = os->fh;
+ int n;
+ char buf[1024];
+ unsigned mlen = METRIC_ONLY_LEN;
+
+ if (!valid_only_metric(unit))
+ return;
+ unit = fixunit(buf, os->evsel, unit);
+ if (color)
+ n = color_fprintf(out, color, fmt, val);
+ else
+ n = fprintf(out, fmt, val);
+ if (n > METRIC_ONLY_LEN)
+ n = METRIC_ONLY_LEN;
+ if (mlen < strlen(unit))
+ mlen = strlen(unit) + 1;
+ fprintf(out, "%*s", mlen - n, "");
+}
+
+static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
+ const char *fmt,
+ const char *unit, double val)
+{
+ struct outstate *os = ctx;
+ FILE *out = os->fh;
+ char buf[64], *vals, *ends;
+ char tbuf[1024];
+
+ if (!valid_only_metric(unit))
+ return;
+ unit = fixunit(tbuf, os->evsel, unit);
+ snprintf(buf, sizeof buf, fmt, val);
+ vals = buf;
+ while (isspace(*vals))
+ vals++;
+ ends = vals;
+ while (isdigit(*ends) || *ends == '.')
+ ends++;
+ *ends = 0;
+ fprintf(out, "%s%s", vals, csv_sep);
+}
+
+static void new_line_metric(void *ctx __maybe_unused)
+{
+}
+
+static void print_metric_header(void *ctx, const char *color __maybe_unused,
+ const char *fmt __maybe_unused,
+ const char *unit, double val __maybe_unused)
+{
+ struct outstate *os = ctx;
+ char tbuf[1024];
+
+ if (!valid_only_metric(unit))
+ return;
+ unit = fixunit(tbuf, os->evsel, unit);
+ if (csv_output)
+ fprintf(os->fh, "%s%s", unit, csv_sep);
+ else
+ fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit);
+}
+
static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
FILE *output = stat_config.output;
@@ -910,9 +1004,16 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
print_metric_t pm = print_metric_std;
void (*nl)(void *);
- nl = new_line_std;
+ if (metric_only) {
+ nl = new_line_metric;
+ if (csv_output)
+ pm = print_metric_only_csv;
+ else
+ pm = print_metric_only;
+ } else
+ nl = new_line_std;
- if (csv_output) {
+ if (csv_output && !metric_only) {
static int aggr_fields[] = {
[AGGR_GLOBAL] = 0,
[AGGR_THREAD] = 1,
@@ -931,6 +1032,10 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
os.ena = ena;
}
if (run == 0 || ena == 0) {
+ if (metric_only) {
+ pm(&os, NULL, "", "", 0);
+ return;
+ }
aggr_printout(counter, id, nr);
fprintf(stat_config.output, "%*s%s",
@@ -954,7 +1059,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
return;
}
- if (nsec_counter(counter))
+ if (metric_only)
+ /* nothing */;
+ else if (nsec_counter(counter))
nsec_printout(id, nr, counter, uval);
else
abs_printout(id, nr, counter, uval);
@@ -967,8 +1074,11 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
stat_config.aggr_mode == AGGR_GLOBAL ? 0 :
first_shadow_cpu(counter, id),
&out);
- print_noise(counter, noise);
- print_running(run, ena);
+
+ if (!metric_only) {
+ print_noise(counter, noise);
+ print_running(run, ena);
+ }
}
static void aggr_update_shadow(void)
@@ -1002,6 +1112,7 @@ static void print_aggr(char *prefix)
int cpu, s, s2, id, nr;
double uval;
u64 ena, run, val;
+ bool first;
if (!(aggr_map || aggr_get_id))
return;
@@ -1009,7 +1120,11 @@ static void print_aggr(char *prefix)
aggr_update_shadow();
for (s = 0; s < aggr_map->nr; s++) {
+ if (prefix && metric_only)
+ fprintf(output, "%s", prefix);
+
id = aggr_map->map[s];
+ first = true;
evlist__for_each(evsel_list, counter) {
val = ena = run = 0;
nr = 0;
@@ -1022,13 +1137,20 @@ static void print_aggr(char *prefix)
run += perf_counts(counter->counts, cpu, 0)->run;
nr++;
}
- if (prefix)
+ if (first && metric_only) {
+ first = false;
+ aggr_printout(counter, id, nr);
+ }
+ if (prefix && !metric_only)
fprintf(output, "%s", prefix);
uval = val * counter->scale;
printout(id, nr, counter, uval, prefix, run, ena, 1.0);
- fputc('\n', output);
+ if (!metric_only)
+ fputc('\n', output);
}
+ if (metric_only)
+ fputc('\n', output);
}
}
@@ -1073,12 +1195,13 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
avg_enabled = avg_stats(&ps->res_stats[1]);
avg_running = avg_stats(&ps->res_stats[2]);
- if (prefix)
+ if (prefix && !metric_only)
fprintf(output, "%s", prefix);
uval = avg * counter->scale;
printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg);
- fprintf(output, "\n");
+ if (!metric_only)
+ fprintf(output, "\n");
}
/*
@@ -1107,6 +1230,43 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
}
}
+static int aggr_header_lens[] = {
+ [AGGR_CORE] = 18,
+ [AGGR_SOCKET] = 12,
+ [AGGR_NONE] = 15,
+ [AGGR_THREAD] = 24,
+ [AGGR_GLOBAL] = 0,
+};
+
+static void print_metric_headers(char *prefix)
+{
+ struct perf_stat_output_ctx out;
+ struct perf_evsel *counter;
+ struct outstate os = {
+ .fh = stat_config.output
+ };
+
+ if (prefix)
+ fprintf(stat_config.output, "%s", prefix);
+
+ if (!csv_output)
+ fprintf(stat_config.output, "%*s",
+ aggr_header_lens[stat_config.aggr_mode], "");
+
+ /* Print metrics headers only */
+ evlist__for_each(evsel_list, counter) {
+ os.evsel = counter;
+ out.ctx = &os;
+ out.print_metric = print_metric_header;
+ out.new_line = new_line_metric;
+ os.evsel = counter;
+ perf_stat__print_shadow_stats(counter, 0,
+ 0,
+ &out);
+ }
+ fputc('\n', stat_config.output);
+}
+
static void print_interval(char *prefix, struct timespec *ts)
{
FILE *output = stat_config.output;
@@ -1114,7 +1274,7 @@ static void print_interval(char *prefix, struct timespec *ts)
sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
- if (num_print_interval == 0 && !csv_output) {
+ if (num_print_interval == 0 && !csv_output && !metric_only) {
switch (stat_config.aggr_mode) {
case AGGR_SOCKET:
fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
@@ -1201,6 +1361,17 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
else
print_header(argc, argv);
+ if (metric_only) {
+ static int num_print_iv;
+
+ if (num_print_iv == 0)
+ print_metric_headers(prefix);
+ if (num_print_iv++ == 25)
+ num_print_iv = 0;
+ if (stat_config.aggr_mode == AGGR_GLOBAL && prefix)
+ fprintf(stat_config.output, "%s", prefix);
+ }
+
switch (stat_config.aggr_mode) {
case AGGR_CORE:
case AGGR_SOCKET:
@@ -1213,6 +1384,8 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
case AGGR_GLOBAL:
evlist__for_each(evsel_list, counter)
print_counter_aggr(counter, prefix);
+ if (metric_only)
+ fputc('\n', stat_config.output);
break;
case AGGR_NONE:
evlist__for_each(evsel_list, counter)
@@ -1337,6 +1510,8 @@ static const struct option stat_options[] = {
"aggregate counts per thread", AGGR_THREAD),
OPT_UINTEGER('D', "delay", &initial_delay,
"ms to wait before starting measurement after program start"),
+ OPT_BOOLEAN(0, "metric-only", &metric_only,
+ "Only print computed metrics. No raw values"),
OPT_END()
};
@@ -1958,6 +2133,21 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
goto out;
}
+ if (metric_only && stat_config.aggr_mode == AGGR_THREAD) {
+ fprintf(stderr, "--metric-only is not supported with --per-thread\n");
+ goto out;
+ }
+
+ if (metric_only && stat_config.aggr_mode == AGGR_NONE) {
+ fprintf(stderr, "--metric-only is not supported with -A\n");
+ goto out;
+ }
+
+ if (metric_only && run_count > 1) {
+ fprintf(stderr, "--metric-only is not supported with -r\n");
+ goto out;
+ }
+
if (output_fd < 0) {
fprintf(stderr, "argument to --log-fd must be a > 0\n");
parse_options_usage(stat_usage, stat_options, "log-fd", 0);
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 8/8] perf, tools, stat: Fix indentation of counter running printout
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
` (6 preceding siblings ...)
2016-01-16 1:11 ` [PATCH 7/8] perf, tools, stat: Implement --metric-only mode Andi Kleen
@ 2016-01-16 1:11 ` Andi Kleen
2016-01-16 20:21 ` perf, tools: Refactor and support interval and CSV metrics Jiri Olsa
8 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-16 1:11 UTC (permalink / raw)
To: acme; +Cc: jolsa, eranian, linux-kernel, mingo, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Fix the indentation of the counter running printout for non supported
counters.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 7f2ed13..5a02870 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1055,6 +1055,8 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
fprintf(stat_config.output, "%s%s",
csv_sep, counter->cgrp->name);
+ pm(&os, NULL, NULL, "", 0);
+
print_running(run, ena);
return;
}
--
2.4.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: perf, tools: Refactor and support interval and CSV metrics
2016-01-16 1:11 perf, tools: Refactor and support interval and CSV metrics Andi Kleen
` (7 preceding siblings ...)
2016-01-16 1:11 ` [PATCH 8/8] perf, tools, stat: Fix indentation of counter running printout Andi Kleen
@ 2016-01-16 20:21 ` Jiri Olsa
2016-01-18 22:25 ` Andi Kleen
8 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2016-01-16 20:21 UTC (permalink / raw)
To: Andi Kleen; +Cc: acme, jolsa, eranian, linux-kernel, mingo
On Fri, Jan 15, 2016 at 05:11:07PM -0800, Andi Kleen wrote:
SNIP
> 1.000852081,1976560,,branch-misses,12010501884,100.00,8.32,of all branches
>
> Available in
> git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-misc-2.6 perf/stat-metrics-12
getting little tired of this:
http://marc.info/?l=linux-kernel&m=145076648115589&w=2
first patch in your perf/stat-metrics-12:
[jolsa@krava perf]$ ./perf stat -e instructions,cycles kill
kill: not enough arguments
Performance counter stats for 'kill':
772,743 instructions # 0.82 insn per cycle
947,484 cycles
0.002016698 seconds time elapsed
jirka
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: perf, tools: Refactor and support interval and CSV metrics
2016-01-16 20:21 ` perf, tools: Refactor and support interval and CSV metrics Jiri Olsa
@ 2016-01-18 22:25 ` Andi Kleen
0 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2016-01-18 22:25 UTC (permalink / raw)
To: Jiri Olsa; +Cc: Andi Kleen, acme, jolsa, eranian, linux-kernel, mingo
On Sat, Jan 16, 2016 at 09:21:20PM +0100, Jiri Olsa wrote:
> On Fri, Jan 15, 2016 at 05:11:07PM -0800, Andi Kleen wrote:
>
> SNIP
>
> > 1.000852081,1976560,,branch-misses,12010501884,100.00,8.32,of all branches
> >
> > Available in
> > git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-misc-2.6 perf/stat-metrics-12
>
> getting little tired of this:
> http://marc.info/?l=linux-kernel&m=145076648115589&w=2
Sorry I thought I had fixed it, but didn't. Next time for real.
-Andi
^ permalink raw reply [flat|nested] 16+ messages in thread