perf/core improvements and fixes:
. Add an option in 'perf script' to print the source line number, from Adrian Hunter . Add --header/--header-only options to 'script' and 'report', the default is not tho show the header info, but as this has been the default for some time, leave a single line explaining how to obtain that information, from Jiri Olsa. . Fix symoff printing in callchains in 'perf script', from Adrian Hunter. . Assorted mmap_pages handling fixes, from Adrian Hunter. . Fix summary percentage when processing files in 'perf trace', fom David Ahern. . Handle old kernels where the "raw_syscalls" tracepoints were called plan "syscalls", in 'perf trace', from David Ahern. . Several man pages typo fixes from Dongsheng Yang. . Add '-v' option to 'perf kvm', from Dongsheng Yang. . Make perf kvm diff support --guestmount, from Dongsheng Yang. . Get rid of several die() calls in libtraceevent, from Namhyung Kim. . Use basename() in a more robust way, to avoid problems related to different system library implementations for that function, from Stephane Eranian. . Remove open coded management of short_name_allocated member, from Adrian Hunter . Several cleanups in the "dso" methods, constifying some parameters and renaming some fields to clarify its purpose. . Add per-feature check flags, fixing libunwind related build problems on some architectures, from Jean Pihet. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQIcBAABAgAGBQJSp3iNAAoJENZQFvNTUqpA0oUP/3bw/cNRuEKkBZ50591/ZC3M QIg9qYowHW7rDU1gogmiLygeBHXd+IcsHM6Q5ZB8HpWjEv3WBPm6BKm36w6PFhWl Gtx+UicASkRO34n+9IV3X9JY1BQMAa0UgcsZuVl6WJRwdUmMoXwMM4wbP8kI+96z iARqBxKem3Hxoc4NBiY0UBoG91uCk5OQaetStZwmxgqoTAc9EyQ4O9JwAZN9B2RA gHBFmrDKAgBRuk8O+zg3SKx/xkxK7PKVhu0C5QvUarmfXmbEg27iA5GaC38DtT29 ogLwIUpbeRV8pTNzCpJjsdzgj7mbfuOzIVOEsnuj/P0C9ky4dUnwxXGwuwVcY0bP sLb6scTqzgboFJDA52Z9/11XuOLPG9DPS2avGC364Xqdm2zIPP/GLsrGOmJFzEUj dxNfgxyQQqLuf0Coc0kQsFMhIoWaZPb3hAviQZz4y85D5itbRVn6F48qHtfGPlLa jVlKgBiw8oEQ1z+KratYDiDfI8hmJtgeNuniBaYqkQqJRcb0YE2BR8FphJ9bT4nl FsgZd0JszQbr83uLmhuV34De6v5zQCRkF20cGV4c64R0ZCwSNvPv84t4zWcbHBig fEH3vmmfMJTyt6rIcDO3NnacNggF4mBz4roRcGJjI2JetUrdObGElEfpJT/+tx68 NK0sGmgopaRtlBAUZ5dS =0wIi -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: * Add an option in 'perf script' to print the source line number, from Adrian Hunter * Add --header/--header-only options to 'script' and 'report', the default is not tho show the header info, but as this has been the default for some time, leave a single line explaining how to obtain that information, from Jiri Olsa. * Fix symoff printing in callchains in 'perf script', from Adrian Hunter. * Assorted mmap_pages handling fixes, from Adrian Hunter. * Fix summary percentage when processing files in 'perf trace', from David Ahern. * Handle old kernels where the "raw_syscalls" tracepoints were called plan "syscalls", in 'perf trace', from David Ahern. * Several man pages typo fixes from Dongsheng Yang. * Add '-v' option to 'perf kvm', from Dongsheng Yang. * Make perf kvm diff support --guestmount, from Dongsheng Yang. * Get rid of several die() calls in libtraceevent, from Namhyung Kim. * Use basename() in a more robust way, to avoid problems related to different system library implementations for that function, from Stephane Eranian. * Remove open coded management of short_name_allocated member, from Adrian Hunter * Several cleanups in the "dso" methods, constifying some parameters and renaming some fields to clarify its purpose. (Arnaldo Carvalho de Melo.) * Add per-feature check flags, fixing libunwind related build problems on some architectures, from Jean Pihet. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
813932149e
|
@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
|
|||
struct print_arg *farg;
|
||||
enum event_type type;
|
||||
char *token;
|
||||
const char *test;
|
||||
int i;
|
||||
|
||||
arg->type = PRINT_FUNC;
|
||||
|
@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
|
|||
}
|
||||
|
||||
type = process_arg(event, farg, &token);
|
||||
if (i < (func->nr_args - 1))
|
||||
test = ",";
|
||||
else
|
||||
test = ")";
|
||||
|
||||
if (test_type_token(type, token, EVENT_DELIM, test)) {
|
||||
free_arg(farg);
|
||||
free_token(token);
|
||||
return EVENT_ERROR;
|
||||
if (i < (func->nr_args - 1)) {
|
||||
if (type != EVENT_DELIM || strcmp(token, ",") != 0) {
|
||||
warning("Error: function '%s()' expects %d arguments but event %s only uses %d",
|
||||
func->name, func->nr_args,
|
||||
event->name, i + 1);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if (type != EVENT_DELIM || strcmp(token, ")") != 0) {
|
||||
warning("Error: function '%s()' only expects %d arguments but event %s has more",
|
||||
func->name, func->nr_args, event->name);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
*next_arg = farg;
|
||||
|
@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
|
|||
*tok = token;
|
||||
|
||||
return type;
|
||||
|
||||
err:
|
||||
free_arg(farg);
|
||||
free_token(token);
|
||||
return EVENT_ERROR;
|
||||
}
|
||||
|
||||
static enum event_type
|
||||
|
|
|
@ -860,7 +860,7 @@ int pevent_event_filtered(struct event_filter *filter,
|
|||
|
||||
void pevent_filter_reset(struct event_filter *filter);
|
||||
|
||||
void pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
int pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
enum filter_trivial_type type);
|
||||
|
||||
void pevent_filter_free(struct event_filter *filter);
|
||||
|
|
|
@ -182,7 +182,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
|
|||
{
|
||||
struct event_filter *filter;
|
||||
|
||||
filter = malloc_or_die(sizeof(*filter));
|
||||
filter = malloc(sizeof(*filter));
|
||||
if (filter == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(filter, 0, sizeof(*filter));
|
||||
filter->pevent = pevent;
|
||||
pevent_ref(pevent);
|
||||
|
@ -242,15 +245,19 @@ static void free_arg(struct filter_arg *arg)
|
|||
free(arg);
|
||||
}
|
||||
|
||||
static void add_event(struct event_list **events,
|
||||
static int add_event(struct event_list **events,
|
||||
struct event_format *event)
|
||||
{
|
||||
struct event_list *list;
|
||||
|
||||
list = malloc_or_die(sizeof(*list));
|
||||
list = malloc(sizeof(*list));
|
||||
if (list == NULL)
|
||||
return -1;
|
||||
|
||||
list->next = *events;
|
||||
*events = list;
|
||||
list->event = event;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event_match(struct event_format *event,
|
||||
|
@ -273,6 +280,7 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|||
regex_t ereg;
|
||||
regex_t sreg;
|
||||
int match = 0;
|
||||
int fail = 0;
|
||||
char *reg;
|
||||
int ret;
|
||||
int i;
|
||||
|
@ -307,7 +315,10 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|||
event = pevent->events[i];
|
||||
if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
|
||||
match = 1;
|
||||
add_event(events, event);
|
||||
if (add_event(events, event) < 0) {
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,6 +328,8 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|||
|
||||
if (!match)
|
||||
return -1;
|
||||
if (fail)
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -349,8 +362,11 @@ create_arg_item(struct event_format *event, const char *token,
|
|||
arg->value.type =
|
||||
type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
|
||||
arg->value.str = strdup(token);
|
||||
if (!arg->value.str)
|
||||
die("malloc string");
|
||||
if (!arg->value.str) {
|
||||
free_arg(arg);
|
||||
show_error(error_str, "failed to allocate string filter arg");
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case EVENT_ITEM:
|
||||
/* if it is a number, then convert it */
|
||||
|
@ -1210,7 +1226,13 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|||
else
|
||||
len = strlen(filter_str);
|
||||
|
||||
this_event = malloc_or_die(len + 1);
|
||||
this_event = malloc(len + 1);
|
||||
if (this_event == NULL) {
|
||||
show_error(error_str, "Memory allocation failure");
|
||||
/* This can only happen when events is NULL, but still */
|
||||
free_events(events);
|
||||
return -1;
|
||||
}
|
||||
memcpy(this_event, filter_str, len);
|
||||
this_event[len] = 0;
|
||||
|
||||
|
@ -1482,8 +1504,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
|
|||
* @type: remove only true, false, or both
|
||||
*
|
||||
* Removes filters that only contain a TRUE or FALES boolean arg.
|
||||
*
|
||||
* Returns 0 on success and -1 if there was a problem.
|
||||
*/
|
||||
void pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
int pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
enum filter_trivial_type type)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
|
@ -1492,13 +1516,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
|
|||
int i;
|
||||
|
||||
if (!filter->filters)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Two steps, first get all ids with trivial filters.
|
||||
* then remove those ids.
|
||||
*/
|
||||
for (i = 0; i < filter->filters; i++) {
|
||||
int *new_ids;
|
||||
|
||||
filter_type = &filter->event_filters[i];
|
||||
if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
|
||||
continue;
|
||||
|
@ -1513,19 +1539,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
|
|||
break;
|
||||
}
|
||||
|
||||
ids = realloc(ids, sizeof(*ids) * (count + 1));
|
||||
if (!ids)
|
||||
die("Can't allocate ids");
|
||||
new_ids = realloc(ids, sizeof(*ids) * (count + 1));
|
||||
if (!new_ids) {
|
||||
free(ids);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ids = new_ids;
|
||||
ids[count++] = filter_type->event_id;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
pevent_filter_remove_event(filter, ids[i]);
|
||||
|
||||
free(ids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,9 +12,9 @@ SYNOPSIS
|
|||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This command runs runs perf-buildid-list --with-hits, and collects the files
|
||||
with the buildids found so that analysis of perf.data contents can be possible
|
||||
on another machine.
|
||||
This command runs perf-buildid-list --with-hits, and collects the files with the
|
||||
buildids found so that analysis of perf.data contents can be possible on another
|
||||
machine.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
|
|
@ -10,9 +10,9 @@ SYNOPSIS
|
|||
[verse]
|
||||
'perf kvm' [--host] [--guest] [--guestmount=<path>
|
||||
[--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
|
||||
{top|record|report|diff|buildid-list}
|
||||
{top|record|report|diff|buildid-list} [<options>]
|
||||
'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
|
||||
| --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
|
||||
| --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} [<options>]
|
||||
'perf kvm stat [record|report|live] [<options>]
|
||||
|
||||
DESCRIPTION
|
||||
|
@ -93,6 +93,9 @@ OPTIONS
|
|||
kernel module information. Users copy it out from guest os.
|
||||
--guestvmlinux=<path>::
|
||||
Guest os kernel vmlinux.
|
||||
-v::
|
||||
--verbose::
|
||||
Be more verbose (show counter open errors, etc).
|
||||
|
||||
STAT REPORT OPTIONS
|
||||
-------------------
|
||||
|
|
|
@ -237,6 +237,15 @@ OPTIONS
|
|||
Do not show entries which have an overhead under that percent.
|
||||
(Default: 0).
|
||||
|
||||
--header::
|
||||
Show header information in the perf.data file. This includes
|
||||
various information like hostname, OS and perf version, cpu/mem
|
||||
info, perf command line, event list and so on. Currently only
|
||||
--stdio output supports this feature.
|
||||
|
||||
--header-only::
|
||||
Show only perf.data header (forces --stdio).
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-stat[1], linkperf:perf-annotate[1]
|
||||
|
|
|
@ -115,7 +115,7 @@ OPTIONS
|
|||
-f::
|
||||
--fields::
|
||||
Comma separated list of fields to print. Options are:
|
||||
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff.
|
||||
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline.
|
||||
Field list can be prepended with the type, trace, sw or hw,
|
||||
to indicate to which event type the field list applies.
|
||||
e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
|
||||
|
@ -209,6 +209,12 @@ OPTIONS
|
|||
--show-mmap-events
|
||||
Display mmap related events (e.g. MMAP, MMAP2).
|
||||
|
||||
--header
|
||||
Show perf.data header.
|
||||
|
||||
--header-only
|
||||
Show only perf.data header.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-record[1], linkperf:perf-script-perl[1],
|
||||
|
|
|
@ -373,7 +373,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
|
||||
if (argc) {
|
||||
/*
|
||||
* Special case: if there's an argument left then assume tha
|
||||
* Special case: if there's an argument left then assume that
|
||||
* it's a symbol filter:
|
||||
*/
|
||||
if (argc > 1)
|
||||
|
|
|
@ -1000,8 +1000,7 @@ static int data_init(int argc, const char **argv)
|
|||
data__files_cnt = argc;
|
||||
use_default = false;
|
||||
}
|
||||
} else if (symbol_conf.default_guest_vmlinux_name ||
|
||||
symbol_conf.default_guest_kallsyms) {
|
||||
} else if (perf_guest) {
|
||||
defaults[0] = "perf.data.host";
|
||||
defaults[1] = "perf.data.guest";
|
||||
}
|
||||
|
|
|
@ -1232,7 +1232,7 @@ static int read_events(struct perf_kvm_stat *kvm)
|
|||
.ordered_samples = true,
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.path = kvm->file_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
|
@ -1690,6 +1690,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
"file", "file saving guest os /proc/kallsyms"),
|
||||
OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
|
||||
"file", "file saving guest os /proc/modules"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show counter open errors, etc)"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -1711,12 +1713,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
perf_guest = 1;
|
||||
|
||||
if (!file_name) {
|
||||
if (perf_host && !perf_guest)
|
||||
file_name = strdup("perf.data.host");
|
||||
else if (!perf_host && perf_guest)
|
||||
file_name = strdup("perf.data.guest");
|
||||
else
|
||||
file_name = strdup("perf.data.kvm");
|
||||
file_name = get_filename_for_perf_kvm();
|
||||
|
||||
if (!file_name) {
|
||||
pr_err("Failed to allocate memory for filename\n");
|
||||
|
|
|
@ -224,7 +224,7 @@ try_again:
|
|||
"Consider increasing "
|
||||
"/proc/sys/kernel/perf_event_mlock_kb,\n"
|
||||
"or try again with a smaller value of -m/--mmap_pages.\n"
|
||||
"(current value: %d)\n", opts->mmap_pages);
|
||||
"(current value: %u)\n", opts->mmap_pages);
|
||||
rc = -errno;
|
||||
} else {
|
||||
pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
|
||||
|
|
|
@ -49,6 +49,8 @@ struct perf_report {
|
|||
bool show_threads;
|
||||
bool inverted_callchain;
|
||||
bool mem_mode;
|
||||
bool header;
|
||||
bool header_only;
|
||||
int max_stack;
|
||||
struct perf_read_values show_threads_values;
|
||||
const char *pretty_printing_style;
|
||||
|
@ -514,9 +516,6 @@ static int __cmd_report(struct perf_report *rep)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (use_browser <= 0)
|
||||
perf_session__fprintf_info(session, stdout, rep->show_full_info);
|
||||
|
||||
if (rep->show_threads)
|
||||
perf_read_values_init(&rep->show_threads_values);
|
||||
|
||||
|
@ -820,6 +819,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
|
||||
OPT_BOOLEAN(0, "stdio", &report.use_stdio,
|
||||
"Use the stdio interface"),
|
||||
OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
|
||||
OPT_BOOLEAN(0, "header-only", &report.header_only,
|
||||
"Show only data header."),
|
||||
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
|
||||
"sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
|
||||
" dso_to, dso_from, symbol_to, symbol_from, mispredict,"
|
||||
|
@ -963,6 +965,10 @@ repeat:
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* Force tty output for header output. */
|
||||
if (report.header || report.header_only)
|
||||
use_browser = 0;
|
||||
|
||||
if (strcmp(input_name, "-") != 0)
|
||||
setup_browser(true);
|
||||
else {
|
||||
|
@ -970,6 +976,16 @@ repeat:
|
|||
perf_hpp__init();
|
||||
}
|
||||
|
||||
if (report.header || report.header_only) {
|
||||
perf_session__fprintf_info(session, stdout,
|
||||
report.show_full_info);
|
||||
if (report.header_only)
|
||||
return 0;
|
||||
} else if (use_browser == 0) {
|
||||
fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
|
||||
stdout);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only in the TUI browser we are doing integrated annotation,
|
||||
* so don't allocate extra space that won't be used in the stdio
|
||||
|
|
|
@ -43,6 +43,7 @@ enum perf_output_field {
|
|||
PERF_OUTPUT_DSO = 1U << 9,
|
||||
PERF_OUTPUT_ADDR = 1U << 10,
|
||||
PERF_OUTPUT_SYMOFFSET = 1U << 11,
|
||||
PERF_OUTPUT_SRCLINE = 1U << 12,
|
||||
};
|
||||
|
||||
struct output_option {
|
||||
|
@ -61,6 +62,7 @@ struct output_option {
|
|||
{.str = "dso", .field = PERF_OUTPUT_DSO},
|
||||
{.str = "addr", .field = PERF_OUTPUT_ADDR},
|
||||
{.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
|
||||
{.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
|
||||
};
|
||||
|
||||
/* default set to maintain compatibility with current format */
|
||||
|
@ -210,6 +212,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
|||
"to DSO.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
|
||||
pr_err("Display of source line number requested but sample IP is not\n"
|
||||
"selected. Hence, no address to lookup the source line number.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
|
||||
perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
|
||||
|
@ -245,6 +252,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
|
|||
|
||||
if (PRINT_FIELD(SYMOFFSET))
|
||||
output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
|
||||
|
||||
if (PRINT_FIELD(SRCLINE))
|
||||
output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1484,6 +1494,8 @@ static int have_cmd(int argc, const char **argv)
|
|||
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;
|
||||
char *rec_script_path = NULL;
|
||||
char *rep_script_path = NULL;
|
||||
struct perf_session *session;
|
||||
|
@ -1522,6 +1534,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
|
||||
"do various checks like samples ordering and lost events"),
|
||||
OPT_BOOLEAN(0, "header", &header, "Show data header."),
|
||||
OPT_BOOLEAN(0, "header-only", &header_only, "Show only data header."),
|
||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"file", "vmlinux pathname"),
|
||||
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
|
||||
|
@ -1738,6 +1752,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (header || header_only) {
|
||||
perf_session__fprintf_info(session, stdout, show_full_info);
|
||||
if (header_only)
|
||||
return 0;
|
||||
}
|
||||
|
||||
script.session = session;
|
||||
|
||||
if (cpu_list) {
|
||||
|
@ -1745,9 +1765,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!script_name && !generate_script_lang)
|
||||
perf_session__fprintf_info(session, stdout, show_full_info);
|
||||
|
||||
if (!no_callchain)
|
||||
symbol_conf.use_callchain = true;
|
||||
else
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "util/thread_map.h"
|
||||
#include "util/stat.h"
|
||||
#include "trace-event.h"
|
||||
#include "util/parse-events.h"
|
||||
|
||||
#include <libaudit.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -173,6 +174,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void
|
|||
{
|
||||
struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
|
||||
|
||||
/* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
|
||||
if (evsel == NULL)
|
||||
evsel = perf_evsel__newtp("syscalls", direction);
|
||||
|
||||
if (evsel) {
|
||||
if (perf_evsel__init_syscall_tp(evsel, handler))
|
||||
goto out_delete;
|
||||
|
@ -1765,8 +1770,10 @@ static int trace__process_sample(struct perf_tool *tool,
|
|||
if (!trace->full_time && trace->base_time == 0)
|
||||
trace->base_time = sample->time;
|
||||
|
||||
if (handler)
|
||||
if (handler) {
|
||||
++trace->nr_events;
|
||||
handler(trace, evsel, sample);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -1801,10 +1808,11 @@ static int trace__record(int argc, const char **argv)
|
|||
"-R",
|
||||
"-m", "1024",
|
||||
"-c", "1",
|
||||
"-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
|
||||
"-e",
|
||||
};
|
||||
|
||||
rec_argc = ARRAY_SIZE(record_args) + argc;
|
||||
/* +1 is for the event string below */
|
||||
rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
|
||||
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||
|
||||
if (rec_argv == NULL)
|
||||
|
@ -1813,6 +1821,17 @@ static int trace__record(int argc, const char **argv)
|
|||
for (i = 0; i < ARRAY_SIZE(record_args); i++)
|
||||
rec_argv[i] = record_args[i];
|
||||
|
||||
/* event string may be different for older kernels - e.g., RHEL6 */
|
||||
if (is_valid_tracepoint("raw_syscalls:sys_enter"))
|
||||
rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
|
||||
else if (is_valid_tracepoint("syscalls:sys_enter"))
|
||||
rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
|
||||
else {
|
||||
pr_err("Neither raw_syscalls nor syscalls events exist.\n");
|
||||
return -1;
|
||||
}
|
||||
i++;
|
||||
|
||||
for (j = 0; j < (unsigned int)argc; j++, i++)
|
||||
rec_argv[i] = argv[j];
|
||||
|
||||
|
@ -2048,6 +2067,10 @@ static int trace__replay(struct trace *trace)
|
|||
|
||||
evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
|
||||
"raw_syscalls:sys_enter");
|
||||
/* older kernels have syscalls tp versus raw_syscalls */
|
||||
if (evsel == NULL)
|
||||
evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
|
||||
"syscalls:sys_enter");
|
||||
if (evsel == NULL) {
|
||||
pr_err("Data file does not have raw_syscalls:sys_enter event\n");
|
||||
goto out;
|
||||
|
@ -2061,6 +2084,9 @@ static int trace__replay(struct trace *trace)
|
|||
|
||||
evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
|
||||
"raw_syscalls:sys_exit");
|
||||
if (evsel == NULL)
|
||||
evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
|
||||
"syscalls:sys_exit");
|
||||
if (evsel == NULL) {
|
||||
pr_err("Data file does not have raw_syscalls:sys_exit event\n");
|
||||
goto out;
|
||||
|
|
|
@ -36,6 +36,30 @@ ifeq ($(ARCH),arm)
|
|||
LIBUNWIND_LIBS = -lunwind -lunwind-arm
|
||||
endif
|
||||
|
||||
ifeq ($(LIBUNWIND_LIBS),)
|
||||
NO_LIBUNWIND := 1
|
||||
else
|
||||
#
|
||||
# For linking with debug library, run like:
|
||||
#
|
||||
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
|
||||
#
|
||||
ifdef LIBUNWIND_DIR
|
||||
LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
|
||||
LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
|
||||
endif
|
||||
LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
|
||||
|
||||
# Set per-feature check compilation flags
|
||||
FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
|
||||
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
|
||||
# and the flags for the test-all case
|
||||
FEATURE_CHECK_CFLAGS-all += $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-all += $(LIBUNWIND_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(NO_PERF_REGS),0)
|
||||
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
|
||||
endif
|
||||
|
@ -102,7 +126,7 @@ endif
|
|||
|
||||
feature_check = $(eval $(feature_check_code))
|
||||
define feature_check_code
|
||||
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
endef
|
||||
|
||||
feature_set = $(eval $(feature_set_code))
|
||||
|
@ -305,21 +329,7 @@ ifndef NO_LIBELF
|
|||
endif # NO_DWARF
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifeq ($(LIBUNWIND_LIBS),)
|
||||
NO_LIBUNWIND := 1
|
||||
endif
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
#
|
||||
# For linking with debug library, run like:
|
||||
#
|
||||
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
|
||||
#
|
||||
ifdef LIBUNWIND_DIR
|
||||
LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
|
||||
LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
|
||||
endif
|
||||
|
||||
ifneq ($(feature-libunwind), 1)
|
||||
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
|
||||
NO_LIBUNWIND := 1
|
||||
|
@ -334,14 +344,12 @@ ifndef NO_LIBUNWIND
|
|||
# non-ARM has no dwarf_find_debug_frame() function:
|
||||
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
|
||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||
CFLAGS += $(LIBUNWIND_CFLAGS)
|
||||
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
||||
CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
|
||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||
CFLAGS += $(LIBUNWIND_CFLAGS)
|
||||
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
||||
endif # ifneq ($(feature-libunwind), 1)
|
||||
endif
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
|
|
|
@ -32,12 +32,12 @@ CC := $(CC) -MD
|
|||
|
||||
all: $(FILES)
|
||||
|
||||
BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
|
||||
BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $@.c $(LDFLAGS)
|
||||
|
||||
###############################
|
||||
|
||||
test-all:
|
||||
$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
|
||||
$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
|
||||
|
||||
test-hello:
|
||||
$(BUILD)
|
||||
|
@ -70,10 +70,10 @@ test-libnuma:
|
|||
$(BUILD) -lnuma
|
||||
|
||||
test-libunwind:
|
||||
$(BUILD) $(LIBUNWIND_LIBS) -lelf
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libunwind-debug-frame:
|
||||
$(BUILD) $(LIBUNWIND_LIBS) -lelf
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libaudit:
|
||||
$(BUILD) -laudit
|
||||
|
|
|
@ -900,7 +900,7 @@ fallback:
|
|||
* cache, or is just a kallsyms file, well, lets hope that this
|
||||
* DSO is the same as when 'perf record' ran.
|
||||
*/
|
||||
filename = dso->long_name;
|
||||
filename = (char *)dso->long_name;
|
||||
snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
|
||||
symbol_conf.symfs, filename);
|
||||
free_filename = false;
|
||||
|
|
|
@ -89,7 +89,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
|
|||
return raw - build_id;
|
||||
}
|
||||
|
||||
char *dso__build_id_filename(struct dso *dso, char *bf, size_t size)
|
||||
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
|
||||
{
|
||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
|
|||
struct dso;
|
||||
|
||||
int build_id__sprintf(const u8 *build_id, int len, char *bf);
|
||||
char *dso__build_id_filename(struct dso *dso, char *bf, size_t size);
|
||||
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
|
||||
|
||||
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
|
||||
struct perf_sample *sample, struct perf_evsel *evsel,
|
||||
|
|
|
@ -28,8 +28,8 @@ char dso__symtab_origin(const struct dso *dso)
|
|||
return origin[dso->symtab_type];
|
||||
}
|
||||
|
||||
int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *file, size_t size)
|
||||
int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *filename, size_t size)
|
||||
{
|
||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||
int ret = 0;
|
||||
|
@ -38,36 +38,36 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
|||
case DSO_BINARY_TYPE__DEBUGLINK: {
|
||||
char *debuglink;
|
||||
|
||||
strncpy(file, dso->long_name, size);
|
||||
debuglink = file + dso->long_name_len;
|
||||
while (debuglink != file && *debuglink != '/')
|
||||
strncpy(filename, dso->long_name, size);
|
||||
debuglink = filename + dso->long_name_len;
|
||||
while (debuglink != filename && *debuglink != '/')
|
||||
debuglink--;
|
||||
if (*debuglink == '/')
|
||||
debuglink++;
|
||||
filename__read_debuglink(dso->long_name, debuglink,
|
||||
size - (debuglink - file));
|
||||
size - (debuglink - filename));
|
||||
}
|
||||
break;
|
||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
||||
/* skip the locally configured cache if a symfs is given */
|
||||
if (symbol_conf.symfs[0] ||
|
||||
(dso__build_id_filename(dso, file, size) == NULL))
|
||||
(dso__build_id_filename(dso, filename, size) == NULL))
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
|
||||
snprintf(file, size, "%s/usr/lib/debug%s.debug",
|
||||
snprintf(filename, size, "%s/usr/lib/debug%s.debug",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
|
||||
snprintf(file, size, "%s/usr/lib/debug%s",
|
||||
snprintf(filename, size, "%s/usr/lib/debug%s",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
|
||||
{
|
||||
char *last_slash;
|
||||
const char *last_slash;
|
||||
size_t len;
|
||||
size_t dir_size;
|
||||
|
||||
|
@ -75,14 +75,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
|||
while (last_slash != dso->long_name && *last_slash != '/')
|
||||
last_slash--;
|
||||
|
||||
len = scnprintf(file, size, "%s", symbol_conf.symfs);
|
||||
len = scnprintf(filename, size, "%s", symbol_conf.symfs);
|
||||
dir_size = last_slash - dso->long_name + 2;
|
||||
if (dir_size > (size - len)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
len += scnprintf(file + len, dir_size, "%s", dso->long_name);
|
||||
len += scnprintf(file + len , size - len, ".debug%s",
|
||||
len += scnprintf(filename + len, dir_size, "%s", dso->long_name);
|
||||
len += scnprintf(filename + len , size - len, ".debug%s",
|
||||
last_slash);
|
||||
break;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
|||
build_id__sprintf(dso->build_id,
|
||||
sizeof(dso->build_id),
|
||||
build_id_hex);
|
||||
snprintf(file, size,
|
||||
snprintf(filename, size,
|
||||
"%s/usr/lib/debug/.build-id/%.2s/%s.debug",
|
||||
symbol_conf.symfs, build_id_hex, build_id_hex + 2);
|
||||
break;
|
||||
|
@ -104,23 +104,23 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
|||
case DSO_BINARY_TYPE__VMLINUX:
|
||||
case DSO_BINARY_TYPE__GUEST_VMLINUX:
|
||||
case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
|
||||
snprintf(file, size, "%s%s",
|
||||
snprintf(filename, size, "%s%s",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__GUEST_KMODULE:
|
||||
snprintf(file, size, "%s%s%s", symbol_conf.symfs,
|
||||
snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
|
||||
root_dir, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
|
||||
snprintf(file, size, "%s%s", symbol_conf.symfs,
|
||||
snprintf(filename, size, "%s%s", symbol_conf.symfs,
|
||||
dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__KCORE:
|
||||
case DSO_BINARY_TYPE__GUEST_KCORE:
|
||||
snprintf(file, size, "%s", dso->long_name);
|
||||
snprintf(filename, size, "%s", dso->long_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -200,11 +200,10 @@ dso_cache__free(struct rb_root *root)
|
|||
}
|
||||
}
|
||||
|
||||
static struct dso_cache*
|
||||
dso_cache__find(struct rb_root *root, u64 offset)
|
||||
static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 offset)
|
||||
{
|
||||
struct rb_node **p = &root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct rb_node * const *p = &root->rb_node;
|
||||
const struct rb_node *parent = NULL;
|
||||
struct dso_cache *cache;
|
||||
|
||||
while (*p != NULL) {
|
||||
|
@ -379,32 +378,63 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
|
|||
* processing we had no idea this was the kernel dso.
|
||||
*/
|
||||
if (dso != NULL) {
|
||||
dso__set_short_name(dso, short_name);
|
||||
dso__set_short_name(dso, short_name, false);
|
||||
dso->kernel = dso_type;
|
||||
}
|
||||
|
||||
return dso;
|
||||
}
|
||||
|
||||
void dso__set_long_name(struct dso *dso, char *name)
|
||||
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
|
||||
{
|
||||
if (name == NULL)
|
||||
return;
|
||||
dso->long_name = name;
|
||||
dso->long_name_len = strlen(name);
|
||||
|
||||
if (dso->long_name_allocated)
|
||||
free((char *)dso->long_name);
|
||||
|
||||
dso->long_name = name;
|
||||
dso->long_name_len = strlen(name);
|
||||
dso->long_name_allocated = name_allocated;
|
||||
}
|
||||
|
||||
void dso__set_short_name(struct dso *dso, const char *name)
|
||||
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
|
||||
{
|
||||
if (name == NULL)
|
||||
return;
|
||||
dso->short_name = name;
|
||||
dso->short_name_len = strlen(name);
|
||||
|
||||
if (dso->short_name_allocated)
|
||||
free((char *)dso->short_name);
|
||||
|
||||
dso->short_name = name;
|
||||
dso->short_name_len = strlen(name);
|
||||
dso->short_name_allocated = name_allocated;
|
||||
}
|
||||
|
||||
static void dso__set_basename(struct dso *dso)
|
||||
{
|
||||
dso__set_short_name(dso, basename(dso->long_name));
|
||||
/*
|
||||
* basename() may modify path buffer, so we must pass
|
||||
* a copy.
|
||||
*/
|
||||
char *base, *lname = strdup(dso->long_name);
|
||||
|
||||
if (!lname)
|
||||
return;
|
||||
|
||||
/*
|
||||
* basename() may return a pointer to internal
|
||||
* storage which is reused in subsequent calls
|
||||
* so copy the result.
|
||||
*/
|
||||
base = strdup(basename(lname));
|
||||
|
||||
free(lname);
|
||||
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
dso__set_short_name(dso, base, true);
|
||||
}
|
||||
|
||||
int dso__name_len(const struct dso *dso)
|
||||
|
@ -439,8 +469,8 @@ struct dso *dso__new(const char *name)
|
|||
if (dso != NULL) {
|
||||
int i;
|
||||
strcpy(dso->name, name);
|
||||
dso__set_long_name(dso, dso->name);
|
||||
dso__set_short_name(dso, dso->name);
|
||||
dso__set_long_name(dso, dso->name, false);
|
||||
dso__set_short_name(dso, dso->name, false);
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
|
||||
dso->cache = RB_ROOT;
|
||||
|
@ -465,13 +495,23 @@ void dso__delete(struct dso *dso)
|
|||
int i;
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
symbols__delete(&dso->symbols[i]);
|
||||
if (dso->sname_alloc)
|
||||
|
||||
if (dso->short_name_allocated) {
|
||||
free((char *)dso->short_name);
|
||||
if (dso->lname_alloc)
|
||||
free(dso->long_name);
|
||||
dso->short_name = NULL;
|
||||
dso->short_name_allocated = false;
|
||||
}
|
||||
|
||||
if (dso->long_name_allocated) {
|
||||
free((char *)dso->long_name);
|
||||
dso->long_name = NULL;
|
||||
dso->long_name_allocated = false;
|
||||
}
|
||||
|
||||
dso_cache__free(&dso->cache);
|
||||
dso__free_a2l(dso);
|
||||
free(dso->symsrc_filename);
|
||||
dso->symsrc_filename = NULL;
|
||||
free(dso);
|
||||
}
|
||||
|
||||
|
@ -546,7 +586,7 @@ void dsos__add(struct list_head *head, struct dso *dso)
|
|||
list_add_tail(&dso->node, head);
|
||||
}
|
||||
|
||||
struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short)
|
||||
struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
|
||||
{
|
||||
struct dso *pos;
|
||||
|
||||
|
|
|
@ -89,14 +89,14 @@ struct dso {
|
|||
u8 has_srcline:1;
|
||||
u8 hit:1;
|
||||
u8 annotate_warned:1;
|
||||
u8 sname_alloc:1;
|
||||
u8 lname_alloc:1;
|
||||
u8 short_name_allocated:1;
|
||||
u8 long_name_allocated:1;
|
||||
u8 sorted_by_name;
|
||||
u8 loaded;
|
||||
u8 rel;
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
const char *short_name;
|
||||
char *long_name;
|
||||
const char *long_name;
|
||||
u16 long_name_len;
|
||||
u16 short_name_len;
|
||||
char name[0];
|
||||
|
@ -110,8 +110,8 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type)
|
|||
struct dso *dso__new(const char *name);
|
||||
void dso__delete(struct dso *dso);
|
||||
|
||||
void dso__set_short_name(struct dso *dso, const char *name);
|
||||
void dso__set_long_name(struct dso *dso, char *name);
|
||||
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated);
|
||||
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated);
|
||||
|
||||
int dso__name_len(const struct dso *dso);
|
||||
|
||||
|
@ -128,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso,
|
|||
int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
|
||||
|
||||
char dso__symtab_origin(const struct dso *dso);
|
||||
int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *file, size_t size);
|
||||
int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *filename, size_t size);
|
||||
|
||||
int dso__data_fd(struct dso *dso, struct machine *machine);
|
||||
ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
|
||||
|
@ -143,7 +143,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
|
|||
const char *short_name, int dso_type);
|
||||
|
||||
void dsos__add(struct list_head *head, struct dso *dso);
|
||||
struct dso *dsos__find(struct list_head *head, const char *name,
|
||||
struct dso *dsos__find(const struct list_head *head, const char *name,
|
||||
bool cmp_short);
|
||||
struct dso *__dsos__findnew(struct list_head *head, const char *name);
|
||||
bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
|
||||
|
|
|
@ -732,11 +732,13 @@ static long parse_pages_arg(const char *str, unsigned long min,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((pages == 0) && (min == 0)) {
|
||||
if (pages == 0 && min == 0) {
|
||||
/* leave number of pages at 0 */
|
||||
} else if (pages < (1UL << 31) && !is_power_of_2(pages)) {
|
||||
} else if (!is_power_of_2(pages)) {
|
||||
/* round pages up to next power of 2 */
|
||||
pages = next_pow2(pages);
|
||||
pages = next_pow2_l(pages);
|
||||
if (!pages)
|
||||
return -EINVAL;
|
||||
pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n",
|
||||
pages * page_size, pages);
|
||||
}
|
||||
|
@ -754,7 +756,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
|
|||
unsigned long max = UINT_MAX;
|
||||
long pages;
|
||||
|
||||
if (max < SIZE_MAX / page_size)
|
||||
if (max > SIZE_MAX / page_size)
|
||||
max = SIZE_MAX / page_size;
|
||||
|
||||
pages = parse_pages_arg(str, 1, max);
|
||||
|
|
|
@ -177,7 +177,7 @@ perf_header__set_cmdline(int argc, const char **argv)
|
|||
continue; \
|
||||
else
|
||||
|
||||
static int write_buildid(char *name, size_t name_len, u8 *build_id,
|
||||
static int write_buildid(const char *name, size_t name_len, u8 *build_id,
|
||||
pid_t pid, u16 misc, int fd)
|
||||
{
|
||||
int err;
|
||||
|
@ -209,7 +209,7 @@ static int __dsos__write_buildid_table(struct list_head *head,
|
|||
|
||||
dsos__for_each_with_build_id(pos, head) {
|
||||
int err;
|
||||
char *name;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
|
||||
if (!pos->hit)
|
||||
|
@ -387,7 +387,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
|
|||
{
|
||||
bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
|
||||
bool is_vdso = is_vdso_map(dso->short_name);
|
||||
char *name = dso->long_name;
|
||||
const char *name = dso->long_name;
|
||||
char nm[PATH_MAX];
|
||||
|
||||
if (dso__is_kcore(dso)) {
|
||||
|
|
|
@ -763,8 +763,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
|
|||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
dso__set_long_name(map->dso, long_name);
|
||||
map->dso->lname_alloc = 1;
|
||||
dso__set_long_name(map->dso, long_name, true);
|
||||
dso__kernel_module_get_build_id(map->dso, "");
|
||||
}
|
||||
}
|
||||
|
@ -935,8 +934,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
|
|||
if (name == NULL)
|
||||
goto out_problem;
|
||||
|
||||
map->dso->short_name = name;
|
||||
map->dso->sname_alloc = 1;
|
||||
dso__set_short_name(map->dso, name, true);
|
||||
map->end = map->start + event->mmap.len;
|
||||
} else if (is_kernel_mmap) {
|
||||
const char *symbol_name = (event->mmap.filename +
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "strlist.h"
|
||||
#include "vdso.h"
|
||||
#include "build-id.h"
|
||||
#include "util.h"
|
||||
#include <linux/string.h>
|
||||
|
||||
const char *map_type__name[MAP__NR_TYPES] = {
|
||||
|
@ -252,6 +253,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
|
|||
return fprintf(fp, "%s", dsoname);
|
||||
}
|
||||
|
||||
int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
|
||||
FILE *fp)
|
||||
{
|
||||
char *srcline;
|
||||
int ret = 0;
|
||||
|
||||
if (map && map->dso) {
|
||||
srcline = get_srcline(map->dso,
|
||||
map__rip_2objdump(map, addr));
|
||||
if (srcline != SRCLINE_UNKNOWN)
|
||||
ret = fprintf(fp, "%s%s", prefix, srcline);
|
||||
free_srcline(srcline);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* map__rip_2objdump - convert symbol start address to objdump address.
|
||||
* @map: memory map
|
||||
|
|
|
@ -103,6 +103,8 @@ struct map *map__clone(struct map *map);
|
|||
int map__overlap(struct map *l, struct map *r);
|
||||
size_t map__fprintf(struct map *map, FILE *fp);
|
||||
size_t map__fprintf_dsoname(struct map *map, FILE *fp);
|
||||
int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
|
||||
FILE *fp);
|
||||
|
||||
int map__load(struct map *map, symbol_filter_t filter);
|
||||
struct symbol *map__find_symbol(struct map *map,
|
||||
|
|
|
@ -154,7 +154,7 @@ static struct dso *kernel_get_module_dso(const char *module)
|
|||
|
||||
vmlinux_name = symbol_conf.vmlinux_name;
|
||||
if (vmlinux_name) {
|
||||
if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
|
||||
if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0)
|
||||
return NULL;
|
||||
} else {
|
||||
if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
|
||||
|
|
|
@ -1497,6 +1497,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
|
|||
int print_dso = print_opts & PRINT_IP_OPT_DSO;
|
||||
int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
|
||||
int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
|
||||
int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
|
||||
char s = print_oneline ? ' ' : '\t';
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain) {
|
||||
|
@ -1515,6 +1516,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
|
|||
node_al = *al;
|
||||
|
||||
while (stack_depth) {
|
||||
u64 addr = 0;
|
||||
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
if (!node)
|
||||
break;
|
||||
|
@ -1525,10 +1528,13 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
|
|||
if (print_ip)
|
||||
printf("%c%16" PRIx64, s, node->ip);
|
||||
|
||||
if (node->map)
|
||||
addr = node->map->map_ip(node->map, node->ip);
|
||||
|
||||
if (print_sym) {
|
||||
printf(" ");
|
||||
if (print_symoffset) {
|
||||
node_al.addr = node->ip;
|
||||
node_al.addr = addr;
|
||||
node_al.map = node->map;
|
||||
symbol__fprintf_symname_offs(node->sym, &node_al, stdout);
|
||||
} else
|
||||
|
@ -1541,6 +1547,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
|
|||
printf(")");
|
||||
}
|
||||
|
||||
if (print_srcline)
|
||||
map__fprintf_srcline(node->map, addr, "\n ",
|
||||
stdout);
|
||||
|
||||
if (!print_oneline)
|
||||
printf("\n");
|
||||
|
||||
|
@ -1570,6 +1580,9 @@ next:
|
|||
map__fprintf_dsoname(al->map, stdout);
|
||||
printf(")");
|
||||
}
|
||||
|
||||
if (print_srcline)
|
||||
map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ struct perf_session {
|
|||
#define PRINT_IP_OPT_DSO (1<<2)
|
||||
#define PRINT_IP_OPT_SYMOFFSET (1<<3)
|
||||
#define PRINT_IP_OPT_ONELINE (1<<4)
|
||||
#define PRINT_IP_OPT_SRCLINE (1<<5)
|
||||
|
||||
struct perf_tool;
|
||||
|
||||
|
|
|
@ -255,7 +255,7 @@ char *get_srcline(struct dso *dso, unsigned long addr)
|
|||
char *file = NULL;
|
||||
unsigned line = 0;
|
||||
char *srcline;
|
||||
char *dso_name;
|
||||
const char *dso_name;
|
||||
|
||||
if (!dso->has_srcline)
|
||||
return SRCLINE_UNKNOWN;
|
||||
|
|
|
@ -1159,7 +1159,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
|||
dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE;
|
||||
else
|
||||
dso->data_type = DSO_BINARY_TYPE__KCORE;
|
||||
dso__set_long_name(dso, strdup(kcore_filename));
|
||||
dso__set_long_name(dso, strdup(kcore_filename), true);
|
||||
|
||||
close(fd);
|
||||
|
||||
|
@ -1408,7 +1408,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
|
|||
}
|
||||
|
||||
int dso__load_vmlinux(struct dso *dso, struct map *map,
|
||||
const char *vmlinux, symbol_filter_t filter)
|
||||
const char *vmlinux, bool vmlinux_allocated,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
int err = -1;
|
||||
struct symsrc ss;
|
||||
|
@ -1437,7 +1438,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
|
|||
dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
|
||||
else
|
||||
dso->data_type = DSO_BINARY_TYPE__VMLINUX;
|
||||
dso__set_long_name(dso, (char *)vmlinux);
|
||||
dso__set_long_name(dso, vmlinux, vmlinux_allocated);
|
||||
dso__set_loaded(dso, map->type);
|
||||
pr_debug("Using %s for symbols\n", symfs_vmlinux);
|
||||
}
|
||||
|
@ -1456,21 +1457,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
|
|||
|
||||
filename = dso__build_id_filename(dso, NULL, 0);
|
||||
if (filename != NULL) {
|
||||
err = dso__load_vmlinux(dso, map, filename, filter);
|
||||
if (err > 0) {
|
||||
dso->lname_alloc = 1;
|
||||
err = dso__load_vmlinux(dso, map, filename, true, filter);
|
||||
if (err > 0)
|
||||
goto out;
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
|
||||
for (i = 0; i < vmlinux_path__nr_entries; ++i) {
|
||||
err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
|
||||
if (err > 0) {
|
||||
dso__set_long_name(dso, strdup(vmlinux_path[i]));
|
||||
dso->lname_alloc = 1;
|
||||
err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
|
||||
if (err > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
|
@ -1607,15 +1603,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
|
|||
}
|
||||
|
||||
if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
|
||||
err = dso__load_vmlinux(dso, map,
|
||||
symbol_conf.vmlinux_name, filter);
|
||||
if (err > 0) {
|
||||
dso__set_long_name(dso,
|
||||
strdup(symbol_conf.vmlinux_name));
|
||||
dso->lname_alloc = 1;
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
|
||||
false, filter);
|
||||
}
|
||||
|
||||
if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
|
||||
|
@ -1641,7 +1630,7 @@ do_kallsyms:
|
|||
free(kallsyms_allocated_filename);
|
||||
|
||||
if (err > 0 && !dso__is_kcore(dso)) {
|
||||
dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
|
||||
dso__set_long_name(dso, "[kernel.kallsyms]", false);
|
||||
map__fixup_start(map);
|
||||
map__fixup_end(map);
|
||||
}
|
||||
|
@ -1671,7 +1660,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
|
|||
*/
|
||||
if (symbol_conf.default_guest_vmlinux_name != NULL) {
|
||||
err = dso__load_vmlinux(dso, map,
|
||||
symbol_conf.default_guest_vmlinux_name, filter);
|
||||
symbol_conf.default_guest_vmlinux_name,
|
||||
false, filter);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1688,7 +1678,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
|
|||
pr_debug("Using %s for symbols\n", kallsyms_filename);
|
||||
if (err > 0 && !dso__is_kcore(dso)) {
|
||||
machine__mmap_name(machine, path, sizeof(path));
|
||||
dso__set_long_name(dso, strdup(path));
|
||||
dso__set_long_name(dso, strdup(path), true);
|
||||
map__fixup_start(map);
|
||||
map__fixup_end(map);
|
||||
}
|
||||
|
|
|
@ -206,7 +206,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss);
|
|||
|
||||
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
|
||||
int dso__load_vmlinux(struct dso *dso, struct map *map,
|
||||
const char *vmlinux, symbol_filter_t filter);
|
||||
const char *vmlinux, bool vmlinux_allocated,
|
||||
symbol_filter_t filter);
|
||||
int dso__load_vmlinux_path(struct dso *dso, struct map *map,
|
||||
symbol_filter_t filter);
|
||||
int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
|
||||
|
|
|
@ -482,3 +482,17 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
|
|||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
const char *get_filename_for_perf_kvm(void)
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
if (perf_host && !perf_guest)
|
||||
filename = strdup("perf.data.host");
|
||||
else if (!perf_host && perf_guest)
|
||||
filename = strdup("perf.data.guest");
|
||||
else
|
||||
filename = strdup("perf.data.kvm");
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include <sys/ttydefaults.h>
|
||||
#include <lk/debugfs.h>
|
||||
#include <termios.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
extern const char *graph_line;
|
||||
extern const char *graph_dotted_line;
|
||||
|
@ -281,6 +282,17 @@ static inline unsigned next_pow2(unsigned x)
|
|||
return 1ULL << (32 - __builtin_clz(x - 1));
|
||||
}
|
||||
|
||||
static inline unsigned long next_pow2_l(unsigned long x)
|
||||
{
|
||||
#if BITS_PER_LONG == 64
|
||||
if (x <= (1UL << 31))
|
||||
return next_pow2(x);
|
||||
return (unsigned long)next_pow2(x >> 32) << 32;
|
||||
#else
|
||||
return next_pow2(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t hex_width(u64 v);
|
||||
int hex2u64(const char *ptr, u64 *val);
|
||||
|
||||
|
@ -309,4 +321,6 @@ void free_srcline(char *srcline);
|
|||
|
||||
int filename__read_int(const char *filename, int *value);
|
||||
int filename__read_str(const char *filename, char **buf, size_t *sizep);
|
||||
|
||||
const char *get_filename_for_perf_kvm(void);
|
||||
#endif /* GIT_COMPAT_UTIL_H */
|
||||
|
|
|
@ -103,7 +103,7 @@ struct dso *vdso__dso_findnew(struct list_head *head)
|
|||
dso = dso__new(VDSO__MAP_NAME);
|
||||
if (dso != NULL) {
|
||||
dsos__add(head, dso);
|
||||
dso__set_long_name(dso, file);
|
||||
dso__set_long_name(dso, file, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue