mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-02 14:34:13 -04:00
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/probe fixes and improvements from Arnaldo Carvalho de Melo:
User visible changes:
* Do not show +/- callchain expansion when there are no childs (top/report) (Namhyung Kim)
* Fix -z and add respective 'z' hotkey to zero samples before refresh
in 'perf top' (Namhyung Kim)
* Capability probing fixes, improving the detection of
kernel features for non-priviledged users (Adrian Hunter)
* Add beautifier for mremap flags param in 'trace' (Alex Snast)
* Fix --list and --del options to show events when just uprobes is
enabled (Masami Hiramatsu)
* perf script: Allow callchains if any event samples them
* Don't look for kernel idle symbols in all DSOs in 'perf top' (Arnaldo Carvalho de Melo)
* Add cpu_startup_entry to the list of kernel idle symbols (Arnaldo Carvalho de Melo)
* 'perf top' terminal output fixes (Jiri Olsa)
* Fix stdin handling for 'perf kvm stat live' (Jiri Olsa)
* Fix missing label symbols (Adrian Hunter)
* Don't demangle C++ parameters and such by default, only in
--verbose mode (Namhyung Kim)
* Set proper sort__mode for the branch option (Naohiro Aota)
* Check recorded kernel version when finding vmlinux (Namhyung Kim)
Infrastructure changes:
* More prep work for intel PT (Adrian Hunter)
* Fix possible memory leaks (Namhyung Kim)
* Fix a memory leak in vmlinux_path__init() (Namhyung Kim)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -36,7 +36,8 @@
|
||||
|
||||
struct perf_annotate {
|
||||
struct perf_tool tool;
|
||||
bool force, use_tui, use_stdio, use_gtk;
|
||||
struct perf_session *session;
|
||||
bool use_tui, use_stdio, use_gtk;
|
||||
bool full_paths;
|
||||
bool print_line;
|
||||
bool skip_missing;
|
||||
@@ -188,18 +189,9 @@ static void hists__find_annotations(struct hists *hists,
|
||||
static int __cmd_annotate(struct perf_annotate *ann)
|
||||
{
|
||||
int ret;
|
||||
struct perf_session *session;
|
||||
struct perf_session *session = ann->session;
|
||||
struct perf_evsel *pos;
|
||||
u64 total_nr_samples;
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = ann->force,
|
||||
};
|
||||
|
||||
session = perf_session__new(&file, false, &ann->tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
machines__set_symbol_filter(&session->machines, symbol__annotate_init);
|
||||
|
||||
@@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
ret = perf_session__cpu_bitmap(session, ann->cpu_list,
|
||||
ann->cpu_bitmap);
|
||||
if (ret)
|
||||
goto out_delete;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!objdump_path) {
|
||||
ret = perf_session_env__lookup_objdump(&session->header.env);
|
||||
if (ret)
|
||||
goto out_delete;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = perf_session__process_events(session, &ann->tool);
|
||||
if (ret)
|
||||
goto out_delete;
|
||||
goto out;
|
||||
|
||||
if (dump_trace) {
|
||||
perf_session__fprintf_nr_events(session, stdout);
|
||||
goto out_delete;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
@@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
}
|
||||
|
||||
if (total_nr_samples == 0) {
|
||||
ui__error("The %s file has no samples!\n", file.path);
|
||||
goto out_delete;
|
||||
ui__error("The %s file has no samples!\n", session->file->path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (use_browser == 2) {
|
||||
@@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
"perf_gtk__show_annotations");
|
||||
if (show_annotations == NULL) {
|
||||
ui__error("GTK browser not found!\n");
|
||||
goto out_delete;
|
||||
goto out;
|
||||
}
|
||||
show_annotations();
|
||||
}
|
||||
|
||||
out_delete:
|
||||
/*
|
||||
* Speed up the exit process, for large files this can
|
||||
* take quite a while.
|
||||
*
|
||||
* XXX Enable this when using valgrind or if we ever
|
||||
* librarize this command.
|
||||
*
|
||||
* Also experiment with obstacks to see how much speed
|
||||
* up we'll get here.
|
||||
*
|
||||
* perf_session__delete(session);
|
||||
*/
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -301,6 +281,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
.ordering_requires_timestamps = true,
|
||||
},
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
const struct option options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file",
|
||||
"input file name"),
|
||||
@@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"only consider symbols in these dsos"),
|
||||
OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
|
||||
"symbol to annotate"),
|
||||
OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
|
||||
OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show symbol address, etc)"),
|
||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
||||
@@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"Show event group information together"),
|
||||
OPT_END()
|
||||
};
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, options, annotate_usage, 0);
|
||||
|
||||
@@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
|
||||
setup_browser(true);
|
||||
|
||||
annotate.session = perf_session__new(&file, false, &annotate.tool);
|
||||
if (annotate.session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
symbol_conf.priv_size = sizeof(struct annotation);
|
||||
symbol_conf.try_vmlinux_path = true;
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
ret = symbol__init(&annotate.session->header.env);
|
||||
if (ret < 0)
|
||||
goto out_delete;
|
||||
|
||||
if (setup_sorting() < 0)
|
||||
usage_with_options(annotate_usage, options);
|
||||
@@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
annotate.sym_hist_filter = argv[0];
|
||||
}
|
||||
|
||||
return __cmd_annotate(&annotate);
|
||||
ret = __cmd_annotate(&annotate);
|
||||
|
||||
out_delete:
|
||||
/*
|
||||
* Speed up the exit process, for large files this can
|
||||
* take quite a while.
|
||||
*
|
||||
* XXX Enable this when using valgrind or if we ever
|
||||
* librarize this command.
|
||||
*
|
||||
* Also experiment with obstacks to see how much speed
|
||||
* up we'll get here.
|
||||
*
|
||||
* perf_session__delete(session);
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
|
||||
static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp)
|
||||
{
|
||||
struct perf_data_file file = {
|
||||
.path = filename,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
};
|
||||
struct perf_session *session = perf_session__new(&file, false, NULL);
|
||||
if (session == NULL)
|
||||
return -1;
|
||||
|
||||
perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
|
||||
perf_session__delete(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -303,6 +292,11 @@ int cmd_buildid_cache(int argc, const char **argv,
|
||||
*update_name_list_str = NULL,
|
||||
*kcore_filename;
|
||||
|
||||
struct perf_data_file file = {
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
struct perf_session *session = NULL;
|
||||
|
||||
const struct option buildid_cache_options[] = {
|
||||
OPT_STRING('a', "add", &add_name_list_str,
|
||||
"file list", "file(s) to add"),
|
||||
@@ -326,8 +320,17 @@ int cmd_buildid_cache(int argc, const char **argv,
|
||||
argc = parse_options(argc, argv, buildid_cache_options,
|
||||
buildid_cache_usage, 0);
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
if (missing_filename) {
|
||||
file.path = missing_filename;
|
||||
file.force = force;
|
||||
|
||||
session = perf_session__new(&file, false, NULL);
|
||||
if (session == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (symbol__init(session ? &session->header.env : NULL) < 0)
|
||||
goto out;
|
||||
|
||||
setup_pager();
|
||||
|
||||
@@ -370,7 +373,7 @@ int cmd_buildid_cache(int argc, const char **argv,
|
||||
}
|
||||
|
||||
if (missing_filename)
|
||||
ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
|
||||
ret = build_id_cache__fprintf_missing(session, stdout);
|
||||
|
||||
if (update_name_list_str) {
|
||||
list = strlist__new(true, update_name_list_str);
|
||||
@@ -394,5 +397,9 @@ int cmd_buildid_cache(int argc, const char **argv,
|
||||
build_id_cache__add_kcore(kcore_filename, debugdir, force))
|
||||
pr_warning("Couldn't add %s\n", kcore_filename);
|
||||
|
||||
out:
|
||||
if (session)
|
||||
perf_session__delete(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
|
||||
argc = parse_options(argc, argv, options, diff_usage, 0);
|
||||
|
||||
if (symbol__init() < 0)
|
||||
if (symbol__init(NULL) < 0)
|
||||
return -1;
|
||||
|
||||
if (data_init(argc, argv) < 0)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
struct perf_inject {
|
||||
struct perf_tool tool;
|
||||
struct perf_session *session;
|
||||
bool build_ids;
|
||||
bool sched_stat;
|
||||
const char *input_name;
|
||||
@@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
|
||||
|
||||
static int __cmd_inject(struct perf_inject *inject)
|
||||
{
|
||||
struct perf_session *session;
|
||||
int ret = -EINVAL;
|
||||
struct perf_data_file file = {
|
||||
.path = inject->input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
struct perf_session *session = inject->session;
|
||||
struct perf_data_file *file_out = &inject->output;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
@@ -357,10 +354,6 @@ static int __cmd_inject(struct perf_inject *inject)
|
||||
inject->tool.tracing_data = perf_event__repipe_tracing_data;
|
||||
}
|
||||
|
||||
session = perf_session__new(&file, true, &inject->tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (inject->build_ids) {
|
||||
inject->tool.sample = perf_event__inject_buildid;
|
||||
} else if (inject->sched_stat) {
|
||||
@@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject)
|
||||
perf_session__write_header(session, session->evlist, file_out->fd, true);
|
||||
}
|
||||
|
||||
perf_session__delete(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
.mode = PERF_DATA_MODE_WRITE,
|
||||
},
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
int ret;
|
||||
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
|
||||
"Inject build-ids into the output stream"),
|
||||
@@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (symbol__init() < 0)
|
||||
file.path = inject.input_name;
|
||||
inject.session = perf_session__new(&file, true, &inject.tool);
|
||||
if (inject.session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (symbol__init(&inject.session->header.env) < 0)
|
||||
return -1;
|
||||
|
||||
return __cmd_inject(&inject);
|
||||
ret = __cmd_inject(&inject);
|
||||
|
||||
perf_session__delete(inject.session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -405,10 +405,9 @@ static void sort_result(void)
|
||||
__sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
|
||||
}
|
||||
|
||||
static int __cmd_kmem(void)
|
||||
static int __cmd_kmem(struct perf_session *session)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct perf_session *session;
|
||||
const struct perf_evsel_str_handler kmem_tracepoints[] = {
|
||||
{ "kmem:kmalloc", perf_evsel__process_alloc_event, },
|
||||
{ "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, },
|
||||
@@ -417,31 +416,22 @@ static int __cmd_kmem(void)
|
||||
{ "kmem:kfree", perf_evsel__process_free_event, },
|
||||
{ "kmem:kmem_cache_free", perf_evsel__process_free_event, },
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
session = perf_session__new(&file, false, &perf_kmem);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!perf_session__has_traces(session, "kmem record"))
|
||||
goto out_delete;
|
||||
goto out;
|
||||
|
||||
if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
|
||||
pr_err("Initializing perf session tracepoint handlers failed\n");
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
setup_pager();
|
||||
err = perf_session__process_events(session, &perf_kmem);
|
||||
if (err != 0)
|
||||
goto out_delete;
|
||||
goto out;
|
||||
sort_result();
|
||||
print_result(session);
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -688,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
struct perf_session *session;
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
int ret = -1;
|
||||
|
||||
argc = parse_options_subcommand(argc, argv, kmem_options,
|
||||
kmem_subcommands, kmem_usage, 0);
|
||||
|
||||
if (!argc)
|
||||
usage_with_options(kmem_usage, kmem_options);
|
||||
|
||||
symbol__init();
|
||||
|
||||
if (!strncmp(argv[0], "rec", 3)) {
|
||||
symbol__init(NULL);
|
||||
return __cmd_record(argc, argv);
|
||||
} else if (!strcmp(argv[0], "stat")) {
|
||||
}
|
||||
|
||||
session = perf_session__new(&file, false, &perf_kmem);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
symbol__init(&session->header.env);
|
||||
|
||||
if (!strcmp(argv[0], "stat")) {
|
||||
if (cpu__setup_cpunode_map())
|
||||
return -1;
|
||||
goto out_delete;
|
||||
|
||||
if (list_empty(&caller_sort))
|
||||
setup_sorting(&caller_sort, default_sort_order);
|
||||
if (list_empty(&alloc_sort))
|
||||
setup_sorting(&alloc_sort, default_sort_order);
|
||||
|
||||
return __cmd_kmem();
|
||||
ret = __cmd_kmem(session);
|
||||
} else
|
||||
usage_with_options(kmem_usage, kmem_options);
|
||||
|
||||
return 0;
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -885,15 +885,11 @@ static int fd_set_nonblock(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
|
||||
static int perf_kvm__handle_stdin(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
tcsetattr(0, TCSANOW, tc_now);
|
||||
c = getc(stdin);
|
||||
tcsetattr(0, TCSAFLUSH, tc_save);
|
||||
|
||||
if (c == 'q')
|
||||
return 1;
|
||||
|
||||
@@ -904,7 +900,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
struct pollfd *pollfds = NULL;
|
||||
int nr_fds, nr_stdin, ret, err = -EINVAL;
|
||||
struct termios tc, save;
|
||||
struct termios save;
|
||||
|
||||
/* live flag must be set first */
|
||||
kvm->live = true;
|
||||
@@ -919,14 +915,9 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
goto out;
|
||||
}
|
||||
|
||||
set_term_quiet_input(&save);
|
||||
init_kvm_event_record(kvm);
|
||||
|
||||
tcgetattr(0, &save);
|
||||
tc = save;
|
||||
tc.c_lflag &= ~(ICANON | ECHO);
|
||||
tc.c_cc[VMIN] = 0;
|
||||
tc.c_cc[VTIME] = 0;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
@@ -972,7 +963,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
goto out;
|
||||
|
||||
if (pollfds[nr_stdin].revents & POLLIN)
|
||||
done = perf_kvm__handle_stdin(&tc, &save);
|
||||
done = perf_kvm__handle_stdin();
|
||||
|
||||
if (!rc && !done)
|
||||
err = poll(pollfds, nr_fds, 100);
|
||||
@@ -989,6 +980,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
if (kvm->timerfd >= 0)
|
||||
close(kvm->timerfd);
|
||||
|
||||
tcsetattr(0, TCSAFLUSH, &save);
|
||||
free(pollfds);
|
||||
return err;
|
||||
}
|
||||
@@ -1072,6 +1064,8 @@ static int read_events(struct perf_kvm_stat *kvm)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
symbol__init(&kvm->session->header.env);
|
||||
|
||||
if (!perf_session__has_traces(kvm->session, "kvm record"))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1201,8 +1195,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
||||
NULL
|
||||
};
|
||||
|
||||
symbol__init();
|
||||
|
||||
if (argc) {
|
||||
argc = parse_options(argc, argv,
|
||||
kvm_events_report_options,
|
||||
@@ -1322,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
||||
kvm->opts.target.uid_str = NULL;
|
||||
kvm->opts.target.uid = UINT_MAX;
|
||||
|
||||
symbol__init();
|
||||
symbol__init(NULL);
|
||||
disable_buildid_cache();
|
||||
|
||||
use_browser = 0;
|
||||
|
||||
@@ -865,6 +865,8 @@ static int __cmd_report(bool display_info)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
symbol__init(&session->header.env);
|
||||
|
||||
if (!perf_session__has_traces(session, "lock record"))
|
||||
goto out_delete;
|
||||
|
||||
@@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
unsigned int i;
|
||||
int rc = 0;
|
||||
|
||||
symbol__init();
|
||||
for (i = 0; i < LOCKHASH_SIZE; i++)
|
||||
INIT_LIST_HEAD(lockhash_table + i);
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem)
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (symbol__init() < 0)
|
||||
if (symbol__init(&session->header.env) < 0)
|
||||
return -1;
|
||||
|
||||
printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
|
||||
|
||||
@@ -908,7 +908,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
usage_with_options(record_usage, record_options);
|
||||
}
|
||||
|
||||
symbol__init();
|
||||
symbol__init(NULL);
|
||||
|
||||
if (symbol_conf.kptr_restrict)
|
||||
pr_warning(
|
||||
|
||||
@@ -730,7 +730,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
has_br_stack = perf_header__has_feat(&session->header,
|
||||
HEADER_BRANCH_STACK);
|
||||
|
||||
if (branch_mode == -1 && has_br_stack) {
|
||||
if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
|
||||
sort__mode = SORT_MODE__BRANCH;
|
||||
symbol_conf.cumulate_callchain = false;
|
||||
}
|
||||
@@ -798,7 +798,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol__init() < 0)
|
||||
if (symbol__init(&session->header.env) < 0)
|
||||
goto error;
|
||||
|
||||
if (argc) {
|
||||
|
||||
@@ -1462,6 +1462,8 @@ static int perf_sched__read_events(struct perf_sched *sched,
|
||||
return -1;
|
||||
}
|
||||
|
||||
symbol__init(&session->header.env);
|
||||
|
||||
if (perf_session__set_tracepoints_handlers(session, handlers))
|
||||
goto out_delete;
|
||||
|
||||
@@ -1747,7 +1749,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (!strcmp(argv[0], "script"))
|
||||
return cmd_script(argc, argv, prefix);
|
||||
|
||||
symbol__init();
|
||||
if (!strncmp(argv[0], "rec", 3)) {
|
||||
return __cmd_record(argc, argv);
|
||||
} else if (!strncmp(argv[0], "lat", 3)) {
|
||||
|
||||
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
||||
if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
|
||||
PERF_OUTPUT_IP))
|
||||
return -EINVAL;
|
||||
|
||||
if (!no_callchain &&
|
||||
!(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
|
||||
symbol_conf.use_callchain = false;
|
||||
}
|
||||
|
||||
if (PRINT_FIELD(ADDR) &&
|
||||
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
|
||||
set_print_ip_opts(&evsel->attr);
|
||||
}
|
||||
|
||||
if (!no_callchain) {
|
||||
bool use_callchain = false;
|
||||
|
||||
evlist__for_each(session->evlist, evsel) {
|
||||
if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
|
||||
use_callchain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!use_callchain)
|
||||
symbol_conf.use_callchain = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* set default for tracepoints to print symbols only
|
||||
* if callchains are present
|
||||
@@ -1471,12 +1480,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
bool show_full_info = false;
|
||||
bool header = false;
|
||||
bool header_only = false;
|
||||
bool script_started = false;
|
||||
char *rec_script_path = NULL;
|
||||
char *rep_script_path = NULL;
|
||||
struct perf_session *session;
|
||||
char *script_path = NULL;
|
||||
const char **__argv;
|
||||
int i, j, err;
|
||||
int i, j, err = 0;
|
||||
struct perf_script script = {
|
||||
.tool = {
|
||||
.sample = process_sample_event,
|
||||
@@ -1718,8 +1728,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
if (!script_name)
|
||||
setup_pager();
|
||||
|
||||
@@ -1730,14 +1738,18 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (header || header_only) {
|
||||
perf_session__fprintf_info(session, stdout, show_full_info);
|
||||
if (header_only)
|
||||
return 0;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (symbol__init(&session->header.env) < 0)
|
||||
goto out_delete;
|
||||
|
||||
script.session = session;
|
||||
|
||||
if (cpu_list) {
|
||||
if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
|
||||
return -1;
|
||||
err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
|
||||
if (err < 0)
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (!no_callchain)
|
||||
@@ -1752,53 +1764,60 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (output_set_by_user()) {
|
||||
fprintf(stderr,
|
||||
"custom fields not supported for generated scripts");
|
||||
return -1;
|
||||
err = -EINVAL;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
input = open(file.path, O_RDONLY); /* input_name */
|
||||
if (input < 0) {
|
||||
err = -errno;
|
||||
perror("failed to open file");
|
||||
return -1;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
err = fstat(input, &perf_stat);
|
||||
if (err < 0) {
|
||||
perror("failed to stat file");
|
||||
return -1;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (!perf_stat.st_size) {
|
||||
fprintf(stderr, "zero-sized file, nothing to do!\n");
|
||||
return 0;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
scripting_ops = script_spec__lookup(generate_script_lang);
|
||||
if (!scripting_ops) {
|
||||
fprintf(stderr, "invalid language specifier");
|
||||
return -1;
|
||||
err = -ENOENT;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
err = scripting_ops->generate_script(session->tevent.pevent,
|
||||
"perf-script");
|
||||
goto out;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (script_name) {
|
||||
err = scripting_ops->start_script(script_name, argc, argv);
|
||||
if (err)
|
||||
goto out;
|
||||
goto out_delete;
|
||||
pr_debug("perf script started with script %s\n\n", script_name);
|
||||
script_started = true;
|
||||
}
|
||||
|
||||
|
||||
err = perf_session__check_output_opt(session);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
goto out_delete;
|
||||
|
||||
err = __cmd_script(&script);
|
||||
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
cleanup_scripting();
|
||||
|
||||
if (script_started)
|
||||
cleanup_scripting();
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1607,6 +1607,8 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
symbol__init(&session->header.env);
|
||||
|
||||
(void)perf_header__process_sections(&session->header,
|
||||
perf_data_file__fd(session->file),
|
||||
tchart,
|
||||
@@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv,
|
||||
return -1;
|
||||
}
|
||||
|
||||
symbol__init();
|
||||
|
||||
if (argc && !strncmp(argv[0], "rec", 3)) {
|
||||
argc = parse_options(argc, argv, record_options, record_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
|
||||
return;
|
||||
}
|
||||
|
||||
if (top->zero) {
|
||||
hists__delete_entries(&top->sym_evsel->hists);
|
||||
} else {
|
||||
hists__decay_entries(&top->sym_evsel->hists,
|
||||
top->hide_user_symbols,
|
||||
top->hide_kernel_symbols);
|
||||
}
|
||||
|
||||
hists__collapse_resort(&top->sym_evsel->hists, NULL);
|
||||
hists__output_resort(&top->sym_evsel->hists);
|
||||
hists__decay_entries(&top->sym_evsel->hists,
|
||||
top->hide_user_symbols,
|
||||
top->hide_kernel_symbols);
|
||||
|
||||
hists__output_recalc_col_len(&top->sym_evsel->hists,
|
||||
top->print_entries - printed);
|
||||
putchar('\n');
|
||||
@@ -542,11 +548,16 @@ static void perf_top__sort_new_samples(void *arg)
|
||||
if (t->evlist->selected != NULL)
|
||||
t->sym_evsel = t->evlist->selected;
|
||||
|
||||
if (t->zero) {
|
||||
hists__delete_entries(&t->sym_evsel->hists);
|
||||
} else {
|
||||
hists__decay_entries(&t->sym_evsel->hists,
|
||||
t->hide_user_symbols,
|
||||
t->hide_kernel_symbols);
|
||||
}
|
||||
|
||||
hists__collapse_resort(&t->sym_evsel->hists, NULL);
|
||||
hists__output_resort(&t->sym_evsel->hists);
|
||||
hists__decay_entries(&t->sym_evsel->hists,
|
||||
t->hide_user_symbols,
|
||||
t->hide_kernel_symbols);
|
||||
}
|
||||
|
||||
static void *display_thread_tui(void *arg)
|
||||
@@ -577,23 +588,32 @@ static void *display_thread_tui(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void display_sig(int sig __maybe_unused)
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
|
||||
static void display_setup_sig(void)
|
||||
{
|
||||
signal(SIGSEGV, display_sig);
|
||||
signal(SIGFPE, display_sig);
|
||||
signal(SIGINT, display_sig);
|
||||
signal(SIGQUIT, display_sig);
|
||||
signal(SIGTERM, display_sig);
|
||||
}
|
||||
|
||||
static void *display_thread(void *arg)
|
||||
{
|
||||
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
|
||||
struct termios tc, save;
|
||||
struct termios save;
|
||||
struct perf_top *top = arg;
|
||||
int delay_msecs, c;
|
||||
|
||||
tcgetattr(0, &save);
|
||||
tc = save;
|
||||
tc.c_lflag &= ~(ICANON | ECHO);
|
||||
tc.c_cc[VMIN] = 0;
|
||||
tc.c_cc[VTIME] = 0;
|
||||
|
||||
display_setup_sig();
|
||||
pthread__unblock_sigwinch();
|
||||
repeat:
|
||||
delay_msecs = top->delay_secs * 1000;
|
||||
tcsetattr(0, TCSANOW, &tc);
|
||||
set_term_quiet_input(&save);
|
||||
/* trash return*/
|
||||
getc(stdin);
|
||||
|
||||
@@ -620,13 +640,16 @@ static void *display_thread(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
tcsetattr(0, TCSAFLUSH, &save);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
|
||||
static int symbol_filter(struct map *map, struct symbol *sym)
|
||||
{
|
||||
const char *name = sym->name;
|
||||
|
||||
if (!map->dso->kernel)
|
||||
return 0;
|
||||
/*
|
||||
* ppc64 uses function descriptors and appends a '.' to the
|
||||
* start of every instruction address. Remove it.
|
||||
@@ -963,7 +986,7 @@ static int __cmd_top(struct perf_top *top)
|
||||
param.sched_priority = top->realtime_prio;
|
||||
if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
|
||||
ui__error("Could not set realtime priority.\n");
|
||||
goto out_delete;
|
||||
goto out_join;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,6 +1000,8 @@ static int __cmd_top(struct perf_top *top)
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out_join:
|
||||
pthread_join(thread, NULL);
|
||||
out_delete:
|
||||
perf_session__delete(top->session);
|
||||
top->session = NULL;
|
||||
@@ -1220,7 +1245,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
symbol_conf.priv_size = sizeof(struct annotation);
|
||||
|
||||
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
|
||||
if (symbol__init() < 0)
|
||||
if (symbol__init(NULL) < 0)
|
||||
return -1;
|
||||
|
||||
sort__setup_elide(stdout);
|
||||
|
||||
@@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
|
||||
|
||||
#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
|
||||
|
||||
static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
|
||||
struct syscall_arg *arg)
|
||||
{
|
||||
int printed = 0, flags = arg->val;
|
||||
|
||||
#define P_MREMAP_FLAG(n) \
|
||||
if (flags & MREMAP_##n) { \
|
||||
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
|
||||
flags &= ~MREMAP_##n; \
|
||||
}
|
||||
|
||||
P_MREMAP_FLAG(MAYMOVE);
|
||||
#ifdef MREMAP_FIXED
|
||||
P_MREMAP_FLAG(FIXED);
|
||||
#endif
|
||||
#undef P_MREMAP_FLAG
|
||||
|
||||
if (flags)
|
||||
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
|
||||
|
||||
static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
|
||||
struct syscall_arg *arg)
|
||||
{
|
||||
@@ -1004,6 +1029,7 @@ static struct syscall_fmt {
|
||||
[2] = SCA_MMAP_PROT, /* prot */ }, },
|
||||
{ .name = "mremap", .hexret = true,
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* addr */
|
||||
[3] = SCA_MREMAP_FLAGS, /* flags */
|
||||
[4] = SCA_HEX, /* new_addr */ }, },
|
||||
{ .name = "munlock", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
|
||||
@@ -1385,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool,
|
||||
|
||||
static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
|
||||
{
|
||||
int err = symbol__init();
|
||||
int err = symbol__init(NULL);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
@@ -2215,13 +2241,13 @@ static int trace__replay(struct trace *trace)
|
||||
/* add tid to output */
|
||||
trace->multiple_threads = true;
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
|
||||
session = perf_session__new(&file, false, &trace->tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (symbol__init(&session->header.env) < 0)
|
||||
goto out;
|
||||
|
||||
trace->host = &session->machines.host;
|
||||
|
||||
err = perf_session__set_tracepoints_handlers(session, handlers);
|
||||
|
||||
@@ -297,7 +297,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
symbol_conf.sort_by_name = true;
|
||||
symbol_conf.try_vmlinux_path = true;
|
||||
|
||||
if (symbol__init() < 0)
|
||||
if (symbol__init(NULL) < 0)
|
||||
return -1;
|
||||
|
||||
if (skip != NULL)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../../util/pstack.h"
|
||||
#include "../../util/sort.h"
|
||||
#include "../../util/util.h"
|
||||
#include "../../util/top.h"
|
||||
#include "../../arch/common.h"
|
||||
|
||||
#include "../browser.h"
|
||||
@@ -228,8 +229,10 @@ static void callchain_node__init_have_children(struct callchain_node *node)
|
||||
{
|
||||
struct callchain_list *chain;
|
||||
|
||||
list_for_each_entry(chain, &node->val, list)
|
||||
if (!list_empty(&node->val)) {
|
||||
chain = list_entry(node->val.prev, struct callchain_list, list);
|
||||
chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
|
||||
}
|
||||
|
||||
callchain_node__init_have_children_rb_tree(node);
|
||||
}
|
||||
@@ -1530,6 +1533,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
|
||||
"P Print histograms to perf.hist.N\n"
|
||||
"t Zoom into current Thread\n"
|
||||
"V Verbose (DSO names in callchains, etc)\n"
|
||||
"z Toggle zeroing of samples\n"
|
||||
"/ Filter symbol by name";
|
||||
|
||||
if (browser == NULL)
|
||||
@@ -1630,6 +1634,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
|
||||
case 'F':
|
||||
symbol_conf.filter_relative ^= 1;
|
||||
continue;
|
||||
case 'z':
|
||||
if (!is_report_browser(hbt)) {
|
||||
struct perf_top *top = hbt->arg;
|
||||
|
||||
top->zero = !top->zero;
|
||||
}
|
||||
continue;
|
||||
case K_F1:
|
||||
case 'h':
|
||||
case '?':
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <sched.h>
|
||||
#include "util.h"
|
||||
#include "../perf.h"
|
||||
#include "cloexec.h"
|
||||
@@ -11,13 +12,27 @@ static int perf_flag_probe(void)
|
||||
struct perf_event_attr attr = {
|
||||
.type = PERF_TYPE_SOFTWARE,
|
||||
.config = PERF_COUNT_SW_CPU_CLOCK,
|
||||
.exclude_kernel = 1,
|
||||
};
|
||||
int fd;
|
||||
int err;
|
||||
int cpu;
|
||||
pid_t pid = -1;
|
||||
|
||||
/* check cloexec flag */
|
||||
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
||||
PERF_FLAG_FD_CLOEXEC);
|
||||
cpu = sched_getcpu();
|
||||
if (cpu < 0)
|
||||
cpu = 0;
|
||||
|
||||
while (1) {
|
||||
/* check cloexec flag */
|
||||
fd = sys_perf_event_open(&attr, pid, cpu, -1,
|
||||
PERF_FLAG_FD_CLOEXEC);
|
||||
if (fd < 0 && pid == -1 && errno == EACCES) {
|
||||
pid = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
err = errno;
|
||||
|
||||
if (fd >= 0) {
|
||||
@@ -30,7 +45,7 @@ static int perf_flag_probe(void)
|
||||
err, strerror(err));
|
||||
|
||||
/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
|
||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||
fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
|
||||
err = errno;
|
||||
|
||||
if (WARN_ONCE(fd < 0 && err != EBUSY,
|
||||
|
||||
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
|
||||
return new;
|
||||
}
|
||||
|
||||
struct comm *comm__new(const char *str, u64 timestamp)
|
||||
struct comm *comm__new(const char *str, u64 timestamp, bool exec)
|
||||
{
|
||||
struct comm *comm = zalloc(sizeof(*comm));
|
||||
|
||||
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
|
||||
return NULL;
|
||||
|
||||
comm->start = timestamp;
|
||||
comm->exec = exec;
|
||||
|
||||
comm->comm_str = comm_str__findnew(str, &comm_str_root);
|
||||
if (!comm->comm_str) {
|
||||
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
|
||||
return comm;
|
||||
}
|
||||
|
||||
int comm__override(struct comm *comm, const char *str, u64 timestamp)
|
||||
int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
|
||||
{
|
||||
struct comm_str *new, *old = comm->comm_str;
|
||||
|
||||
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)
|
||||
comm_str__put(old);
|
||||
comm->comm_str = new;
|
||||
comm->start = timestamp;
|
||||
if (exec)
|
||||
comm->exec = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ struct comm {
|
||||
struct comm_str *comm_str;
|
||||
u64 start;
|
||||
struct list_head list;
|
||||
bool exec;
|
||||
};
|
||||
|
||||
void comm__free(struct comm *comm);
|
||||
struct comm *comm__new(const char *str, u64 timestamp);
|
||||
struct comm *comm__new(const char *str, u64 timestamp, bool exec);
|
||||
const char *comm__str(const struct comm *comm);
|
||||
int comm__override(struct comm *comm, const char *str, u64 timestamp);
|
||||
int comm__override(struct comm *comm, const char *str, u64 timestamp,
|
||||
bool exec);
|
||||
|
||||
#endif /* __PERF_COMM_H */
|
||||
|
||||
@@ -156,6 +156,8 @@ struct perf_sample {
|
||||
u32 cpu;
|
||||
u32 raw_size;
|
||||
u64 data_src;
|
||||
u32 flags;
|
||||
u16 insn_len;
|
||||
void *raw_data;
|
||||
struct ip_callchain *callchain;
|
||||
struct branch_stack *branch_stack;
|
||||
|
||||
@@ -122,6 +122,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
|
||||
{
|
||||
list_add_tail(&entry->node, &evlist->entries);
|
||||
entry->idx = evlist->nr_entries;
|
||||
entry->tracking = !entry->idx;
|
||||
|
||||
if (!evlist->nr_entries++)
|
||||
perf_evlist__set_id_pos(evlist);
|
||||
@@ -265,17 +266,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_evlist__nr_threads(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel)
|
||||
{
|
||||
if (evsel->system_wide)
|
||||
return 1;
|
||||
else
|
||||
return thread_map__nr(evlist->threads);
|
||||
}
|
||||
|
||||
void perf_evlist__disable(struct perf_evlist *evlist)
|
||||
{
|
||||
int cpu, thread;
|
||||
struct perf_evsel *pos;
|
||||
int nr_cpus = cpu_map__nr(evlist->cpus);
|
||||
int nr_threads = thread_map__nr(evlist->threads);
|
||||
int nr_threads;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
evlist__for_each(evlist, pos) {
|
||||
if (!perf_evsel__is_group_leader(pos) || !pos->fd)
|
||||
continue;
|
||||
nr_threads = perf_evlist__nr_threads(evlist, pos);
|
||||
for (thread = 0; thread < nr_threads; thread++)
|
||||
ioctl(FD(pos, cpu, thread),
|
||||
PERF_EVENT_IOC_DISABLE, 0);
|
||||
@@ -288,12 +299,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
|
||||
int cpu, thread;
|
||||
struct perf_evsel *pos;
|
||||
int nr_cpus = cpu_map__nr(evlist->cpus);
|
||||
int nr_threads = thread_map__nr(evlist->threads);
|
||||
int nr_threads;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
evlist__for_each(evlist, pos) {
|
||||
if (!perf_evsel__is_group_leader(pos) || !pos->fd)
|
||||
continue;
|
||||
nr_threads = perf_evlist__nr_threads(evlist, pos);
|
||||
for (thread = 0; thread < nr_threads; thread++)
|
||||
ioctl(FD(pos, cpu, thread),
|
||||
PERF_EVENT_IOC_ENABLE, 0);
|
||||
@@ -305,12 +317,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel)
|
||||
{
|
||||
int cpu, thread, err;
|
||||
int nr_cpus = cpu_map__nr(evlist->cpus);
|
||||
int nr_threads = perf_evlist__nr_threads(evlist, evsel);
|
||||
|
||||
if (!evsel->fd)
|
||||
return 0;
|
||||
|
||||
for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
|
||||
for (thread = 0; thread < evlist->threads->nr; thread++) {
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
for (thread = 0; thread < nr_threads; thread++) {
|
||||
err = ioctl(FD(evsel, cpu, thread),
|
||||
PERF_EVENT_IOC_DISABLE, 0);
|
||||
if (err)
|
||||
@@ -324,12 +338,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel)
|
||||
{
|
||||
int cpu, thread, err;
|
||||
int nr_cpus = cpu_map__nr(evlist->cpus);
|
||||
int nr_threads = perf_evlist__nr_threads(evlist, evsel);
|
||||
|
||||
if (!evsel->fd)
|
||||
return -EINVAL;
|
||||
|
||||
for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
|
||||
for (thread = 0; thread < evlist->threads->nr; thread++) {
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
for (thread = 0; thread < nr_threads; thread++) {
|
||||
err = ioctl(FD(evsel, cpu, thread),
|
||||
PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (err)
|
||||
@@ -339,11 +355,67 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel, int cpu)
|
||||
{
|
||||
int thread, err;
|
||||
int nr_threads = perf_evlist__nr_threads(evlist, evsel);
|
||||
|
||||
if (!evsel->fd)
|
||||
return -EINVAL;
|
||||
|
||||
for (thread = 0; thread < nr_threads; thread++) {
|
||||
err = ioctl(FD(evsel, cpu, thread),
|
||||
PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel,
|
||||
int thread)
|
||||
{
|
||||
int cpu, err;
|
||||
int nr_cpus = cpu_map__nr(evlist->cpus);
|
||||
|
||||
if (!evsel->fd)
|
||||
return -EINVAL;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel, int idx)
|
||||
{
|
||||
bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
|
||||
|
||||
if (per_cpu_mmaps)
|
||||
return perf_evlist__enable_event_cpu(evlist, evsel, idx);
|
||||
else
|
||||
return perf_evlist__enable_event_thread(evlist, evsel, idx);
|
||||
}
|
||||
|
||||
static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
|
||||
{
|
||||
int nr_cpus = cpu_map__nr(evlist->cpus);
|
||||
int nr_threads = thread_map__nr(evlist->threads);
|
||||
int nfds = nr_cpus * nr_threads * evlist->nr_entries;
|
||||
int nfds = 0;
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
if (evsel->system_wide)
|
||||
nfds += nr_cpus;
|
||||
else
|
||||
nfds += nr_cpus * nr_threads;
|
||||
}
|
||||
|
||||
evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
|
||||
return evlist->pollfd != NULL ? 0 : -ENOMEM;
|
||||
}
|
||||
@@ -636,7 +708,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
int fd = FD(evsel, cpu, thread);
|
||||
int fd;
|
||||
|
||||
if (evsel->system_wide && thread)
|
||||
continue;
|
||||
|
||||
fd = FD(evsel, cpu, thread);
|
||||
|
||||
if (*output == -1) {
|
||||
*output = fd;
|
||||
@@ -1266,3 +1343,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
|
||||
|
||||
list_splice(&move, &evlist->entries);
|
||||
}
|
||||
|
||||
void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *tracking_evsel)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
if (tracking_evsel->tracking)
|
||||
return;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
if (evsel != tracking_evsel)
|
||||
evsel->tracking = false;
|
||||
}
|
||||
|
||||
tracking_evsel->tracking = true;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
int perf_evlist__enable_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel, int idx);
|
||||
|
||||
void perf_evlist__set_selected(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
@@ -262,4 +264,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
|
||||
#define evlist__for_each_safe(evlist, tmp, evsel) \
|
||||
__evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
|
||||
|
||||
void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *tracking_evsel);
|
||||
|
||||
#endif /* __PERF_EVLIST_H */
|
||||
|
||||
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
|
||||
struct perf_event_attr *attr, int idx)
|
||||
{
|
||||
evsel->idx = idx;
|
||||
evsel->tracking = !idx;
|
||||
evsel->attr = *attr;
|
||||
evsel->leader = evsel;
|
||||
evsel->unit = "";
|
||||
@@ -561,7 +562,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
|
||||
{
|
||||
struct perf_evsel *leader = evsel->leader;
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
int track = !evsel->idx; /* only the first counter needs these */
|
||||
int track = evsel->tracking;
|
||||
bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
|
||||
|
||||
attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
|
||||
@@ -695,6 +696,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
|
||||
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
{
|
||||
int cpu, thread;
|
||||
|
||||
if (evsel->system_wide)
|
||||
nthreads = 1;
|
||||
|
||||
evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
|
||||
|
||||
if (evsel->fd) {
|
||||
@@ -713,6 +718,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
|
||||
{
|
||||
int cpu, thread;
|
||||
|
||||
if (evsel->system_wide)
|
||||
nthreads = 1;
|
||||
|
||||
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||
for (thread = 0; thread < nthreads; thread++) {
|
||||
int fd = FD(evsel, cpu, thread),
|
||||
@@ -743,6 +751,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
|
||||
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
{
|
||||
if (evsel->system_wide)
|
||||
nthreads = 1;
|
||||
|
||||
evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
|
||||
if (evsel->sample_id == NULL)
|
||||
return -ENOMEM;
|
||||
@@ -787,6 +798,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
{
|
||||
int cpu, thread;
|
||||
|
||||
if (evsel->system_wide)
|
||||
nthreads = 1;
|
||||
|
||||
for (cpu = 0; cpu < ncpus; cpu++)
|
||||
for (thread = 0; thread < nthreads; ++thread) {
|
||||
close(FD(evsel, cpu, thread));
|
||||
@@ -875,6 +889,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,
|
||||
int cpu, thread;
|
||||
struct perf_counts_values *aggr = &evsel->counts->aggr, count;
|
||||
|
||||
if (evsel->system_wide)
|
||||
nthreads = 1;
|
||||
|
||||
aggr->val = aggr->ena = aggr->run = 0;
|
||||
|
||||
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||
@@ -997,13 +1014,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
|
||||
static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
|
||||
struct thread_map *threads)
|
||||
{
|
||||
int cpu, thread;
|
||||
int cpu, thread, nthreads;
|
||||
unsigned long flags = PERF_FLAG_FD_CLOEXEC;
|
||||
int pid = -1, err;
|
||||
enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
|
||||
|
||||
if (evsel->system_wide)
|
||||
nthreads = 1;
|
||||
else
|
||||
nthreads = threads->nr;
|
||||
|
||||
if (evsel->fd == NULL &&
|
||||
perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
|
||||
perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (evsel->cgrp) {
|
||||
@@ -1027,10 +1049,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
|
||||
|
||||
for (cpu = 0; cpu < cpus->nr; cpu++) {
|
||||
|
||||
for (thread = 0; thread < threads->nr; thread++) {
|
||||
for (thread = 0; thread < nthreads; thread++) {
|
||||
int group_fd;
|
||||
|
||||
if (!evsel->cgrp)
|
||||
if (!evsel->cgrp && !evsel->system_wide)
|
||||
pid = threads->map[thread];
|
||||
|
||||
group_fd = get_group_fd(evsel, cpu, thread);
|
||||
@@ -1103,7 +1125,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
|
||||
close(FD(evsel, cpu, thread));
|
||||
FD(evsel, cpu, thread) = -1;
|
||||
}
|
||||
thread = threads->nr;
|
||||
thread = nthreads;
|
||||
} while (--cpu >= 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,8 @@ struct perf_evsel {
|
||||
bool needs_swap;
|
||||
bool no_aux_samples;
|
||||
bool immediate;
|
||||
bool system_wide;
|
||||
bool tracking;
|
||||
/* parse modifier helper */
|
||||
int exclude_GH;
|
||||
int nr_members;
|
||||
|
||||
@@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
|
||||
}
|
||||
}
|
||||
|
||||
void hists__delete_entries(struct hists *hists)
|
||||
{
|
||||
struct rb_node *next = rb_first(&hists->entries);
|
||||
struct hist_entry *n;
|
||||
|
||||
while (next) {
|
||||
n = rb_entry(next, struct hist_entry, rb_node);
|
||||
next = rb_next(&n->rb_node);
|
||||
|
||||
rb_erase(&n->rb_node, &hists->entries);
|
||||
|
||||
if (sort__need_collapse)
|
||||
rb_erase(&n->rb_node_in, &hists->entries_collapsed);
|
||||
|
||||
--hists->nr_entries;
|
||||
if (!n->filtered)
|
||||
--hists->nr_non_filtered_entries;
|
||||
|
||||
hist_entry__free(n);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* histogram, sorted on item, collects periods
|
||||
*/
|
||||
|
||||
@@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists);
|
||||
void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
|
||||
|
||||
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
|
||||
void hists__delete_entries(struct hists *hists);
|
||||
void hists__output_recalc_col_len(struct hists *hists, int max_rows);
|
||||
|
||||
u64 hists__total_period(struct hists *hists);
|
||||
|
||||
@@ -31,6 +31,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
||||
|
||||
machine->symbol_filter = NULL;
|
||||
machine->id_hdr_size = 0;
|
||||
machine->comm_exec = false;
|
||||
|
||||
machine->root_dir = strdup(root_dir);
|
||||
if (machine->root_dir == NULL)
|
||||
@@ -179,6 +180,19 @@ void machines__set_symbol_filter(struct machines *machines,
|
||||
}
|
||||
}
|
||||
|
||||
void machines__set_comm_exec(struct machines *machines, bool comm_exec)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
|
||||
machines->host.comm_exec = comm_exec;
|
||||
|
||||
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
||||
struct machine *machine = rb_entry(nd, struct machine, rb_node);
|
||||
|
||||
machine->comm_exec = comm_exec;
|
||||
}
|
||||
}
|
||||
|
||||
struct machine *machines__find(struct machines *machines, pid_t pid)
|
||||
{
|
||||
struct rb_node **p = &machines->guests.rb_node;
|
||||
@@ -398,17 +412,31 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
|
||||
return __machine__findnew_thread(machine, pid, tid, false);
|
||||
}
|
||||
|
||||
struct comm *machine__thread_exec_comm(struct machine *machine,
|
||||
struct thread *thread)
|
||||
{
|
||||
if (machine->comm_exec)
|
||||
return thread__exec_comm(thread);
|
||||
else
|
||||
return thread__comm(thread);
|
||||
}
|
||||
|
||||
int machine__process_comm_event(struct machine *machine, union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
struct thread *thread = machine__findnew_thread(machine,
|
||||
event->comm.pid,
|
||||
event->comm.tid);
|
||||
bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
|
||||
|
||||
if (exec)
|
||||
machine->comm_exec = true;
|
||||
|
||||
if (dump_trace)
|
||||
perf_event__fprintf_comm(event, stdout);
|
||||
|
||||
if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
|
||||
if (thread == NULL ||
|
||||
__thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
|
||||
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ struct machine {
|
||||
struct rb_node rb_node;
|
||||
pid_t pid;
|
||||
u16 id_hdr_size;
|
||||
bool comm_exec;
|
||||
char *root_dir;
|
||||
struct rb_root threads;
|
||||
struct list_head dead_threads;
|
||||
@@ -47,6 +48,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
|
||||
|
||||
struct thread *machine__find_thread(struct machine *machine, pid_t pid,
|
||||
pid_t tid);
|
||||
struct comm *machine__thread_exec_comm(struct machine *machine,
|
||||
struct thread *thread);
|
||||
|
||||
int machine__process_comm_event(struct machine *machine, union perf_event *event,
|
||||
struct perf_sample *sample);
|
||||
@@ -88,6 +91,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
|
||||
|
||||
void machines__set_symbol_filter(struct machines *machines,
|
||||
symbol_filter_t symbol_filter);
|
||||
void machines__set_comm_exec(struct machines *machines, bool comm_exec);
|
||||
|
||||
struct machine *machine__new_host(void);
|
||||
int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
|
||||
|
||||
@@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only)
|
||||
int ret;
|
||||
|
||||
symbol_conf.sort_by_name = true;
|
||||
ret = symbol__init();
|
||||
ret = symbol__init(NULL);
|
||||
if (ret < 0) {
|
||||
pr_debug("Failed to init symbol map.\n");
|
||||
goto out;
|
||||
@@ -1780,10 +1780,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
|
||||
memset(tev, 0, sizeof(*tev));
|
||||
}
|
||||
|
||||
static void print_warn_msg(const char *file, bool is_kprobe)
|
||||
static void print_open_warning(int err, bool is_kprobe)
|
||||
{
|
||||
char sbuf[128];
|
||||
|
||||
if (errno == ENOENT) {
|
||||
if (err == -ENOENT) {
|
||||
const char *config;
|
||||
|
||||
if (!is_kprobe)
|
||||
@@ -1791,25 +1792,43 @@ static void print_warn_msg(const char *file, bool is_kprobe)
|
||||
else
|
||||
config = "CONFIG_KPROBE_EVENTS";
|
||||
|
||||
pr_warning("%s file does not exist - please rebuild kernel"
|
||||
" with %s.\n", file, config);
|
||||
} else
|
||||
pr_warning("Failed to open %s file: %s\n", file,
|
||||
strerror(errno));
|
||||
pr_warning("%cprobe_events file does not exist"
|
||||
" - please rebuild kernel with %s.\n",
|
||||
is_kprobe ? 'k' : 'u', config);
|
||||
} else if (err == -ENOTSUP)
|
||||
pr_warning("Debugfs is not mounted.\n");
|
||||
else
|
||||
pr_warning("Failed to open %cprobe_events: %s\n",
|
||||
is_kprobe ? 'k' : 'u',
|
||||
strerror_r(-err, sbuf, sizeof(sbuf)));
|
||||
}
|
||||
|
||||
static int open_probe_events(const char *trace_file, bool readwrite,
|
||||
bool is_kprobe)
|
||||
static void print_both_open_warning(int kerr, int uerr)
|
||||
{
|
||||
/* Both kprobes and uprobes are disabled, warn it. */
|
||||
if (kerr == -ENOTSUP && uerr == -ENOTSUP)
|
||||
pr_warning("Debugfs is not mounted.\n");
|
||||
else if (kerr == -ENOENT && uerr == -ENOENT)
|
||||
pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
|
||||
"or/and CONFIG_UPROBE_EVENTS.\n");
|
||||
else {
|
||||
char sbuf[128];
|
||||
pr_warning("Failed to open kprobe events: %s.\n",
|
||||
strerror_r(-kerr, sbuf, sizeof(sbuf)));
|
||||
pr_warning("Failed to open uprobe events: %s.\n",
|
||||
strerror_r(-uerr, sbuf, sizeof(sbuf)));
|
||||
}
|
||||
}
|
||||
|
||||
static int open_probe_events(const char *trace_file, bool readwrite)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
const char *__debugfs;
|
||||
int ret;
|
||||
|
||||
__debugfs = debugfs_find_mountpoint();
|
||||
if (__debugfs == NULL) {
|
||||
pr_warning("Debugfs is not mounted.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
if (__debugfs == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
|
||||
if (ret >= 0) {
|
||||
@@ -1820,19 +1839,19 @@ static int open_probe_events(const char *trace_file, bool readwrite,
|
||||
ret = open(buf, O_RDONLY, 0);
|
||||
|
||||
if (ret < 0)
|
||||
print_warn_msg(buf, is_kprobe);
|
||||
ret = -errno;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int open_kprobe_events(bool readwrite)
|
||||
{
|
||||
return open_probe_events("tracing/kprobe_events", readwrite, true);
|
||||
return open_probe_events("tracing/kprobe_events", readwrite);
|
||||
}
|
||||
|
||||
static int open_uprobe_events(bool readwrite)
|
||||
{
|
||||
return open_probe_events("tracing/uprobe_events", readwrite, false);
|
||||
return open_probe_events("tracing/uprobe_events", readwrite);
|
||||
}
|
||||
|
||||
/* Get raw string list of current kprobe_events or uprobe_events */
|
||||
@@ -1940,27 +1959,34 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
|
||||
/* List up current perf-probe events */
|
||||
int show_perf_probe_events(void)
|
||||
{
|
||||
int fd, ret;
|
||||
int kp_fd, up_fd, ret;
|
||||
|
||||
setup_pager();
|
||||
fd = open_kprobe_events(false);
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
ret = init_symbol_maps(false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = __show_perf_probe_events(fd, true);
|
||||
close(fd);
|
||||
|
||||
fd = open_uprobe_events(false);
|
||||
if (fd >= 0) {
|
||||
ret = __show_perf_probe_events(fd, false);
|
||||
close(fd);
|
||||
kp_fd = open_kprobe_events(false);
|
||||
if (kp_fd >= 0) {
|
||||
ret = __show_perf_probe_events(kp_fd, true);
|
||||
close(kp_fd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
up_fd = open_uprobe_events(false);
|
||||
if (kp_fd < 0 && up_fd < 0) {
|
||||
print_both_open_warning(kp_fd, up_fd);
|
||||
ret = kp_fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (up_fd >= 0) {
|
||||
ret = __show_perf_probe_events(up_fd, false);
|
||||
close(up_fd);
|
||||
}
|
||||
out:
|
||||
exit_symbol_maps();
|
||||
return ret;
|
||||
}
|
||||
@@ -2075,8 +2101,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
|
||||
else
|
||||
fd = open_kprobe_events(true);
|
||||
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
print_open_warning(fd, !pev->uprobes);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Get current event names */
|
||||
namelist = get_probe_trace_event_names(fd, false);
|
||||
if (!namelist) {
|
||||
@@ -2449,15 +2478,18 @@ int del_perf_probe_events(struct strlist *dellist)
|
||||
|
||||
/* Get current event names */
|
||||
kfd = open_kprobe_events(true);
|
||||
if (kfd < 0)
|
||||
return kfd;
|
||||
if (kfd >= 0)
|
||||
namelist = get_probe_trace_event_names(kfd, true);
|
||||
|
||||
namelist = get_probe_trace_event_names(kfd, true);
|
||||
ufd = open_uprobe_events(true);
|
||||
|
||||
if (ufd >= 0)
|
||||
unamelist = get_probe_trace_event_names(ufd, true);
|
||||
|
||||
if (kfd < 0 && ufd < 0) {
|
||||
print_both_open_warning(kfd, ufd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (namelist == NULL && unamelist == NULL)
|
||||
goto error;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
|
||||
struct perf_evsel *evsel;
|
||||
unsigned long flags = perf_event_open_cloexec_flag();
|
||||
int err = -EAGAIN, fd;
|
||||
static pid_t pid = -1;
|
||||
|
||||
evlist = perf_evlist__new();
|
||||
if (!evlist)
|
||||
@@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
|
||||
|
||||
evsel = perf_evlist__first(evlist);
|
||||
|
||||
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
|
||||
if (fd < 0)
|
||||
goto out_delete;
|
||||
while (1) {
|
||||
fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
|
||||
if (fd < 0) {
|
||||
if (pid == -1 && errno == EACCES) {
|
||||
pid = 0;
|
||||
continue;
|
||||
}
|
||||
goto out_delete;
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
fn(evsel);
|
||||
|
||||
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
|
||||
fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
|
||||
if (fd < 0) {
|
||||
if (errno == EINVAL)
|
||||
err = -EINVAL;
|
||||
@@ -47,7 +56,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
|
||||
|
||||
static bool perf_probe_api(setup_probe_fn_t fn)
|
||||
{
|
||||
const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
|
||||
const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
|
||||
struct cpu_map *cpus;
|
||||
int cpu, ret, i = 0;
|
||||
|
||||
@@ -106,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
perf_evsel__config(evsel, opts);
|
||||
if (!evsel->idx && use_comm_exec)
|
||||
if (evsel->tracking && use_comm_exec)
|
||||
evsel->attr.comm_exec = 1;
|
||||
}
|
||||
|
||||
@@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
|
||||
struct perf_evsel *evsel;
|
||||
int err, fd, cpu;
|
||||
bool ret = false;
|
||||
pid_t pid = -1;
|
||||
|
||||
temp_evlist = perf_evlist__new();
|
||||
if (!temp_evlist)
|
||||
@@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
|
||||
cpu = evlist->cpus->map[0];
|
||||
}
|
||||
|
||||
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
|
||||
perf_event_open_cloexec_flag());
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
ret = true;
|
||||
while (1) {
|
||||
fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1,
|
||||
perf_event_open_cloexec_flag());
|
||||
if (fd < 0) {
|
||||
if (pid == -1 && errno == EACCES) {
|
||||
pid = 0;
|
||||
continue;
|
||||
}
|
||||
goto out_delete;
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
ret = true;
|
||||
|
||||
out_delete:
|
||||
perf_evlist__delete(temp_evlist);
|
||||
|
||||
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj
|
||||
Py_DECREF(val);
|
||||
}
|
||||
|
||||
static PyObject *get_handler(const char *handler_name)
|
||||
{
|
||||
PyObject *handler;
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, handler_name);
|
||||
if (handler && !PyCallable_Check(handler))
|
||||
return NULL;
|
||||
return handler;
|
||||
}
|
||||
|
||||
static void call_object(PyObject *handler, PyObject *args, const char *die_msg)
|
||||
{
|
||||
PyObject *retval;
|
||||
|
||||
retval = PyObject_CallObject(handler, args);
|
||||
if (retval == NULL)
|
||||
handler_call_die(die_msg);
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
|
||||
static void try_call_object(const char *handler_name, PyObject *args)
|
||||
{
|
||||
PyObject *handler;
|
||||
|
||||
handler = get_handler(handler_name);
|
||||
if (handler)
|
||||
call_object(handler, args, handler_name);
|
||||
}
|
||||
|
||||
static void define_value(enum print_arg_type field_type,
|
||||
const char *ev_name,
|
||||
const char *field_name,
|
||||
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type,
|
||||
const char *field_str)
|
||||
{
|
||||
const char *handler_name = "define_flag_value";
|
||||
PyObject *handler, *t, *retval;
|
||||
PyObject *t;
|
||||
unsigned long long value;
|
||||
unsigned n = 0;
|
||||
|
||||
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,
|
||||
PyTuple_SetItem(t, n++, PyInt_FromLong(value));
|
||||
PyTuple_SetItem(t, n++, PyString_FromString(field_str));
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, handler_name);
|
||||
if (handler && PyCallable_Check(handler)) {
|
||||
retval = PyObject_CallObject(handler, t);
|
||||
if (retval == NULL)
|
||||
handler_call_die(handler_name);
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
try_call_object(handler_name, t);
|
||||
|
||||
Py_DECREF(t);
|
||||
}
|
||||
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type,
|
||||
const char *delim)
|
||||
{
|
||||
const char *handler_name = "define_flag_field";
|
||||
PyObject *handler, *t, *retval;
|
||||
PyObject *t;
|
||||
unsigned n = 0;
|
||||
|
||||
if (field_type == PRINT_SYMBOL)
|
||||
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,
|
||||
if (field_type == PRINT_FLAGS)
|
||||
PyTuple_SetItem(t, n++, PyString_FromString(delim));
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, handler_name);
|
||||
if (handler && PyCallable_Check(handler)) {
|
||||
retval = PyObject_CallObject(handler, t);
|
||||
if (retval == NULL)
|
||||
handler_call_die(handler_name);
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
try_call_object(handler_name, t);
|
||||
|
||||
Py_DECREF(t);
|
||||
}
|
||||
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
|
||||
struct thread *thread,
|
||||
struct addr_location *al)
|
||||
{
|
||||
PyObject *handler, *retval, *context, *t, *obj, *callchain;
|
||||
PyObject *handler, *context, *t, *obj, *callchain;
|
||||
PyObject *dict = NULL;
|
||||
static char handler_name[256];
|
||||
struct format_field *field;
|
||||
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
|
||||
|
||||
sprintf(handler_name, "%s__%s", event->system, event->name);
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, handler_name);
|
||||
if (handler && !PyCallable_Check(handler))
|
||||
handler = NULL;
|
||||
handler = get_handler(handler_name);
|
||||
if (!handler) {
|
||||
dict = PyDict_New();
|
||||
if (!dict)
|
||||
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
|
||||
Py_FatalError("error resizing Python tuple");
|
||||
|
||||
if (handler) {
|
||||
retval = PyObject_CallObject(handler, t);
|
||||
if (retval == NULL)
|
||||
handler_call_die(handler_name);
|
||||
Py_DECREF(retval);
|
||||
call_object(handler, t, handler_name);
|
||||
} else {
|
||||
handler = PyDict_GetItemString(main_dict, "trace_unhandled");
|
||||
if (handler && PyCallable_Check(handler)) {
|
||||
|
||||
retval = PyObject_CallObject(handler, t);
|
||||
if (retval == NULL)
|
||||
handler_call_die("trace_unhandled");
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
try_call_object("trace_unhandled", t);
|
||||
Py_DECREF(dict);
|
||||
}
|
||||
|
||||
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,
|
||||
struct thread *thread,
|
||||
struct addr_location *al)
|
||||
{
|
||||
PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
|
||||
PyObject *handler, *t, *dict, *callchain, *dict_sample;
|
||||
static char handler_name[64];
|
||||
unsigned n = 0;
|
||||
|
||||
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,
|
||||
|
||||
snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, handler_name);
|
||||
if (!handler || !PyCallable_Check(handler))
|
||||
handler = get_handler(handler_name);
|
||||
if (!handler)
|
||||
goto exit;
|
||||
|
||||
pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
|
||||
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,
|
||||
if (_PyTuple_Resize(&t, n) == -1)
|
||||
Py_FatalError("error resizing Python tuple");
|
||||
|
||||
retval = PyObject_CallObject(handler, t);
|
||||
if (retval == NULL)
|
||||
handler_call_die(handler_name);
|
||||
Py_DECREF(retval);
|
||||
call_object(handler, t, handler_name);
|
||||
exit:
|
||||
Py_DECREF(dict);
|
||||
Py_DECREF(t);
|
||||
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,
|
||||
|
||||
static int run_start_sub(void)
|
||||
{
|
||||
PyObject *handler, *retval;
|
||||
int err = 0;
|
||||
|
||||
main_module = PyImport_AddModule("__main__");
|
||||
if (main_module == NULL)
|
||||
return -1;
|
||||
Py_INCREF(main_module);
|
||||
|
||||
main_dict = PyModule_GetDict(main_module);
|
||||
if (main_dict == NULL) {
|
||||
err = -1;
|
||||
if (main_dict == NULL)
|
||||
goto error;
|
||||
}
|
||||
Py_INCREF(main_dict);
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, "trace_begin");
|
||||
if (handler == NULL || !PyCallable_Check(handler))
|
||||
goto out;
|
||||
try_call_object("trace_begin", NULL);
|
||||
|
||||
retval = PyObject_CallObject(handler, NULL);
|
||||
if (retval == NULL)
|
||||
handler_call_die("trace_begin");
|
||||
return 0;
|
||||
|
||||
Py_DECREF(retval);
|
||||
return err;
|
||||
error:
|
||||
Py_XDECREF(main_dict);
|
||||
Py_XDECREF(main_module);
|
||||
out:
|
||||
return err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -654,23 +644,13 @@ static int python_start_script(const char *script, int argc, const char **argv)
|
||||
*/
|
||||
static int python_stop_script(void)
|
||||
{
|
||||
PyObject *handler, *retval;
|
||||
int err = 0;
|
||||
try_call_object("trace_end", NULL);
|
||||
|
||||
handler = PyDict_GetItemString(main_dict, "trace_end");
|
||||
if (handler == NULL || !PyCallable_Check(handler))
|
||||
goto out;
|
||||
|
||||
retval = PyObject_CallObject(handler, NULL);
|
||||
if (retval == NULL)
|
||||
handler_call_die("trace_end");
|
||||
Py_DECREF(retval);
|
||||
out:
|
||||
Py_XDECREF(main_dict);
|
||||
Py_XDECREF(main_module);
|
||||
Py_Finalize();
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int python_generate_script(struct pevent *pevent, const char *outfile)
|
||||
|
||||
@@ -67,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)
|
||||
machines__destroy_kernel_maps(&session->machines);
|
||||
}
|
||||
|
||||
static bool perf_session__has_comm_exec(struct perf_session *session)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(session->evlist, evsel) {
|
||||
if (evsel->attr.comm_exec)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void perf_session__set_comm_exec(struct perf_session *session)
|
||||
{
|
||||
bool comm_exec = perf_session__has_comm_exec(session);
|
||||
|
||||
machines__set_comm_exec(&session->machines, comm_exec);
|
||||
}
|
||||
|
||||
struct perf_session *perf_session__new(struct perf_data_file *file,
|
||||
bool repipe, struct perf_tool *tool)
|
||||
{
|
||||
@@ -90,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
|
||||
goto out_close;
|
||||
|
||||
perf_session__set_id_hdr_size(session);
|
||||
perf_session__set_comm_exec(session);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,
|
||||
switch (event->header.type) {
|
||||
case PERF_RECORD_HEADER_ATTR:
|
||||
err = tool->attr(tool, event, &session->evlist);
|
||||
if (err == 0)
|
||||
if (err == 0) {
|
||||
perf_session__set_id_hdr_size(session);
|
||||
perf_session__set_comm_exec(session);
|
||||
}
|
||||
return err;
|
||||
case PERF_RECORD_HEADER_EVENT_TYPE:
|
||||
/*
|
||||
@@ -897,6 +919,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)
|
||||
swap(event, sample_id_all);
|
||||
}
|
||||
|
||||
int perf_session__peek_event(struct perf_session *session, off_t file_offset,
|
||||
void *buf, size_t buf_sz,
|
||||
union perf_event **event_ptr,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
union perf_event *event;
|
||||
size_t hdr_sz, rest;
|
||||
int fd;
|
||||
|
||||
if (session->one_mmap && !session->header.needs_swap) {
|
||||
event = file_offset - session->one_mmap_offset +
|
||||
session->one_mmap_addr;
|
||||
goto out_parse_sample;
|
||||
}
|
||||
|
||||
if (perf_data_file__is_pipe(session->file))
|
||||
return -1;
|
||||
|
||||
fd = perf_data_file__fd(session->file);
|
||||
hdr_sz = sizeof(struct perf_event_header);
|
||||
|
||||
if (buf_sz < hdr_sz)
|
||||
return -1;
|
||||
|
||||
if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
|
||||
readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
|
||||
return -1;
|
||||
|
||||
event = (union perf_event *)buf;
|
||||
|
||||
if (session->header.needs_swap)
|
||||
perf_event_header__bswap(&event->header);
|
||||
|
||||
if (event->header.size < hdr_sz)
|
||||
return -1;
|
||||
|
||||
rest = event->header.size - hdr_sz;
|
||||
|
||||
if (readn(fd, &buf, rest) != (ssize_t)rest)
|
||||
return -1;
|
||||
|
||||
if (session->header.needs_swap)
|
||||
event_swap(event, perf_evlist__sample_id_all(session->evlist));
|
||||
|
||||
out_parse_sample:
|
||||
|
||||
if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
|
||||
perf_evlist__parse_sample(session->evlist, event, sample))
|
||||
return -1;
|
||||
|
||||
*event_ptr = event;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s64 perf_session__process_event(struct perf_session *session,
|
||||
union perf_event *event,
|
||||
struct perf_tool *tool,
|
||||
|
||||
@@ -45,6 +45,11 @@ void perf_session__delete(struct perf_session *session);
|
||||
|
||||
void perf_event_header__bswap(struct perf_event_header *hdr);
|
||||
|
||||
int perf_session__peek_event(struct perf_session *session, off_t file_offset,
|
||||
void *buf, size_t buf_sz,
|
||||
union perf_event **event_ptr,
|
||||
struct perf_sample *sample);
|
||||
|
||||
int __perf_session__process_events(struct perf_session *session,
|
||||
u64 data_offset, u64 data_size, u64 size,
|
||||
struct perf_tool *tool);
|
||||
|
||||
@@ -736,7 +736,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
|
||||
if (symstrs == NULL)
|
||||
goto out_elf_end;
|
||||
|
||||
sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
|
||||
sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
|
||||
if (sec_strndx == NULL)
|
||||
goto out_elf_end;
|
||||
|
||||
@@ -939,8 +939,11 @@ int dso__load_sym(struct dso *dso, struct map *map,
|
||||
* to it...
|
||||
*/
|
||||
if (symbol_conf.demangle) {
|
||||
demangled = bfd_demangle(NULL, elf_name,
|
||||
DMGL_PARAMS | DMGL_ANSI);
|
||||
int demangle_flags = DMGL_NO_OPTS;
|
||||
if (verbose)
|
||||
demangle_flags = DMGL_PARAMS | DMGL_ANSI;
|
||||
|
||||
demangled = bfd_demangle(NULL, elf_name, demangle_flags);
|
||||
if (demangled != NULL)
|
||||
elf_name = demangled;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "machine.h"
|
||||
#include "symbol.h"
|
||||
#include "strlist.h"
|
||||
#include "header.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include <limits.h>
|
||||
@@ -523,10 +524,15 @@ struct process_kallsyms_args {
|
||||
struct dso *dso;
|
||||
};
|
||||
|
||||
/*
|
||||
* These are symbols in the kernel image, so make sure that
|
||||
* sym is from a kernel DSO.
|
||||
*/
|
||||
bool symbol__is_idle(struct symbol *sym)
|
||||
{
|
||||
const char * const idle_symbols[] = {
|
||||
"cpu_idle",
|
||||
"cpu_startup_entry",
|
||||
"intel_idle",
|
||||
"default_idle",
|
||||
"native_safe_halt",
|
||||
@@ -1744,10 +1750,11 @@ static void vmlinux_path__exit(void)
|
||||
zfree(&vmlinux_path);
|
||||
}
|
||||
|
||||
static int vmlinux_path__init(void)
|
||||
static int vmlinux_path__init(struct perf_session_env *env)
|
||||
{
|
||||
struct utsname uts;
|
||||
char bf[PATH_MAX];
|
||||
char *kernel_version;
|
||||
|
||||
vmlinux_path = malloc(sizeof(char *) * 5);
|
||||
if (vmlinux_path == NULL)
|
||||
@@ -1762,25 +1769,31 @@ static int vmlinux_path__init(void)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
|
||||
/* only try running kernel version if no symfs was given */
|
||||
/* only try kernel version if no symfs was given */
|
||||
if (symbol_conf.symfs[0] != 0)
|
||||
return 0;
|
||||
|
||||
if (uname(&uts) < 0)
|
||||
return -1;
|
||||
if (env) {
|
||||
kernel_version = env->os_release;
|
||||
} else {
|
||||
if (uname(&uts) < 0)
|
||||
goto out_fail;
|
||||
|
||||
snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
|
||||
kernel_version = uts.release;
|
||||
}
|
||||
|
||||
snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
|
||||
snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
|
||||
uts.release);
|
||||
kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
@@ -1826,7 +1839,7 @@ static bool symbol__read_kptr_restrict(void)
|
||||
return value;
|
||||
}
|
||||
|
||||
int symbol__init(void)
|
||||
int symbol__init(struct perf_session_env *env)
|
||||
{
|
||||
const char *symfs;
|
||||
|
||||
@@ -1841,7 +1854,7 @@ int symbol__init(void)
|
||||
symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
|
||||
sizeof(struct symbol));
|
||||
|
||||
if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
|
||||
if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
|
||||
return -1;
|
||||
|
||||
if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
|
||||
|
||||
@@ -60,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
|
||||
#endif
|
||||
|
||||
#ifndef DMGL_PARAMS
|
||||
#define DMGL_NO_OPTS 0 /* For readability... */
|
||||
#define DMGL_PARAMS (1 << 0) /* Include function args */
|
||||
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
|
||||
#endif
|
||||
@@ -262,7 +263,8 @@ int modules__parse(const char *filename, void *arg,
|
||||
int filename__read_debuglink(const char *filename, char *debuglink,
|
||||
size_t size);
|
||||
|
||||
int symbol__init(void);
|
||||
struct perf_session_env;
|
||||
int symbol__init(struct perf_session_env *env);
|
||||
void symbol__exit(void);
|
||||
void symbol__elf_init(void);
|
||||
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
|
||||
|
||||
@@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
|
||||
goto err_thread;
|
||||
|
||||
snprintf(comm_str, 32, ":%d", tid);
|
||||
comm = comm__new(comm_str, 0);
|
||||
comm = comm__new(comm_str, 0, false);
|
||||
free(comm_str);
|
||||
if (!comm)
|
||||
goto err_thread;
|
||||
@@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread)
|
||||
return list_first_entry(&thread->comm_list, struct comm, list);
|
||||
}
|
||||
|
||||
struct comm *thread__exec_comm(const struct thread *thread)
|
||||
{
|
||||
struct comm *comm, *last = NULL;
|
||||
|
||||
list_for_each_entry(comm, &thread->comm_list, list) {
|
||||
if (comm->exec)
|
||||
return comm;
|
||||
last = comm;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
/* CHECKME: time should always be 0 if event aren't ordered */
|
||||
int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
|
||||
int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
|
||||
bool exec)
|
||||
{
|
||||
struct comm *new, *curr = thread__comm(thread);
|
||||
int err;
|
||||
|
||||
/* Override latest entry if it had no specific time coverage */
|
||||
if (!curr->start) {
|
||||
err = comm__override(curr, str, timestamp);
|
||||
if (!curr->start && !curr->exec) {
|
||||
err = comm__override(curr, str, timestamp, exec);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
new = comm__new(str, timestamp);
|
||||
new = comm__new(str, timestamp, exec);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
list_add(&new->list, &thread->comm_list);
|
||||
|
||||
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
|
||||
thread->dead = true;
|
||||
}
|
||||
|
||||
int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
|
||||
int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
|
||||
bool exec);
|
||||
static inline int thread__set_comm(struct thread *thread, const char *comm,
|
||||
u64 timestamp)
|
||||
{
|
||||
return __thread__set_comm(thread, comm, timestamp, false);
|
||||
}
|
||||
|
||||
int thread__comm_len(struct thread *thread);
|
||||
struct comm *thread__comm(const struct thread *thread);
|
||||
struct comm *thread__exec_comm(const struct thread *thread);
|
||||
const char *thread__comm_str(const struct thread *thread);
|
||||
void thread__insert_map(struct thread *thread, struct map *map);
|
||||
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <limits.h>
|
||||
#include <byteswap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* XXX We need to find a better place for these things...
|
||||
@@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws)
|
||||
ws->ws_col = 80;
|
||||
}
|
||||
|
||||
void set_term_quiet_input(struct termios *old)
|
||||
{
|
||||
struct termios tc;
|
||||
|
||||
tcgetattr(0, old);
|
||||
tc = *old;
|
||||
tc.c_lflag &= ~(ICANON | ECHO);
|
||||
tc.c_cc[VMIN] = 0;
|
||||
tc.c_cc[VTIME] = 0;
|
||||
tcsetattr(0, TCSANOW, &tc);
|
||||
}
|
||||
|
||||
static void set_tracing_events_path(const char *mountpoint)
|
||||
{
|
||||
snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#include <api/fs/debugfs.h>
|
||||
#include <termios.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <termios.h>
|
||||
|
||||
extern const char *graph_line;
|
||||
extern const char *graph_dotted_line;
|
||||
@@ -308,6 +309,7 @@ extern unsigned int page_size;
|
||||
extern int cacheline_size;
|
||||
|
||||
void get_term_dimensions(struct winsize *ws);
|
||||
void set_term_quiet_input(struct termios *old);
|
||||
|
||||
struct parse_tag {
|
||||
char tag;
|
||||
|
||||
Reference in New Issue
Block a user