mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 03:11:11 -04:00
perf evlist: Improve default event for s390
Frame pointer callchains are not supported on s390 and dwarf callchains are only supported on software events. Switch the default event from the hardware 'cycles' event to the software 'cpu-clock' or 'task-clock' on s390 if callchains are enabled. Move some of the target initialization earlier in builtin-top and builtin-record, so it is ready for use by evlist__new_default. If frame pointer callchains are requested on s390 show a warning. Modify the '-g' option of `perf top` and `perf record` to default to dwarf callchains on s390. Signed-off-by: Ian Rogers <irogers@google.com> Tested-by: Thomas Richter <tmricht@linux.ibm.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
@@ -55,6 +55,7 @@
|
||||
#include "asm/bug.h"
|
||||
#include "perf.h"
|
||||
#include "cputopo.h"
|
||||
#include "dwarf-regs.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
@@ -2995,7 +2996,9 @@ static int record_callchain_opt(const struct option *opt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return record_opts__parse_callchain(opt->value, &callchain_param, "fp", unset);
|
||||
return record_opts__parse_callchain(opt->value, &callchain_param,
|
||||
EM_HOST != EM_S390 ? "fp" : "dwarf",
|
||||
unset);
|
||||
}
|
||||
|
||||
|
||||
@@ -4095,8 +4098,11 @@ int cmd_record(int argc, const char **argv)
|
||||
|
||||
perf_debuginfod_setup(&record.debuginfod);
|
||||
|
||||
/* Make system wide (-a) the default target. */
|
||||
if (!argc && target__none(&rec->opts.target))
|
||||
/*
|
||||
* Use system wide (-a) for the default target (ie. when no
|
||||
* workload). User ID filtering also implies system-wide.
|
||||
*/
|
||||
if ((!argc && target__none(&rec->opts.target)) || rec->uid_str)
|
||||
rec->opts.target.system_wide = true;
|
||||
|
||||
if (nr_cgroups && !rec->opts.target.system_wide) {
|
||||
@@ -4274,7 +4280,8 @@ int cmd_record(int argc, const char **argv)
|
||||
record.opts.tail_synthesize = true;
|
||||
|
||||
if (rec->evlist->core.nr_entries == 0) {
|
||||
struct evlist *def_evlist = evlist__new_default();
|
||||
struct evlist *def_evlist = evlist__new_default(&rec->opts.target,
|
||||
callchain_param.enabled);
|
||||
|
||||
if (!def_evlist)
|
||||
goto out;
|
||||
@@ -4303,9 +4310,6 @@ int cmd_record(int argc, const char **argv)
|
||||
err = parse_uid_filter(rec->evlist, uid);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* User ID filtering implies system wide. */
|
||||
rec->opts.target.system_wide = true;
|
||||
}
|
||||
|
||||
/* Enable ignoring missing threads when -p option is defined. */
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "util/debug.h"
|
||||
#include "util/ordered-events.h"
|
||||
#include "util/pfm.h"
|
||||
#include "dwarf-regs.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
@@ -1420,7 +1421,7 @@ callchain_opt(const struct option *opt, const char *arg __maybe_unused, int unse
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parse_callchain_opt(opt, "fp", unset);
|
||||
return parse_callchain_opt(opt, EM_HOST != EM_S390 ? "fp" : "dwarf", unset);
|
||||
}
|
||||
|
||||
|
||||
@@ -1705,8 +1706,17 @@ int cmd_top(int argc, const char **argv)
|
||||
if (annotate_check_args() < 0)
|
||||
goto out_delete_evlist;
|
||||
|
||||
status = target__validate(target);
|
||||
if (status) {
|
||||
target__strerror(target, status, errbuf, BUFSIZ);
|
||||
ui__warning("%s\n", errbuf);
|
||||
}
|
||||
|
||||
if (target__none(target))
|
||||
target->system_wide = true;
|
||||
|
||||
if (!top.evlist->core.nr_entries) {
|
||||
struct evlist *def_evlist = evlist__new_default();
|
||||
struct evlist *def_evlist = evlist__new_default(target, callchain_param.enabled);
|
||||
|
||||
if (!def_evlist)
|
||||
goto out_delete_evlist;
|
||||
@@ -1799,12 +1809,6 @@ int cmd_top(int argc, const char **argv)
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
status = target__validate(target);
|
||||
if (status) {
|
||||
target__strerror(target, status, errbuf, BUFSIZ);
|
||||
ui__warning("%s\n", errbuf);
|
||||
}
|
||||
|
||||
if (top.uid_str) {
|
||||
uid_t uid = parse_uid(top.uid_str);
|
||||
|
||||
@@ -1818,9 +1822,6 @@ int cmd_top(int argc, const char **argv)
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
if (target__none(target))
|
||||
target->system_wide = true;
|
||||
|
||||
if (evlist__create_maps(top.evlist, target) < 0) {
|
||||
ui__error("Couldn't create thread/CPU maps: %s\n",
|
||||
errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "header.h"
|
||||
#include "machine.h"
|
||||
#include "util/synthetic-events.h"
|
||||
#include "target.h"
|
||||
#include "tool.h"
|
||||
#include "tests.h"
|
||||
#include "debug.h"
|
||||
@@ -81,7 +82,8 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
|
||||
{
|
||||
struct evsel *evsel;
|
||||
struct event_name tmp;
|
||||
struct evlist *evlist = evlist__new_default();
|
||||
struct target target = {};
|
||||
struct evlist *evlist = evlist__new_default(&target, /*sample_callchains=*/false);
|
||||
|
||||
TEST_ASSERT_VAL("failed to get evlist", evlist);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "parse-events.h"
|
||||
#include "pmu-events/pmu-events.h"
|
||||
#include "pfm.h"
|
||||
#include "target.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -99,7 +100,8 @@ out: for (i = 0; i < nr_events; i++)
|
||||
static int expand_default_events(void)
|
||||
{
|
||||
int ret;
|
||||
struct evlist *evlist = evlist__new_default();
|
||||
struct target target = {};
|
||||
struct evlist *evlist = evlist__new_default(&target, /*sample_callchains=*/false);
|
||||
|
||||
TEST_ASSERT_VAL("failed to get evlist", evlist);
|
||||
|
||||
|
||||
@@ -84,8 +84,11 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
|
||||
CPU_ZERO_S(cpu_mask_size, cpu_mask);
|
||||
|
||||
perf_sample__init(&sample, /*all=*/false);
|
||||
if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */
|
||||
evlist = evlist__new_default();
|
||||
if (evlist == NULL) { /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */
|
||||
struct target target = {};
|
||||
|
||||
evlist = evlist__new_default(&target, /*sample_callchains=*/false);
|
||||
}
|
||||
|
||||
if (evlist == NULL) {
|
||||
pr_debug("Not enough memory to create evlist\n");
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "evlist.h"
|
||||
#include "debug.h"
|
||||
#include "pmus.h"
|
||||
#include "target.h"
|
||||
#include <linux/err.h>
|
||||
|
||||
#define TEMPL "/tmp/perf-test-XXXXXX"
|
||||
@@ -37,11 +38,12 @@ static int session_write_header(char *path)
|
||||
.path = path,
|
||||
.mode = PERF_DATA_MODE_WRITE,
|
||||
};
|
||||
struct target target = {};
|
||||
|
||||
session = perf_session__new(&data, NULL);
|
||||
TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
|
||||
|
||||
session->evlist = evlist__new_default();
|
||||
session->evlist = evlist__new_default(&target, /*sample_callchains=*/false);
|
||||
TEST_ASSERT_VAL("can't get evlist", session->evlist);
|
||||
session->evlist->session = session;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "util/mmap.h"
|
||||
#include "thread_map.h"
|
||||
#include "target.h"
|
||||
#include "dwarf-regs.h"
|
||||
#include "evlist.h"
|
||||
#include "evsel.h"
|
||||
#include "record.h"
|
||||
@@ -98,38 +99,47 @@ struct evlist *evlist__new(void)
|
||||
return evlist;
|
||||
}
|
||||
|
||||
struct evlist *evlist__new_default(void)
|
||||
struct evlist *evlist__new_default(const struct target *target, bool sample_callchains)
|
||||
{
|
||||
struct evlist *evlist = evlist__new();
|
||||
bool can_profile_kernel;
|
||||
struct perf_pmu *pmu = NULL;
|
||||
struct evsel *evsel;
|
||||
char buf[256];
|
||||
int err;
|
||||
|
||||
if (!evlist)
|
||||
return NULL;
|
||||
|
||||
can_profile_kernel = perf_event_paranoid_check(1);
|
||||
|
||||
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
|
||||
char buf[256];
|
||||
int err;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/cycles/%s", pmu->name,
|
||||
if (EM_HOST == EM_S390 && sample_callchains) {
|
||||
snprintf(buf, sizeof(buf), "software/%s/%s",
|
||||
target__has_cpu(target) ? "cpu-clock" : "task-clock",
|
||||
can_profile_kernel ? "P" : "Pu");
|
||||
err = parse_event(evlist, buf);
|
||||
if (err) {
|
||||
evlist__delete(evlist);
|
||||
return NULL;
|
||||
if (err)
|
||||
goto out_err;
|
||||
} else {
|
||||
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
|
||||
snprintf(buf, sizeof(buf), "%s/cycles/%s", pmu->name,
|
||||
can_profile_kernel ? "P" : "Pu");
|
||||
err = parse_event(evlist, buf);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is only 1 event a sample identifier isn't necessary. */
|
||||
if (evlist->core.nr_entries > 1) {
|
||||
struct evsel *evsel;
|
||||
|
||||
evlist__for_each_entry(evlist, evsel)
|
||||
evsel__set_sample_id(evsel, /*can_sample_identifier=*/false);
|
||||
}
|
||||
|
||||
return evlist;
|
||||
out_err:
|
||||
evlist__delete(evlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct evlist *evlist__new_dummy(void)
|
||||
|
||||
@@ -104,7 +104,7 @@ struct evsel_str_handler {
|
||||
};
|
||||
|
||||
struct evlist *evlist__new(void);
|
||||
struct evlist *evlist__new_default(void);
|
||||
struct evlist *evlist__new_default(const struct target *target, bool sample_callchains);
|
||||
struct evlist *evlist__new_dummy(void);
|
||||
void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
|
||||
struct perf_thread_map *threads);
|
||||
|
||||
@@ -1021,6 +1021,11 @@ static void __evsel__config_callchain(struct evsel *evsel, const struct record_o
|
||||
bool function = evsel__is_function_event(evsel);
|
||||
struct perf_event_attr *attr = &evsel->core.attr;
|
||||
|
||||
if (EM_HOST == EM_S390 && param->record_mode == CALLCHAIN_FP) {
|
||||
pr_warning_once(
|
||||
"Framepointer unwinding lacks kernel support. Use '--call-graph dwarf'\n");
|
||||
}
|
||||
|
||||
evsel__set_sample_bit(evsel, CALLCHAIN);
|
||||
|
||||
attr->sample_max_stack = param->max_stack;
|
||||
|
||||
Reference in New Issue
Block a user