Commit f373da34 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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