|
@@ -65,6 +65,7 @@
|
|
|
#include "util/tool.h"
|
|
|
#include "util/string2.h"
|
|
|
#include "util/metricgroup.h"
|
|
|
+#include "util/top.h"
|
|
|
#include "asm/bug.h"
|
|
|
|
|
|
#include <linux/time64.h>
|
|
@@ -144,6 +145,8 @@ static struct target target = {
|
|
|
|
|
|
typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);
|
|
|
|
|
|
+#define METRIC_ONLY_LEN 20
|
|
|
+
|
|
|
static int run_count = 1;
|
|
|
static bool no_inherit = false;
|
|
|
static volatile pid_t child_pid = -1;
|
|
@@ -173,6 +176,7 @@ static struct cpu_map *aggr_map;
|
|
|
static aggr_get_id_t aggr_get_id;
|
|
|
static bool append_file;
|
|
|
static bool interval_count;
|
|
|
+static bool interval_clear;
|
|
|
static const char *output_name;
|
|
|
static int output_fd;
|
|
|
static int print_free_counters_hint;
|
|
@@ -180,6 +184,7 @@ static int print_mixed_hw_group_error;
|
|
|
static u64 *walltime_run;
|
|
|
static bool ru_display = false;
|
|
|
static struct rusage ru_data;
|
|
|
+static unsigned int metric_only_len = METRIC_ONLY_LEN;
|
|
|
|
|
|
struct perf_stat {
|
|
|
bool record;
|
|
@@ -967,8 +972,6 @@ static void print_metric_csv(void *ctx,
|
|
|
fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
|
|
|
}
|
|
|
|
|
|
-#define METRIC_ONLY_LEN 20
|
|
|
-
|
|
|
/* Filter out some columns that don't work well in metrics only mode */
|
|
|
|
|
|
static bool valid_only_metric(const char *unit)
|
|
@@ -999,22 +1002,20 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt,
|
|
|
{
|
|
|
struct outstate *os = ctx;
|
|
|
FILE *out = os->fh;
|
|
|
- int n;
|
|
|
- char buf[1024];
|
|
|
- unsigned mlen = METRIC_ONLY_LEN;
|
|
|
+ char buf[1024], str[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, "");
|
|
|
+
|
|
|
+ if (color)
|
|
|
+ mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
|
|
|
+
|
|
|
+ color_snprintf(str, sizeof(str), color ?: "", fmt, val);
|
|
|
+ fprintf(out, "%*s ", mlen, str);
|
|
|
}
|
|
|
|
|
|
static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
|
|
@@ -1054,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused,
|
|
|
if (csv_output)
|
|
|
fprintf(os->fh, "%s%s", unit, csv_sep);
|
|
|
else
|
|
|
- fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit);
|
|
|
+ fprintf(os->fh, "%*s ", metric_only_len, unit);
|
|
|
}
|
|
|
|
|
|
static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
|
|
@@ -1704,9 +1705,12 @@ static void print_interval(char *prefix, struct timespec *ts)
|
|
|
FILE *output = stat_config.output;
|
|
|
static int num_print_interval;
|
|
|
|
|
|
+ if (interval_clear)
|
|
|
+ puts(CONSOLE_CLEAR);
|
|
|
+
|
|
|
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) || interval_clear) {
|
|
|
switch (stat_config.aggr_mode) {
|
|
|
case AGGR_SOCKET:
|
|
|
fprintf(output, "# time socket cpus");
|
|
@@ -1719,7 +1723,7 @@ static void print_interval(char *prefix, struct timespec *ts)
|
|
|
fprintf(output, " counts %*s events\n", unit_width, "unit");
|
|
|
break;
|
|
|
case AGGR_NONE:
|
|
|
- fprintf(output, "# time CPU");
|
|
|
+ fprintf(output, "# time CPU ");
|
|
|
if (!metric_only)
|
|
|
fprintf(output, " counts %*s events\n", unit_width, "unit");
|
|
|
break;
|
|
@@ -1738,7 +1742,7 @@ static void print_interval(char *prefix, struct timespec *ts)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (num_print_interval == 0 && metric_only)
|
|
|
+ if ((num_print_interval == 0 && metric_only) || interval_clear)
|
|
|
print_metric_headers(" ", true);
|
|
|
if (++num_print_interval == 25)
|
|
|
num_print_interval = 0;
|
|
@@ -2057,6 +2061,8 @@ static const struct option stat_options[] = {
|
|
|
"(overhead is possible for values <= 100ms)"),
|
|
|
OPT_INTEGER(0, "interval-count", &stat_config.times,
|
|
|
"print counts for fixed number of times"),
|
|
|
+ OPT_BOOLEAN(0, "interval-clear", &interval_clear,
|
|
|
+ "clear screen in between new interval"),
|
|
|
OPT_UINTEGER(0, "timeout", &stat_config.timeout,
|
|
|
"stop workload and print counts after a timeout period in ms (>= 10ms)"),
|
|
|
OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
|
|
@@ -2436,14 +2442,13 @@ static int add_default_attributes(void)
|
|
|
(PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
|
|
|
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
|
|
};
|
|
|
+ struct parse_events_error errinfo;
|
|
|
|
|
|
/* Set attrs if no event is selected and !null_run: */
|
|
|
if (null_run)
|
|
|
return 0;
|
|
|
|
|
|
if (transaction_run) {
|
|
|
- struct parse_events_error errinfo;
|
|
|
-
|
|
|
if (pmu_have_event("cpu", "cycles-ct") &&
|
|
|
pmu_have_event("cpu", "el-start"))
|
|
|
err = parse_events(evsel_list, transaction_attrs,
|
|
@@ -2454,6 +2459,7 @@ static int add_default_attributes(void)
|
|
|
&errinfo);
|
|
|
if (err) {
|
|
|
fprintf(stderr, "Cannot set up transaction events\n");
|
|
|
+ parse_events_print_error(&errinfo, transaction_attrs);
|
|
|
return -1;
|
|
|
}
|
|
|
return 0;
|
|
@@ -2479,10 +2485,11 @@ static int add_default_attributes(void)
|
|
|
pmu_have_event("msr", "smi")) {
|
|
|
if (!force_metric_only)
|
|
|
metric_only = true;
|
|
|
- err = parse_events(evsel_list, smi_cost_attrs, NULL);
|
|
|
+ err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
|
|
|
} else {
|
|
|
fprintf(stderr, "To measure SMI cost, it needs "
|
|
|
"msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
|
|
|
+ parse_events_print_error(&errinfo, smi_cost_attrs);
|
|
|
return -1;
|
|
|
}
|
|
|
if (err) {
|
|
@@ -2517,12 +2524,13 @@ static int add_default_attributes(void)
|
|
|
if (topdown_attrs[0] && str) {
|
|
|
if (warn)
|
|
|
arch_topdown_group_warn();
|
|
|
- err = parse_events(evsel_list, str, NULL);
|
|
|
+ err = parse_events(evsel_list, str, &errinfo);
|
|
|
if (err) {
|
|
|
fprintf(stderr,
|
|
|
"Cannot set up top down events %s: %d\n",
|
|
|
str, err);
|
|
|
free(str);
|
|
|
+ parse_events_print_error(&errinfo, str);
|
|
|
return -1;
|
|
|
}
|
|
|
} else {
|