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