static void print_counters(struct timespec *ts, int argc, const char **argv);
-/* Default events used for perf stat -T */
-static const char *transaction_attrs = {
- "task-clock,"
- "{"
- "instructions,"
- "cycles,"
- "cpu/cycles-t/,"
- "cpu/tx-start/,"
- "cpu/el-start/,"
- "cpu/cycles-ct/"
- "}"
-};
-
-/* More limited version when the CPU does not have all events. */
-static const char * transaction_limited_attrs = {
- "task-clock,"
- "{"
- "instructions,"
- "cycles,"
- "cpu/cycles-t/,"
- "cpu/tx-start/"
- "}"
-};
-
-static const char * topdown_attrs[] = {
- "topdown-total-slots",
- "topdown-slots-retired",
- "topdown-recovery-bubbles",
- "topdown-fetch-bubbles",
- "topdown-slots-issued",
- NULL,
-};
-
-static const char *topdown_metric_attrs[] = {
- "slots",
- "topdown-retiring",
- "topdown-bad-spec",
- "topdown-fe-bound",
- "topdown-be-bound",
- NULL,
-};
-
-static const char *topdown_metric_L2_attrs[] = {
- "slots",
- "topdown-retiring",
- "topdown-bad-spec",
- "topdown-fe-bound",
- "topdown-be-bound",
- "topdown-heavy-ops",
- "topdown-br-mispredict",
- "topdown-fetch-lat",
- "topdown-mem-bound",
- NULL,
-};
-
-#define TOPDOWN_MAX_LEVEL 2
-
-static const char *smi_cost_attrs = {
- "{"
- "msr/aperf/,"
- "msr/smi/,"
- "cycles"
- "}"
-};
-
static struct evlist *evsel_list;
static bool all_counters_use_bpf = true;
perf_stat_merge_counters(&stat_config, evsel_list);
perf_stat_process_percore(&stat_config, evsel_list);
- perf_stat_process_shadow_stats(&stat_config, evsel_list);
}
static void process_interval(void)
clock_gettime(CLOCK_MONOTONIC, &ts);
diff_timespec(&rs, &ts, &ref_time);
- perf_stat__reset_shadow_per_stat(&rt_stat);
evlist__reset_aggr_stats(evsel_list);
if (read_counters(&rs) == 0)
return err;
}
- /*
- * We need to enable counters only if:
- * - we don't have tracee (attaching to task or cpu)
- * - we have initial delay configured
- */
- if (!target__none(&target)) {
+ if (!target__enable_on_exec(&target)) {
if (!all_counters_use_bpf)
evlist__enable(evsel_list);
}
return err;
}
- if (stat_config.initial_delay) {
+ if (target.initial_delay) {
pr_info(EVLIST_DISABLED_MSG);
} else {
err = enable_counters();
if (forks)
evlist__start_workload(evsel_list);
- if (stat_config.initial_delay > 0) {
- usleep(stat_config.initial_delay * USEC_PER_MSEC);
+ if (target.initial_delay > 0) {
+ usleep(target.initial_delay * USEC_PER_MSEC);
err = enable_counters();
if (err)
return -1;
evlist__copy_prev_raw_counts(evsel_list);
evlist__reset_prev_raw_counts(evsel_list);
evlist__reset_aggr_stats(evsel_list);
- perf_stat__reset_shadow_per_stat(&rt_stat);
} else {
update_stats(&walltime_nsecs_stats, t1 - t0);
update_rusage_stats(&ru_stats, &stat_config.ru_data);
"aggregate counts per thread", AGGR_THREAD),
OPT_SET_UINT(0, "per-node", &stat_config.aggr_mode,
"aggregate counts per numa node", AGGR_NODE),
- OPT_INTEGER('D', "delay", &stat_config.initial_delay,
+ OPT_INTEGER('D', "delay", &target.initial_delay,
"ms to wait before starting measurement after program start (-1: start with events disabled)"),
OPT_CALLBACK_NOOPT(0, "metric-only", &stat_config.metric_only, NULL,
"Only print computed metrics. No raw values", enable_metric_only),
"don't group metric events, impacts multiplexing"),
OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge,
"don't try to share events between metrics in a group"),
+ OPT_BOOLEAN(0, "metric-no-threshold", &stat_config.metric_no_threshold,
+ "don't try to share events between metrics in a group "),
OPT_BOOLEAN(0, "topdown", &topdown_run,
"measure top-down statistics"),
OPT_UINTEGER(0, "td-level", &stat_config.topdown_level,
*/
static int add_default_attributes(void)
{
- int err;
struct perf_event_attr default_attrs0[] = {
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
return 0;
if (transaction_run) {
- struct parse_events_error errinfo;
/* Handle -T as -M transaction. Once platform specific metrics
* support has been added to the json files, all architectures
* will use this approach. To determine transaction support
* on an architecture test for such a metric name.
*/
- if (metricgroup__has_metric("transaction")) {
- return metricgroup__parse_groups(evsel_list, "transaction",
- stat_config.metric_no_group,
- stat_config.metric_no_merge,
- stat_config.user_requested_cpu_list,
- stat_config.system_wide,
- &stat_config.metric_events);
- }
-
- parse_events_error__init(&errinfo);
- if (pmu_have_event("cpu", "cycles-ct") &&
- pmu_have_event("cpu", "el-start"))
- err = parse_events(evsel_list, transaction_attrs,
- &errinfo);
- else
- err = parse_events(evsel_list,
- transaction_limited_attrs,
- &errinfo);
- if (err) {
- fprintf(stderr, "Cannot set up transaction events\n");
- parse_events_error__print(&errinfo, transaction_attrs);
+ if (!metricgroup__has_metric("transaction")) {
+ pr_err("Missing transaction metrics");
+ return -1;
}
- parse_events_error__exit(&errinfo);
- return err ? -1 : 0;
+ return metricgroup__parse_groups(evsel_list, "transaction",
+ stat_config.metric_no_group,
+ stat_config.metric_no_merge,
+ stat_config.metric_no_threshold,
+ stat_config.user_requested_cpu_list,
+ stat_config.system_wide,
+ &stat_config.metric_events);
}
if (smi_cost) {
- struct parse_events_error errinfo;
int smi;
if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) {
- fprintf(stderr, "freeze_on_smi is not supported.\n");
+ pr_err("freeze_on_smi is not supported.");
return -1;
}
smi_reset = true;
}
- if (!pmu_have_event("msr", "aperf") ||
- !pmu_have_event("msr", "smi")) {
- fprintf(stderr, "To measure SMI cost, it needs "
- "msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
+ if (!metricgroup__has_metric("smi")) {
+ pr_err("Missing smi metrics");
return -1;
}
+
if (!force_metric_only)
stat_config.metric_only = true;
- parse_events_error__init(&errinfo);
- err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
- if (err) {
- parse_events_error__print(&errinfo, smi_cost_attrs);
- fprintf(stderr, "Cannot set up SMI cost events\n");
- }
- parse_events_error__exit(&errinfo);
- return err ? -1 : 0;
+ return metricgroup__parse_groups(evsel_list, "smi",
+ stat_config.metric_no_group,
+ stat_config.metric_no_merge,
+ stat_config.metric_no_threshold,
+ stat_config.user_requested_cpu_list,
+ stat_config.system_wide,
+ &stat_config.metric_events);
}
if (topdown_run) {
- const char **metric_attrs = topdown_metric_attrs;
- unsigned int max_level = 1;
- char *str = NULL;
- bool warn = false;
- const char *pmu_name = arch_get_topdown_pmu_name(evsel_list, true);
+ unsigned int max_level = metricgroups__topdown_max_level();
+ char str[] = "TopdownL1";
if (!force_metric_only)
stat_config.metric_only = true;
- if (pmu_have_event(pmu_name, topdown_metric_L2_attrs[5])) {
- metric_attrs = topdown_metric_L2_attrs;
- max_level = 2;
+ if (!max_level) {
+ pr_err("Topdown requested but the topdown metric groups aren't present.\n"
+ "(See perf list the metric groups have names like TopdownL1)");
+ return -1;
}
-
if (stat_config.topdown_level > max_level) {
pr_err("Invalid top-down metrics level. The max level is %u.\n", max_level);
return -1;
} else if (!stat_config.topdown_level)
- stat_config.topdown_level = max_level;
-
- if (topdown_filter_events(metric_attrs, &str, 1, pmu_name) < 0) {
- pr_err("Out of memory\n");
- return -1;
- }
-
- if (metric_attrs[0] && str) {
- if (!stat_config.interval && !stat_config.metric_only) {
- fprintf(stat_config.output,
- "Topdown accuracy may decrease when measuring long periods.\n"
- "Please print the result regularly, e.g. -I1000\n");
- }
- goto setup_metrics;
- }
-
- zfree(&str);
-
- if (stat_config.aggr_mode != AGGR_GLOBAL &&
- stat_config.aggr_mode != AGGR_CORE) {
- pr_err("top down event configuration requires --per-core mode\n");
- return -1;
- }
- stat_config.aggr_mode = AGGR_CORE;
- if (nr_cgroups || !target__has_cpu(&target)) {
- pr_err("top down event configuration requires system-wide mode (-a)\n");
- return -1;
- }
+ stat_config.topdown_level = 1;
- if (topdown_filter_events(topdown_attrs, &str,
- arch_topdown_check_group(&warn),
- pmu_name) < 0) {
- pr_err("Out of memory\n");
- return -1;
+ if (!stat_config.interval && !stat_config.metric_only) {
+ fprintf(stat_config.output,
+ "Topdown accuracy may decrease when measuring long periods.\n"
+ "Please print the result regularly, e.g. -I1000\n");
}
-
- if (topdown_attrs[0] && str) {
- struct parse_events_error errinfo;
- if (warn)
- arch_topdown_group_warn();
-setup_metrics:
- parse_events_error__init(&errinfo);
- err = parse_events(evsel_list, str, &errinfo);
- if (err) {
- fprintf(stderr,
- "Cannot set up top down events %s: %d\n",
- str, err);
- parse_events_error__print(&errinfo, str);
- parse_events_error__exit(&errinfo);
- free(str);
- return -1;
- }
- parse_events_error__exit(&errinfo);
- } else {
- fprintf(stderr, "System does not support topdown\n");
+ str[8] = stat_config.topdown_level + '0';
+ if (metricgroup__parse_groups(evsel_list, str,
+ /*metric_no_group=*/false,
+ /*metric_no_merge=*/false,
+ /*metric_no_threshold=*/true,
+ stat_config.user_requested_cpu_list,
+ stat_config.system_wide,
+ &stat_config.metric_events) < 0)
return -1;
- }
- free(str);
}
if (!stat_config.topdown_level)
- stat_config.topdown_level = TOPDOWN_MAX_LEVEL;
+ stat_config.topdown_level = 1;
if (!evsel_list->core.nr_entries) {
+ /* No events so add defaults. */
if (target__has_cpu(&target))
default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK;
}
if (evlist__add_default_attrs(evsel_list, default_attrs1) < 0)
return -1;
+ /*
+ * Add TopdownL1 metrics if they exist. To minimize
+ * multiplexing, don't request threshold computation.
+ */
+ if (metricgroup__has_metric("TopdownL1") &&
+ metricgroup__parse_groups(evsel_list, "TopdownL1",
+ /*metric_no_group=*/false,
+ /*metric_no_merge=*/false,
+ /*metric_no_threshold=*/true,
+ stat_config.user_requested_cpu_list,
+ stat_config.system_wide,
+ &stat_config.metric_events) < 0)
+ return -1;
/* Platform specific attrs */
if (evlist__add_default_attrs(evsel_list, default_null_attrs) < 0)
return -1;
input_name = "perf.data";
}
- perf_stat__init_shadow_stats();
-
perf_stat.data.path = input_name;
perf_stat.data.mode = PERF_DATA_MODE_READ;
metricgroup__parse_groups(evsel_list, metrics,
stat_config.metric_no_group,
stat_config.metric_no_merge,
+ stat_config.metric_no_threshold,
stat_config.user_requested_cpu_list,
stat_config.system_wide,
&stat_config.metric_events);
zfree(&metrics);
}
- perf_stat__init_shadow_stats();
if (add_default_attributes())
goto out;
return pct;
}
-bool __perf_stat_evsel__is(struct evsel *evsel, enum perf_stat_evsel_id id)
-{
- struct perf_stat_evsel *ps = evsel->stats;
-
- return ps->id == id;
-}
-
-#define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
-static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
- ID(NONE, x),
- ID(CYCLES_IN_TX, cpu/cycles-t/),
- ID(TRANSACTION_START, cpu/tx-start/),
- ID(ELISION_START, cpu/el-start/),
- ID(CYCLES_IN_TX_CP, cpu/cycles-ct/),
- ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots),
- ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued),
- ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired),
- ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles),
- ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles),
- ID(TOPDOWN_RETIRING, topdown-retiring),
- ID(TOPDOWN_BAD_SPEC, topdown-bad-spec),
- ID(TOPDOWN_FE_BOUND, topdown-fe-bound),
- ID(TOPDOWN_BE_BOUND, topdown-be-bound),
- ID(TOPDOWN_HEAVY_OPS, topdown-heavy-ops),
- ID(TOPDOWN_BR_MISPREDICT, topdown-br-mispredict),
- ID(TOPDOWN_FETCH_LAT, topdown-fetch-lat),
- ID(TOPDOWN_MEM_BOUND, topdown-mem-bound),
- ID(SMI_NUM, msr/smi/),
- ID(APERF, msr/aperf/),
-};
-#undef ID
-
-static void perf_stat_evsel_id_init(struct evsel *evsel)
-{
- struct perf_stat_evsel *ps = evsel->stats;
- int i;
-
- /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
-
- for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
- if (!strcmp(evsel__name(evsel), id_str[i]) ||
- (strstr(evsel__name(evsel), id_str[i]) && evsel->pmu_name
- && strstr(evsel__name(evsel), evsel->pmu_name))) {
- ps->id = i;
- break;
- }
- }
-}
-
static void evsel__reset_aggr_stats(struct evsel *evsel)
{
struct perf_stat_evsel *ps = evsel->stats;
return -ENOMEM;
}
- perf_stat_evsel_id_init(evsel);
evsel__reset_stat_priv(evsel);
return 0;
}
evsel__process_percore(evsel);
}
-static void evsel__update_shadow_stats(struct evsel *evsel)
-{
- struct perf_stat_evsel *ps = evsel->stats;
- int i;
-
- if (ps->aggr == NULL)
- return;
-
- for (i = 0; i < ps->nr_aggr; i++) {
- struct perf_counts_values *aggr_counts = &ps->aggr[i].counts;
-
- perf_stat__update_shadow_stats(evsel, aggr_counts->val, i, &rt_stat);
- }
-}
-
-void perf_stat_process_shadow_stats(struct perf_stat_config *config __maybe_unused,
- struct evlist *evlist)
-{
- struct evsel *evsel;
-
- evlist__for_each_entry(evlist, evsel)
- evsel__update_shadow_stats(evsel);
-}
-
int perf_event__process_stat_event(struct perf_session *session,
union perf_event *event)
{
if (evsel__is_group_leader(evsel)) {
attr->disabled = 1;
- /*
- * In case of initial_delay we enable tracee
- * events manually.
- */
- if (target__none(target) && !config->initial_delay)
+ if (target__enable_on_exec(target))
attr->enable_on_exec = 1;
}
u64 max, min;
};
-enum perf_stat_evsel_id {
- PERF_STAT_EVSEL_ID__NONE = 0,
- PERF_STAT_EVSEL_ID__CYCLES_IN_TX,
- PERF_STAT_EVSEL_ID__TRANSACTION_START,
- PERF_STAT_EVSEL_ID__ELISION_START,
- PERF_STAT_EVSEL_ID__CYCLES_IN_TX_CP,
- PERF_STAT_EVSEL_ID__TOPDOWN_TOTAL_SLOTS,
- PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_ISSUED,
- PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED,
- PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES,
- PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES,
- PERF_STAT_EVSEL_ID__TOPDOWN_RETIRING,
- PERF_STAT_EVSEL_ID__TOPDOWN_BAD_SPEC,
- PERF_STAT_EVSEL_ID__TOPDOWN_FE_BOUND,
- PERF_STAT_EVSEL_ID__TOPDOWN_BE_BOUND,
- PERF_STAT_EVSEL_ID__TOPDOWN_HEAVY_OPS,
- PERF_STAT_EVSEL_ID__TOPDOWN_BR_MISPREDICT,
- PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_LAT,
- PERF_STAT_EVSEL_ID__TOPDOWN_MEM_BOUND,
- PERF_STAT_EVSEL_ID__SMI_NUM,
- PERF_STAT_EVSEL_ID__APERF,
- PERF_STAT_EVSEL_ID__MAX,
-};
-
/* hold aggregated event info */
struct perf_stat_aggr {
/* aggregated values */
struct perf_stat_evsel {
/* used for repeated runs */
struct stats res_stats;
- /* evsel id for quick check */
- enum perf_stat_evsel_id id;
/* number of allocated 'aggr' */
int nr_aggr;
/* aggregated event values */
AGGR_MAX
};
-enum {
- CTX_BIT_USER = 1 << 0,
- CTX_BIT_KERNEL = 1 << 1,
- CTX_BIT_HV = 1 << 2,
- CTX_BIT_HOST = 1 << 3,
- CTX_BIT_IDLE = 1 << 4,
- CTX_BIT_MAX = 1 << 5,
-};
-
-#define NUM_CTX CTX_BIT_MAX
-
-enum stat_type {
- STAT_NONE = 0,
- STAT_NSECS,
- STAT_CYCLES,
- STAT_STALLED_CYCLES_FRONT,
- STAT_STALLED_CYCLES_BACK,
- STAT_BRANCHES,
- STAT_CACHEREFS,
- STAT_L1_DCACHE,
- STAT_L1_ICACHE,
- STAT_LL_CACHE,
- STAT_ITLB_CACHE,
- STAT_DTLB_CACHE,
- STAT_CYCLES_IN_TX,
- STAT_TRANSACTION,
- STAT_ELISION,
- STAT_TOPDOWN_TOTAL_SLOTS,
- STAT_TOPDOWN_SLOTS_ISSUED,
- STAT_TOPDOWN_SLOTS_RETIRED,
- STAT_TOPDOWN_FETCH_BUBBLES,
- STAT_TOPDOWN_RECOVERY_BUBBLES,
- STAT_TOPDOWN_RETIRING,
- STAT_TOPDOWN_BAD_SPEC,
- STAT_TOPDOWN_FE_BOUND,
- STAT_TOPDOWN_BE_BOUND,
- STAT_TOPDOWN_HEAVY_OPS,
- STAT_TOPDOWN_BR_MISPREDICT,
- STAT_TOPDOWN_FETCH_LAT,
- STAT_TOPDOWN_MEM_BOUND,
- STAT_SMI_NUM,
- STAT_APERF,
- STAT_MAX
-};
-
-struct runtime_stat {
- struct rblist value_list;
-};
-
struct rusage_stats {
struct stats ru_utime_usec_stat;
struct stats ru_stime_usec_stat;
bool no_csv_summary;
bool metric_no_group;
bool metric_no_merge;
+ bool metric_no_threshold;
bool stop_read_counter;
bool iostat_run;
char *user_requested_cpu_list;
FILE *output;
unsigned int interval;
unsigned int timeout;
- int initial_delay;
unsigned int unit_width;
unsigned int metric_only_len;
int times;
struct evsel;
struct evlist;
-bool __perf_stat_evsel__is(struct evsel *evsel, enum perf_stat_evsel_id id);
-
-#define perf_stat_evsel__is(evsel, id) \
- __perf_stat_evsel__is(evsel, PERF_STAT_EVSEL_ID__ ## id)
-
-extern struct runtime_stat rt_stat;
extern struct stats walltime_nsecs_stats;
extern struct rusage_stats ru_stats;
const char *fmt, double val);
typedef void (*new_line_t)(struct perf_stat_config *config, void *ctx);
-void runtime_stat__init(struct runtime_stat *st);
-void runtime_stat__exit(struct runtime_stat *st);
-void perf_stat__init_shadow_stats(void);
void perf_stat__reset_shadow_stats(void);
-void perf_stat__reset_shadow_per_stat(struct runtime_stat *st);
-void perf_stat__update_shadow_stats(struct evsel *counter, u64 count,
- int map_idx, struct runtime_stat *st);
struct perf_stat_output_ctx {
void *ctx;
print_metric_t print_metric;
void perf_stat__print_shadow_stats(struct perf_stat_config *config,
struct evsel *evsel,
- double avg, int map_idx,
+ double avg, int aggr_idx,
struct perf_stat_output_ctx *out,
- struct rblist *metric_events,
- struct runtime_stat *st);
+ struct rblist *metric_events);
int evlist__alloc_stats(struct perf_stat_config *config,
struct evlist *evlist, bool alloc_raw);
struct evsel *counter);
void perf_stat_merge_counters(struct perf_stat_config *config, struct evlist *evlist);
void perf_stat_process_percore(struct perf_stat_config *config, struct evlist *evlist);
-void perf_stat_process_shadow_stats(struct perf_stat_config *config, struct evlist *evlist);
struct perf_tool;
union perf_event;
struct target *_target, struct timespec *ts, int argc, const char **argv);
struct metric_expr;
-double test_generic_metric(struct metric_expr *mexp, int map_idx, struct runtime_stat *st);
+double test_generic_metric(struct metric_expr *mexp, int aggr_idx);
#endif