perf/core improvements and fixes:

New features:
 
 - Handle inline functions in callchains (Jin Yao)
 
 - Enable sorting by srcline as key (Milian Wolff)
 
 Fixes:
 
 - Fix no_size logic in addr_filter__resolve_kernel_syms() in the
   auxtrace code (Adrian Hunter)
 
 - Fix some thread refcount leaks in 'perf trace' (Arnaldo Carvalho de Melo)
 
 - Fix divide by zero when calculating percent for an event in a group in
   the annotate by source line code (Taeung Song)
 
 - build-id files now aren't anymore symlinks, their parent directories
   are, so readlink the later (Taeung Song)
 
 - Assorted fixes for null termination problems, mostly related to
   readlink, detected by valgrind (Tommi Rantala)
 
 Infrastructure:
 
 - Make vfs_getname probe point logic in 'perf trace' more robust
   wrt length of pathname (Arnaldo Carvalho de Melo)
 
 - Remove unused 'prefix' parameter from builtins main functions (Arnaldo Carvalho de Melo)
 
 - Show 'perf list sdt' option in man page (Ravi Bangoria)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJY2WNUAAoJENZQFvNTUqpAZ3AQAIn/Q+Y665oP57RbikedeifL
 He8vdMUkD/haRo0atbvuu5tRrwiRUabkUa6GKPHNCDl8GUD6UbkztUirL4Cq4v9s
 7ONbCHXzaPnPZbDbl/W7Yx4vADow3YMR9EyNkL8/i2ApZqMCPQ9mUBhxJlSDp7RY
 agYcOugUlYuvHsKVX59fTyvTAq8btfyFQTqhJ+NPddcxsyR5jam9XxxvgMURdFJr
 h6OLO9wqCxlMctqlGXU+6tpqiAR+bp8UZgzDKwabGR4mZR+uLBYGf0FUQz52vf2A
 83ufaZ5UrQUsSnVeYXBPW+i8+Ixu8pEOFDMDcSpk/wQXunLlN52LmuatSCkPBEV1
 jFth8SX3IAX349hpaRBNuLk5UuqS6NKBztYzlaVsKMpuIw4hRPVE3VvqKefZD/hx
 Vdlr1v6fPXMcRUcc3lFFiVCIvs0hRV4IDDIimGjJHf8dm+GFMHH+bk+tfiSQAlmZ
 q3aSKMImUM3vlD01E4BmTVr4IEZHTd3mv0Ml+nbQGNj6Bu2364eBsFRnNHJWwGmt
 c9tcnmeRv6JzrmprVXMuOUyyTcml+b5/vincEEmTxUdbxCbYFkQS3JzPxfpxqFI/
 zM5rlJJ9KKWXmwD6OgUoXT5IUzq4BuIVyJ3DxwuL2rrQggsv0zORxQtVduY+IJSj
 ZD/Qu7SOiFfnAFM6kLwP
 =Lm/M
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo-4.12-20170327' 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:

New features:

 - Handle inline functions in callchains (Jin Yao)

 - Enable sorting by srcline as key (Milian Wolff)

Fixes:

 - Fix no_size logic in addr_filter__resolve_kernel_syms() in the
   auxtrace code (Adrian Hunter)

 - Fix some thread refcount leaks in 'perf trace' (Arnaldo Carvalho de Melo)

 - Fix divide by zero when calculating percent for an event in a group in
   the annotate by source line code (Taeung Song)

 - build-id files now aren't anymore symlinks, their parent directories
   are, so readlink the later (Taeung Song)

 - Assorted fixes for null termination problems, mostly related to
   readlink, detected by valgrind (Tommi Rantala)

Infrastructure changes:

 - Make vfs_getname probe point logic in 'perf trace' more robust
   wrt length of pathname (Arnaldo Carvalho de Melo)

 - Remove unused 'prefix' parameter from builtins main functions (Arnaldo Carvalho de Melo)

 - Show 'perf list sdt' option in man page (Ravi Bangoria)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2017-03-28 07:44:43 +02:00
commit 3906a13a6b
62 changed files with 740 additions and 209 deletions

View File

@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob]
'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]
DESCRIPTION
-----------
@ -244,6 +244,8 @@ To limit the list use:
. 'pmu' to print the kernel supplied PMU events.
. 'sdt' to list all Statically Defined Tracepoint events.
. If none of the above is matched, it will apply the supplied glob to all
events, printing the ones that match.

View File

@ -235,6 +235,7 @@ OPTIONS
sort_key can be:
- function: compare on functions (default)
- address: compare on individual code addresses
- srcline: compare on source filename and line number
branch can be:
- branch: include last branch information in callgraph when available.
@ -430,6 +431,10 @@ include::itrace.txt[]
--hierarchy::
Enable hierarchical output.
--inline::
If a callgraph address belongs to an inlined function, the inline stack
will be printed. Each entry is function name or file/line.
include::callchain-overhead-calculation.txt[]
SEE ALSO

View File

@ -25,17 +25,17 @@
# endif
#endif
int bench_numa(int argc, const char **argv, const char *prefix);
int bench_sched_messaging(int argc, const char **argv, const char *prefix);
int bench_sched_pipe(int argc, const char **argv, const char *prefix);
int bench_mem_memcpy(int argc, const char **argv, const char *prefix);
int bench_mem_memset(int argc, const char **argv, const char *prefix);
int bench_futex_hash(int argc, const char **argv, const char *prefix);
int bench_futex_wake(int argc, const char **argv, const char *prefix);
int bench_futex_wake_parallel(int argc, const char **argv, const char *prefix);
int bench_futex_requeue(int argc, const char **argv, const char *prefix);
int bench_numa(int argc, const char **argv);
int bench_sched_messaging(int argc, const char **argv);
int bench_sched_pipe(int argc, const char **argv);
int bench_mem_memcpy(int argc, const char **argv);
int bench_mem_memset(int argc, const char **argv);
int bench_futex_hash(int argc, const char **argv);
int bench_futex_wake(int argc, const char **argv);
int bench_futex_wake_parallel(int argc, const char **argv);
int bench_futex_requeue(int argc, const char **argv);
/* pi futexes */
int bench_futex_lock_pi(int argc, const char **argv, const char *prefix);
int bench_futex_lock_pi(int argc, const char **argv);
#define BENCH_FORMAT_DEFAULT_STR "default"
#define BENCH_FORMAT_DEFAULT 0

View File

@ -114,8 +114,7 @@ static void print_summary(void)
(int) runtime.tv_sec);
}
int bench_futex_hash(int argc, const char **argv,
const char *prefix __maybe_unused)
int bench_futex_hash(int argc, const char **argv)
{
int ret = 0;
cpu_set_t cpu;

View File

@ -140,8 +140,7 @@ static void create_threads(struct worker *w, pthread_attr_t thread_attr)
}
}
int bench_futex_lock_pi(int argc, const char **argv,
const char *prefix __maybe_unused)
int bench_futex_lock_pi(int argc, const char **argv)
{
int ret = 0;
unsigned int i;

View File

@ -109,8 +109,7 @@ static void toggle_done(int sig __maybe_unused,
done = true;
}
int bench_futex_requeue(int argc, const char **argv,
const char *prefix __maybe_unused)
int bench_futex_requeue(int argc, const char **argv)
{
int ret = 0;
unsigned int i, j;

View File

@ -197,8 +197,7 @@ static void toggle_done(int sig __maybe_unused,
done = true;
}
int bench_futex_wake_parallel(int argc, const char **argv,
const char *prefix __maybe_unused)
int bench_futex_wake_parallel(int argc, const char **argv)
{
int ret = 0;
unsigned int i, j;

View File

@ -115,8 +115,7 @@ static void toggle_done(int sig __maybe_unused,
done = true;
}
int bench_futex_wake(int argc, const char **argv,
const char *prefix __maybe_unused)
int bench_futex_wake(int argc, const char **argv)
{
int ret = 0;
unsigned int i, j;

View File

@ -284,7 +284,7 @@ static const char * const bench_mem_memcpy_usage[] = {
NULL
};
int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused)
int bench_mem_memcpy(int argc, const char **argv)
{
struct bench_mem_info info = {
.functions = memcpy_functions,
@ -358,7 +358,7 @@ static const struct function memset_functions[] = {
{ .name = NULL, }
};
int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unused)
int bench_mem_memset(int argc, const char **argv)
{
struct bench_mem_info info = {
.functions = memset_functions,

View File

@ -1767,7 +1767,7 @@ static int bench_all(void)
return 0;
}
int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused)
int bench_numa(int argc, const char **argv)
{
init_params(&p0, "main,", argc, argv);
argc = parse_options(argc, argv, options, bench_numa_usage, 0);

View File

@ -260,8 +260,7 @@ static const char * const bench_sched_message_usage[] = {
NULL
};
int bench_sched_messaging(int argc, const char **argv,
const char *prefix __maybe_unused)
int bench_sched_messaging(int argc, const char **argv)
{
unsigned int i, total_children;
struct timeval start, stop, diff;

View File

@ -76,7 +76,7 @@ static void *worker_thread(void *__tdata)
return NULL;
}
int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused)
int bench_sched_pipe(int argc, const char **argv)
{
struct thread_data threads[2], *td;
int pipe_1[2], pipe_2[2];

View File

@ -383,7 +383,7 @@ static const char * const annotate_usage[] = {
NULL
};
int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_annotate(int argc, const char **argv)
{
struct perf_annotate annotate = {
.tool = {

View File

@ -25,7 +25,7 @@
#include <string.h>
#include <sys/prctl.h>
typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix);
typedef int (*bench_fn_t)(int argc, const char **argv);
struct bench {
const char *name;
@ -155,7 +155,7 @@ static int bench_str2int(const char *str)
* to something meaningful:
*/
static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
int argc, const char **argv, const char *prefix)
int argc, const char **argv)
{
int size;
char *name;
@ -171,7 +171,7 @@ static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t f
prctl(PR_SET_NAME, name);
argv[0] = name;
ret = fn(argc, argv, prefix);
ret = fn(argc, argv);
free(name);
@ -198,7 +198,7 @@ static void run_collection(struct collection *coll)
fflush(stdout);
argv[1] = bench->name;
run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL);
run_bench(coll->name, bench->name, bench->fn, 1, argv);
printf("\n");
}
}
@ -211,7 +211,7 @@ static void run_all_collections(void)
run_collection(coll);
}
int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_bench(int argc, const char **argv)
{
struct collection *coll;
int ret = 0;
@ -270,7 +270,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
if (bench_format == BENCH_FORMAT_DEFAULT)
printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
fflush(stdout);
ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix);
ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
goto end;
}

View File

@ -276,8 +276,7 @@ static int build_id_cache__update_file(const char *filename)
return err;
}
int cmd_buildid_cache(int argc, const char **argv,
const char *prefix __maybe_unused)
int cmd_buildid_cache(int argc, const char **argv)
{
struct strlist *list;
struct str_node *pos;

View File

@ -87,8 +87,7 @@ out:
return 0;
}
int cmd_buildid_list(int argc, const char **argv,
const char *prefix __maybe_unused)
int cmd_buildid_list(int argc, const char **argv)
{
bool show_kernel = false;
bool with_hits = false;

View File

@ -2755,12 +2755,12 @@ static int perf_c2c__record(int argc, const char **argv)
pr_debug("\n");
}
ret = cmd_record(i, rec_argv, NULL);
ret = cmd_record(i, rec_argv);
free(rec_argv);
return ret;
}
int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_c2c(int argc, const char **argv)
{
argc = parse_options(argc, argv, c2c_options, c2c_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

View File

@ -154,7 +154,7 @@ static int parse_config_arg(char *arg, char **var, char **value)
return 0;
}
int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_config(int argc, const char **argv)
{
int i, ret = 0;
struct perf_config_set *set;

View File

@ -6,7 +6,7 @@
#include "data-convert.h"
#include "data-convert-bt.h"
typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
typedef int (*data_cmd_fn_t)(int argc, const char **argv);
struct data_cmd {
const char *name;
@ -50,8 +50,7 @@ static const char * const data_convert_usage[] = {
NULL
};
static int cmd_data_convert(int argc, const char **argv,
const char *prefix __maybe_unused)
static int cmd_data_convert(int argc, const char **argv)
{
const char *to_ctf = NULL;
struct perf_data_convert_opts opts = {
@ -98,7 +97,7 @@ static struct data_cmd data_cmds[] = {
{ .name = NULL, },
};
int cmd_data(int argc, const char **argv, const char *prefix)
int cmd_data(int argc, const char **argv)
{
struct data_cmd *cmd;
const char *cmdstr;
@ -118,7 +117,7 @@ int cmd_data(int argc, const char **argv, const char *prefix)
if (strcmp(cmd->name, cmdstr))
continue;
return cmd->fn(argc, argv, prefix);
return cmd->fn(argc, argv);
}
pr_err("Unknown command: %s\n", cmdstr);

View File

@ -1321,7 +1321,7 @@ static int diff__config(const char *var, const char *value,
return 0;
}
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_diff(int argc, const char **argv)
{
int ret = hists__init();

View File

@ -46,7 +46,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
return 0;
}
int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_evlist(int argc, const char **argv)
{
struct perf_attr_details details = { .verbose = false, };
const struct option options[] = {

View File

@ -304,7 +304,7 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb)
return -1;
}
int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_ftrace(int argc, const char **argv)
{
int ret;
struct perf_ftrace ftrace = {

View File

@ -418,7 +418,7 @@ static int show_html_page(const char *perf_cmd)
return 0;
}
int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_help(int argc, const char **argv)
{
bool show_all = false;
enum help_format help_format = HELP_FORMAT_MAN;

View File

@ -738,7 +738,7 @@ static int __cmd_inject(struct perf_inject *inject)
return ret;
}
int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_inject(int argc, const char **argv)
{
struct perf_inject inject = {
.tool = {

View File

@ -43,7 +43,7 @@ static int __cmd_kallsyms(int argc, const char **argv)
return 0;
}
int cmd_kallsyms(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_kallsyms(int argc, const char **argv)
{
const struct option options[] = {
OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),

View File

@ -1866,7 +1866,7 @@ static int __cmd_record(int argc, const char **argv)
for (j = 1; j < (unsigned int)argc; j++, i++)
rec_argv[i] = argv[j];
return cmd_record(i, rec_argv, NULL);
return cmd_record(i, rec_argv);
}
static int kmem_config(const char *var, const char *value, void *cb __maybe_unused)
@ -1885,7 +1885,7 @@ static int kmem_config(const char *var, const char *value, void *cb __maybe_unus
return 0;
}
int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_kmem(int argc, const char **argv)
{
const char * const default_slab_sort = "frag,hit,bytes";
const char * const default_page_sort = "bytes,hit";

View File

@ -1209,7 +1209,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED);
record_usage = kvm_stat_record_usage;
return cmd_record(i, rec_argv, NULL);
return cmd_record(i, rec_argv);
}
static int
@ -1477,7 +1477,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
#endif
perf_stat:
return cmd_stat(argc, argv, NULL);
return cmd_stat(argc, argv);
}
#endif /* HAVE_KVM_STAT_SUPPORT */
@ -1496,7 +1496,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv)
BUG_ON(i != rec_argc);
return cmd_record(i, rec_argv, NULL);
return cmd_record(i, rec_argv);
}
static int __cmd_report(const char *file_name, int argc, const char **argv)
@ -1514,7 +1514,7 @@ static int __cmd_report(const char *file_name, int argc, const char **argv)
BUG_ON(i != rec_argc);
return cmd_report(i, rec_argv, NULL);
return cmd_report(i, rec_argv);
}
static int
@ -1533,10 +1533,10 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
BUG_ON(i != rec_argc);
return cmd_buildid_list(i, rec_argv, NULL);
return cmd_buildid_list(i, rec_argv);
}
int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_kvm(int argc, const char **argv)
{
const char *file_name = NULL;
const struct option kvm_options[] = {
@ -1591,9 +1591,9 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
else if (!strncmp(argv[0], "rep", 3))
return __cmd_report(file_name, argc, argv);
else if (!strncmp(argv[0], "diff", 4))
return cmd_diff(argc, argv, NULL);
return cmd_diff(argc, argv);
else if (!strncmp(argv[0], "top", 3))
return cmd_top(argc, argv, NULL);
return cmd_top(argc, argv);
else if (!strncmp(argv[0], "buildid-list", 12))
return __cmd_buildid_list(file_name, argc, argv);
#ifdef HAVE_KVM_STAT_SUPPORT

View File

@ -20,7 +20,7 @@
static bool desc_flag = true;
static bool details_flag;
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_list(int argc, const char **argv)
{
int i;
bool raw_dump = false;

View File

@ -941,12 +941,12 @@ static int __cmd_record(int argc, const char **argv)
BUG_ON(i != rec_argc);
ret = cmd_record(i, rec_argv, NULL);
ret = cmd_record(i, rec_argv);
free(rec_argv);
return ret;
}
int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_lock(int argc, const char **argv)
{
const struct option lock_options[] = {
OPT_STRING('i', "input", &input_name, "file", "input file name"),
@ -1009,7 +1009,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
rc = __cmd_report(false);
} else if (!strcmp(argv[0], "script")) {
/* Aliased to 'perf script' */
return cmd_script(argc, argv, prefix);
return cmd_script(argc, argv);
} else if (!strcmp(argv[0], "info")) {
if (argc) {
argc = parse_options(argc, argv,

View File

@ -129,7 +129,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
pr_debug("\n");
}
ret = cmd_record(i, rec_argv, NULL);
ret = cmd_record(i, rec_argv);
free(rec_argv);
return ret;
}
@ -256,7 +256,7 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem)
for (j = 1; j < argc; j++, i++)
rep_argv[i] = argv[j];
ret = cmd_report(i, rep_argv, NULL);
ret = cmd_report(i, rep_argv);
free(rep_argv);
return ret;
}
@ -330,7 +330,7 @@ error:
return ret;
}
int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_mem(int argc, const char **argv)
{
struct stat st;
struct perf_mem mem = {

View File

@ -468,7 +468,7 @@ out:
static int
__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
__cmd_probe(int argc, const char **argv)
{
const char * const probe_usage[] = {
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
@ -687,13 +687,13 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
return 0;
}
int cmd_probe(int argc, const char **argv, const char *prefix)
int cmd_probe(int argc, const char **argv)
{
int ret;
ret = init_params();
if (!ret) {
ret = __cmd_probe(argc, argv, prefix);
ret = __cmd_probe(argc, argv);
cleanup_params();
}

View File

@ -1667,7 +1667,7 @@ static struct option __record_options[] = {
struct option *record_options = __record_options;
int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_record(int argc, const char **argv)
{
int err;
struct record *rec = &record;

View File

@ -681,7 +681,7 @@ const char report_callchain_help[] = "Display call graph (stack chain/backtrace)
CALLCHAIN_REPORT_HELP
"\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_report(int argc, const char **argv)
{
struct perf_session *session;
struct itrace_synth_opts itrace_synth_opts = { .set = 0, };
@ -845,6 +845,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
stdio__config_color, "always"),
OPT_STRING(0, "time", &report.time_str, "str",
"Time span of interest (start,stop)"),
OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
"Show inline function"),
OPT_END()
};
struct perf_data_file file = {

View File

@ -3272,10 +3272,10 @@ static int __cmd_record(int argc, const char **argv)
BUG_ON(i != rec_argc);
return cmd_record(i, rec_argv, NULL);
return cmd_record(i, rec_argv);
}
int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_sched(int argc, const char **argv)
{
const char default_sort_order[] = "avg, max, switch, runtime";
struct perf_sched sched = {
@ -3412,7 +3412,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
* Aliased to 'perf script' for now:
*/
if (!strcmp(argv[0], "script"))
return cmd_script(argc, argv, prefix);
return cmd_script(argc, argv);
if (!strncmp(argv[0], "rec", 3)) {
return __cmd_record(argc, argv);

View File

@ -2359,7 +2359,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
return set_maps(script);
}
int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_script(int argc, const char **argv)
{
bool show_full_info = false;
bool header = false;
@ -2504,7 +2504,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
if (!rec_script_path)
return cmd_record(argc, argv, NULL);
return cmd_record(argc, argv);
}
if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {

View File

@ -2478,7 +2478,7 @@ static void setup_system_wide(int forks)
}
}
int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_stat(int argc, const char **argv)
{
const char * const stat_usage[] = {
"perf stat [<options>] [<command>]",

View File

@ -1773,7 +1773,7 @@ static int timechart__io_record(int argc, const char **argv)
for (i = 0; i < (unsigned int)argc; i++)
*p++ = argv[i];
return cmd_record(rec_argc, rec_argv, NULL);
return cmd_record(rec_argc, rec_argv);
}
@ -1864,7 +1864,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
for (j = 0; j < (unsigned int)argc; j++)
*p++ = argv[j];
return cmd_record(rec_argc, rec_argv, NULL);
return cmd_record(rec_argc, rec_argv);
}
static int
@ -1917,8 +1917,7 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
return 0;
}
int cmd_timechart(int argc, const char **argv,
const char *prefix __maybe_unused)
int cmd_timechart(int argc, const char **argv)
{
struct timechart tchart = {
.tool = {

View File

@ -1075,7 +1075,7 @@ parse_percent_limit(const struct option *opt, const char *arg,
const char top_callchain_help[] = CALLCHAIN_RECORD_HELP CALLCHAIN_REPORT_HELP
"\n\t\t\t\tDefault: fp,graph,0.5,caller,function";
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_top(int argc, const char **argv)
{
char errbuf[BUFSIZ];
struct perf_top top = {

View File

@ -1653,15 +1653,17 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
ttrace = thread__priv(thread);
if (!ttrace)
goto out;
goto out_put;
filename_len = strlen(filename);
if (filename_len == 0)
goto out_put;
if (ttrace->filename.namelen < filename_len) {
char *f = realloc(ttrace->filename.name, filename_len + 1);
if (f == NULL)
goto out;
goto out_put;
ttrace->filename.namelen = filename_len;
ttrace->filename.name = f;
@ -1671,12 +1673,12 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
ttrace->filename.pending_open = true;
if (!ttrace->filename.ptr)
goto out;
goto out_put;
entry_str_len = strlen(ttrace->entry_str);
remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
if (remaining_space <= 0)
goto out;
goto out_put;
if (filename_len > (size_t)remaining_space) {
filename += filename_len - remaining_space;
@ -1690,6 +1692,8 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
ttrace->filename.ptr = 0;
ttrace->filename.entry_str_pos = 0;
out_put:
thread__put(thread);
out:
return 0;
}
@ -1710,6 +1714,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
ttrace->runtime_ms += runtime_ms;
trace->runtime_ms += runtime_ms;
out_put:
thread__put(thread);
return 0;
@ -1720,8 +1725,7 @@ out_dump:
(pid_t)perf_evsel__intval(evsel, sample, "pid"),
runtime,
perf_evsel__intval(evsel, sample, "vruntime"));
thread__put(thread);
return 0;
goto out_put;
}
static void bpf_output__printer(enum binary_printer_ops op,
@ -1920,7 +1924,7 @@ static int trace__process_sample(struct perf_tool *tool,
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
if (thread && thread__is_filtered(thread))
return 0;
goto out;
trace__set_base_time(trace, evsel, sample);
@ -1928,7 +1932,8 @@ static int trace__process_sample(struct perf_tool *tool,
++trace->nr_events;
handler(trace, evsel, event, sample);
}
out:
thread__put(thread);
return err;
}
@ -1988,7 +1993,7 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
for (i = 0; i < (unsigned int)argc; i++)
rec_argv[j++] = argv[i];
return cmd_record(j, rec_argv, NULL);
return cmd_record(j, rec_argv);
}
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
@ -2786,7 +2791,7 @@ out:
return err;
}
int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_trace(int argc, const char **argv)
{
const char *trace_usage[] = {
"perf trace [<options>] [<command>]",

View File

@ -2,8 +2,7 @@
#include "builtin.h"
#include "perf.h"
int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
const char *prefix __maybe_unused)
int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused)
{
printf("perf version %s\n", perf_version_string);
return 0;

View File

@ -13,35 +13,35 @@ void prune_packed_objects(int);
int read_line_with_nul(char *buf, int size, FILE *file);
int check_pager_config(const char *cmd);
int cmd_annotate(int argc, const char **argv, const char *prefix);
int cmd_bench(int argc, const char **argv, const char *prefix);
int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
int cmd_buildid_list(int argc, const char **argv, const char *prefix);
int cmd_config(int argc, const char **argv, const char *prefix);
int cmd_c2c(int argc, const char **argv, const char *prefix);
int cmd_diff(int argc, const char **argv, const char *prefix);
int cmd_evlist(int argc, const char **argv, const char *prefix);
int cmd_help(int argc, const char **argv, const char *prefix);
int cmd_sched(int argc, const char **argv, const char *prefix);
int cmd_kallsyms(int argc, const char **argv, const char *prefix);
int cmd_list(int argc, const char **argv, const char *prefix);
int cmd_record(int argc, const char **argv, const char *prefix);
int cmd_report(int argc, const char **argv, const char *prefix);
int cmd_stat(int argc, const char **argv, const char *prefix);
int cmd_timechart(int argc, const char **argv, const char *prefix);
int cmd_top(int argc, const char **argv, const char *prefix);
int cmd_script(int argc, const char **argv, const char *prefix);
int cmd_version(int argc, const char **argv, const char *prefix);
int cmd_probe(int argc, const char **argv, const char *prefix);
int cmd_kmem(int argc, const char **argv, const char *prefix);
int cmd_lock(int argc, const char **argv, const char *prefix);
int cmd_kvm(int argc, const char **argv, const char *prefix);
int cmd_test(int argc, const char **argv, const char *prefix);
int cmd_trace(int argc, const char **argv, const char *prefix);
int cmd_inject(int argc, const char **argv, const char *prefix);
int cmd_mem(int argc, const char **argv, const char *prefix);
int cmd_data(int argc, const char **argv, const char *prefix);
int cmd_ftrace(int argc, const char **argv, const char *prefix);
int cmd_annotate(int argc, const char **argv);
int cmd_bench(int argc, const char **argv);
int cmd_buildid_cache(int argc, const char **argv);
int cmd_buildid_list(int argc, const char **argv);
int cmd_config(int argc, const char **argv);
int cmd_c2c(int argc, const char **argv);
int cmd_diff(int argc, const char **argv);
int cmd_evlist(int argc, const char **argv);
int cmd_help(int argc, const char **argv);
int cmd_sched(int argc, const char **argv);
int cmd_kallsyms(int argc, const char **argv);
int cmd_list(int argc, const char **argv);
int cmd_record(int argc, const char **argv);
int cmd_report(int argc, const char **argv);
int cmd_stat(int argc, const char **argv);
int cmd_timechart(int argc, const char **argv);
int cmd_top(int argc, const char **argv);
int cmd_script(int argc, const char **argv);
int cmd_version(int argc, const char **argv);
int cmd_probe(int argc, const char **argv);
int cmd_kmem(int argc, const char **argv);
int cmd_lock(int argc, const char **argv);
int cmd_kvm(int argc, const char **argv);
int cmd_test(int argc, const char **argv);
int cmd_trace(int argc, const char **argv);
int cmd_inject(int argc, const char **argv);
int cmd_mem(int argc, const char **argv);
int cmd_data(int argc, const char **argv);
int cmd_ftrace(int argc, const char **argv);
int find_scripts(char **scripts_array, char **scripts_path_array);
#endif

View File

@ -34,7 +34,7 @@ const char *input_name;
struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, const char *);
int (*fn)(int, const char **);
int option;
};
@ -339,13 +339,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
{
int status;
struct stat st;
const char *prefix;
char sbuf[STRERR_BUFSIZE];
prefix = NULL;
if (p->option & RUN_SETUP)
prefix = NULL; /* setup_perf_directory(); */
if (use_browser == -1)
use_browser = check_browser_config(p->cmd);
@ -356,7 +351,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
commit_pager_choice();
perf_env__set_cmdline(&perf_env, argc, argv);
status = p->fn(argc, argv, prefix);
status = p->fn(argc, argv);
perf_config__exit();
exit_browser(status);
perf_env__exit(&perf_env);
@ -566,7 +561,7 @@ int main(int argc, const char **argv)
#ifdef HAVE_LIBAUDIT_SUPPORT
setup_path();
argv[0] = "trace";
return cmd_trace(argc, argv, NULL);
return cmd_trace(argc, argv);
#else
fprintf(stderr,
"trace command not available: missing audit-libs devel package at build time.\n");

View File

@ -464,7 +464,7 @@ static int perf_test__list(int argc, const char **argv)
return 0;
}
int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_test(int argc, const char **argv)
{
const char *test_usage[] = {
"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",

View File

@ -43,7 +43,7 @@ static char *get_self_path(void)
{
char *buf = calloc(PATH_MAX, sizeof(char));
if (buf && readlink("/proc/self/exe", buf, PATH_MAX) < 0) {
if (buf && readlink("/proc/self/exe", buf, PATH_MAX - 1) < 0) {
pr_debug("Failed to get correct path of perf\n");
free(buf);
return NULL;

View File

@ -144,9 +144,60 @@ static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
cl->unfolded = unfold ? cl->has_children : false;
}
static struct inline_node *inline_node__create(struct map *map, u64 ip)
{
struct dso *dso;
struct inline_node *node;
if (map == NULL)
return NULL;
dso = map->dso;
if (dso == NULL)
return NULL;
if (dso->kernel != DSO_TYPE_USER)
return NULL;
node = dso__parse_addr_inlines(dso,
map__rip_2objdump(map, ip));
return node;
}
static int inline__count_rows(struct inline_node *node)
{
struct inline_list *ilist;
int i = 0;
if (node == NULL)
return 0;
list_for_each_entry(ilist, &node->val, list) {
if ((ilist->filename != NULL) || (ilist->funcname != NULL))
i++;
}
return i;
}
static int callchain_list__inline_rows(struct callchain_list *chain)
{
struct inline_node *node;
int rows;
node = inline_node__create(chain->ms.map, chain->ip);
if (node == NULL)
return 0;
rows = inline__count_rows(node);
inline_node__delete(node);
return rows;
}
static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
{
int n = 0;
int n = 0, inline_rows;
struct rb_node *nd;
for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
@ -156,6 +207,13 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
list_for_each_entry(chain, &child->val, list) {
++n;
if (symbol_conf.inline_name) {
inline_rows =
callchain_list__inline_rows(chain);
n += inline_rows;
}
/* We need this because we may not have children */
folded_sign = callchain_list__folded(chain);
if (folded_sign == '+')
@ -207,7 +265,7 @@ static int callchain_node__count_rows(struct callchain_node *node)
{
struct callchain_list *chain;
bool unfolded = false;
int n = 0;
int n = 0, inline_rows;
if (callchain_param.mode == CHAIN_FLAT)
return callchain_node__count_flat_rows(node);
@ -216,6 +274,11 @@ static int callchain_node__count_rows(struct callchain_node *node)
list_for_each_entry(chain, &node->val, list) {
++n;
if (symbol_conf.inline_name) {
inline_rows = callchain_list__inline_rows(chain);
n += inline_rows;
}
unfolded = chain->unfolded;
}
@ -362,6 +425,19 @@ static void hist_entry__init_have_children(struct hist_entry *he)
he->init_have_children = true;
}
static void hist_entry_init_inline_node(struct hist_entry *he)
{
if (he->inline_node)
return;
he->inline_node = inline_node__create(he->ms.map, he->ip);
if (he->inline_node == NULL)
return;
he->has_children = true;
}
static bool hist_browser__toggle_fold(struct hist_browser *browser)
{
struct hist_entry *he = browser->he_selection;
@ -393,7 +469,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
if (he->unfolded) {
if (he->leaf)
he->nr_rows = callchain__count_rows(&he->sorted_chain);
if (he->inline_node)
he->nr_rows = inline__count_rows(
he->inline_node);
else
he->nr_rows = callchain__count_rows(
&he->sorted_chain);
else
he->nr_rows = hierarchy_count_rows(browser, he, false);
@ -753,6 +834,71 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
#define LEVEL_OFFSET_STEP 3
static int hist_browser__show_inline(struct hist_browser *browser,
struct inline_node *node,
unsigned short row,
int offset)
{
struct inline_list *ilist;
char buf[1024];
int color, width, first_row;
first_row = row;
width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
list_for_each_entry(ilist, &node->val, list) {
if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
color = HE_COLORSET_NORMAL;
if (ui_browser__is_current_entry(&browser->b, row))
color = HE_COLORSET_SELECTED;
if (callchain_param.key == CCKEY_ADDRESS ||
callchain_param.key == CCKEY_SRCLINE) {
if (ilist->filename != NULL)
scnprintf(buf, sizeof(buf),
"%s:%d (inline)",
ilist->filename,
ilist->line_nr);
else
scnprintf(buf, sizeof(buf), "??");
} else if (ilist->funcname != NULL)
scnprintf(buf, sizeof(buf), "%s (inline)",
ilist->funcname);
else if (ilist->filename != NULL)
scnprintf(buf, sizeof(buf),
"%s:%d (inline)",
ilist->filename,
ilist->line_nr);
else
scnprintf(buf, sizeof(buf), "??");
ui_browser__set_color(&browser->b, color);
hist_browser__gotorc(browser, row, 0);
ui_browser__write_nstring(&browser->b, " ",
LEVEL_OFFSET_STEP + offset);
ui_browser__write_nstring(&browser->b, buf, width);
row++;
}
}
return row - first_row;
}
static size_t show_inline_list(struct hist_browser *browser, struct map *map,
u64 ip, int row, int offset)
{
struct inline_node *node;
int ret;
node = inline_node__create(map, ip);
if (node == NULL)
return 0;
ret = hist_browser__show_inline(browser, node, row, offset);
inline_node__delete(node);
return ret;
}
static int hist_browser__show_callchain_list(struct hist_browser *browser,
struct callchain_node *node,
struct callchain_list *chain,
@ -764,6 +910,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
char bf[1024], *alloc_str;
char buf[64], *alloc_str2;
const char *str;
int inline_rows = 0, ret = 1;
if (arg->row_offset != 0) {
arg->row_offset--;
@ -801,10 +948,15 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
}
print(browser, chain, str, offset, row, arg);
free(alloc_str);
free(alloc_str2);
return 1;
if (symbol_conf.inline_name) {
inline_rows = show_inline_list(browser, chain->ms.map,
chain->ip, row + 1, offset);
}
return ret + inline_rows;
}
static bool check_percent_display(struct rb_node *node, u64 parent_total)
@ -1228,6 +1380,12 @@ static int hist_browser__show_entry(struct hist_browser *browser,
folded_sign = hist_entry__folded(entry);
}
if (symbol_conf.inline_name &&
(!entry->has_children)) {
hist_entry_init_inline_node(entry);
folded_sign = hist_entry__folded(entry);
}
if (row_offset == 0) {
struct hpp_arg arg = {
.b = &browser->b,
@ -1259,7 +1417,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
}
if (first) {
if (symbol_conf.use_callchain) {
if (symbol_conf.use_callchain ||
symbol_conf.inline_name) {
ui_browser__printf(&browser->b, "%c ", folded_sign);
width -= 2;
}
@ -1301,8 +1460,14 @@ static int hist_browser__show_entry(struct hist_browser *browser,
.is_current_entry = current_entry,
};
printed += hist_browser__show_callchain(browser, entry, 1, row,
hist_browser__show_callchain_entry, &arg,
if (entry->inline_node)
printed += hist_browser__show_inline(browser,
entry->inline_node, row, 0);
else
printed += hist_browser__show_callchain(browser,
entry, 1, row,
hist_browser__show_callchain_entry,
&arg,
hist_browser__check_output_full);
}

View File

@ -17,6 +17,67 @@ static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
return ret;
}
static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,
int depth, int depth_mask, FILE *fp)
{
struct dso *dso;
struct inline_node *node;
struct inline_list *ilist;
int ret = 0, i;
if (map == NULL)
return 0;
dso = map->dso;
if (dso == NULL)
return 0;
if (dso->kernel != DSO_TYPE_USER)
return 0;
node = dso__parse_addr_inlines(dso,
map__rip_2objdump(map, ip));
if (node == NULL)
return 0;
list_for_each_entry(ilist, &node->val, list) {
if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
ret += callchain__fprintf_left_margin(fp, left_margin);
for (i = 0; i < depth; i++) {
if (depth_mask & (1 << i))
ret += fprintf(fp, "|");
else
ret += fprintf(fp, " ");
ret += fprintf(fp, " ");
}
if (callchain_param.key == CCKEY_ADDRESS ||
callchain_param.key == CCKEY_SRCLINE) {
if (ilist->filename != NULL)
ret += fprintf(fp, "%s:%d (inline)",
ilist->filename,
ilist->line_nr);
else
ret += fprintf(fp, "??");
} else if (ilist->funcname != NULL)
ret += fprintf(fp, "%s (inline)",
ilist->funcname);
else if (ilist->filename != NULL)
ret += fprintf(fp, "%s:%d (inline)",
ilist->filename,
ilist->line_nr);
else
ret += fprintf(fp, "??");
ret += fprintf(fp, "\n");
}
}
inline_node__delete(node);
return ret;
}
static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
int left_margin)
{
@ -78,6 +139,10 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
fputs(str, fp);
fputc('\n', fp);
free(alloc_str);
if (symbol_conf.inline_name)
ret += inline__fprintf(chain->ms.map, chain->ip,
left_margin, depth, depth_mask, fp);
return ret;
}
@ -229,6 +294,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
if (!i++ && field_order == NULL &&
sort_order && !prefixcmp(sort_order, "sym"))
continue;
if (!printed) {
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "|\n");
@ -251,6 +317,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
if (++entries_printed == callchain_param.print_limit)
break;
if (symbol_conf.inline_name)
ret += inline__fprintf(chain->ms.map,
chain->ip,
left_margin,
0, 0,
fp);
}
root = &cnode->rb_root;
}
@ -529,6 +602,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
bool use_callchain)
{
int ret;
int callchain_ret = 0;
int inline_ret = 0;
struct perf_hpp hpp = {
.buf = bf,
.size = size,
@ -547,7 +622,16 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
ret = fprintf(fp, "%s\n", bf);
if (use_callchain)
ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
callchain_ret = hist_entry_callchain__fprintf(he, total_period,
0, fp);
if (callchain_ret == 0 && symbol_conf.inline_name) {
inline_ret = inline__fprintf(he->ms.map, he->ip, 0, 0, 0, fp);
ret += inline_ret;
if (inline_ret > 0)
ret += fprintf(fp, "\n");
} else
ret += callchain_ret;
return ret;
}

View File

@ -1307,6 +1307,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
{
char linkname[PATH_MAX];
char *build_id_filename;
char *build_id_path = NULL;
if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
!dso__is_kcore(dso))
@ -1322,8 +1323,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
goto fallback;
}
build_id_path = strdup(filename);
if (!build_id_path)
return -1;
dirname(build_id_path);
if (dso__is_kcore(dso) ||
readlink(filename, linkname, sizeof(linkname)) < 0 ||
readlink(build_id_path, linkname, sizeof(linkname)) < 0 ||
strstr(linkname, DSO__NAME_KALLSYMS) ||
access(filename, R_OK)) {
fallback:
@ -1335,6 +1342,7 @@ fallback:
__symbol__join_symfs(filename, filename_size, dso->long_name);
}
free(build_id_path);
return 0;
}
@ -1663,18 +1671,23 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
src_line->nr_pcnt = nr_pcnt;
for (k = 0; k < nr_pcnt; k++) {
h = annotation__histogram(notes, evidx + k);
src_line->samples[k].percent = 100.0 * h->addr[i] / h->sum;
double percent = 0.0;
if (src_line->samples[k].percent > percent_max)
percent_max = src_line->samples[k].percent;
h = annotation__histogram(notes, evidx + k);
if (h->sum)
percent = 100.0 * h->addr[i] / h->sum;
if (percent > percent_max)
percent_max = percent;
src_line->samples[k].percent = percent;
}
if (percent_max <= 0.5)
goto next;
offset = start + i;
src_line->path = get_srcline(map->dso, offset, NULL, false);
src_line->path = get_srcline(map->dso, offset, NULL,
false, true);
insert_source_line(&tmp_root, src_line);
next:

View File

@ -1826,7 +1826,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt)
filt->addr = start;
if (filt->range && !filt->size && !filt->sym_to) {
filt->size = size;
no_size = !!size;
no_size = !size;
}
}
@ -1840,7 +1840,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt)
if (err)
return err;
filt->size = start + size - filt->addr;
no_size = !!size;
no_size = !size;
}
/* The very last symbol in kallsyms does not imply a particular size */

View File

@ -182,13 +182,17 @@ char *build_id_cache__origname(const char *sbuild_id)
char buf[PATH_MAX];
char *ret = NULL, *p;
size_t offs = 5; /* == strlen("../..") */
ssize_t len;
linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
if (!linkname)
return NULL;
if (readlink(linkname, buf, PATH_MAX) < 0)
len = readlink(linkname, buf, sizeof(buf) - 1);
if (len <= 0)
goto out;
buf[len] = '\0';
/* The link should be "../..<origpath>/<sbuild_id>" */
p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */
if (p && (p > buf + offs)) {
@ -690,7 +694,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
err = 0;
/* Update SDT cache : error is just warned */
if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
if (realname && build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
out_free:

View File

@ -80,6 +80,10 @@ static int parse_callchain_sort_key(const char *value)
callchain_param.key = CCKEY_ADDRESS;
return 0;
}
if (!strncmp(value, "srcline", strlen(value))) {
callchain_param.key = CCKEY_SRCLINE;
return 0;
}
if (!strncmp(value, "branch", strlen(value))) {
callchain_param.branch_callstack = 1;
return 0;
@ -510,14 +514,51 @@ enum match_result {
MATCH_GT,
};
static enum match_result match_chain_srcline(struct callchain_cursor_node *node,
struct callchain_list *cnode)
{
char *left = get_srcline(cnode->ms.map->dso,
map__rip_2objdump(cnode->ms.map, cnode->ip),
cnode->ms.sym, true, false);
char *right = get_srcline(node->map->dso,
map__rip_2objdump(node->map, node->ip),
node->sym, true, false);
enum match_result ret = MATCH_EQ;
int cmp;
if (left && right)
cmp = strcmp(left, right);
else if (!left && right)
cmp = 1;
else if (left && !right)
cmp = -1;
else if (cnode->ip == node->ip)
cmp = 0;
else
cmp = (cnode->ip < node->ip) ? -1 : 1;
if (cmp != 0)
ret = cmp < 0 ? MATCH_LT : MATCH_GT;
free_srcline(left);
free_srcline(right);
return ret;
}
static enum match_result match_chain(struct callchain_cursor_node *node,
struct callchain_list *cnode)
{
struct symbol *sym = node->sym;
u64 left, right;
if (cnode->ms.sym && sym &&
callchain_param.key == CCKEY_FUNCTION) {
if (callchain_param.key == CCKEY_SRCLINE) {
enum match_result match = match_chain_srcline(node, cnode);
if (match != MATCH_ERROR)
return match;
}
if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) {
left = cnode->ms.sym->start;
right = sym->start;
} else {
@ -911,15 +952,16 @@ out:
char *callchain_list__sym_name(struct callchain_list *cl,
char *bf, size_t bfsize, bool show_dso)
{
bool show_addr = callchain_param.key == CCKEY_ADDRESS;
bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE;
int printed;
if (cl->ms.sym) {
if (callchain_param.key == CCKEY_ADDRESS &&
cl->ms.map && !cl->srcline)
if (show_srcline && cl->ms.map && !cl->srcline)
cl->srcline = get_srcline(cl->ms.map->dso,
map__rip_2objdump(cl->ms.map,
cl->ip),
cl->ms.sym, false);
cl->ms.sym, false, show_addr);
if (cl->srcline)
printed = scnprintf(bf, bfsize, "%s %s",
cl->ms.sym->name, cl->srcline);

View File

@ -77,7 +77,8 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
enum chain_key {
CCKEY_FUNCTION,
CCKEY_ADDRESS
CCKEY_ADDRESS,
CCKEY_SRCLINE
};
enum chain_value {

View File

@ -370,15 +370,11 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist __maybe_unused)
{
char buf[MAXPATHLEN];
char proc[32];
u32 n;
int i, ret;
/*
* actual atual path to perf binary
*/
sprintf(proc, "/proc/%d/exe", getpid());
ret = readlink(proc, buf, sizeof(buf));
/* actual path to perf binary */
ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (ret <= 0)
return -1;

View File

@ -1136,6 +1136,11 @@ void hist_entry__delete(struct hist_entry *he)
zfree(&he->mem_info);
}
if (he->inline_node) {
inline_node__delete(he->inline_node);
he->inline_node = NULL;
}
zfree(&he->stat_acc);
free_srcline(he->srcline);
if (he->srcfile && he->srcfile[0])

View File

@ -405,7 +405,8 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
if (map && map->dso) {
srcline = get_srcline(map->dso,
map__rip_2objdump(map, addr), NULL, true);
map__rip_2objdump(map, addr), NULL,
true, true);
if (srcline != SRCLINE_UNKNOWN)
ret = fprintf(fp, "%s%s", prefix, srcline);
free_srcline(srcline);

View File

@ -323,7 +323,7 @@ char *hist_entry__get_srcline(struct hist_entry *he)
return SRCLINE_UNKNOWN;
return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
he->ms.sym, true);
he->ms.sym, true, true);
}
static int64_t
@ -366,7 +366,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
left->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->from.al_addr),
left->branch_info->from.sym, true);
left->branch_info->from.sym,
true, true);
}
if (!right->branch_info->srcline_from) {
struct map *map = right->branch_info->from.map;
@ -376,7 +377,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->from.al_addr),
right->branch_info->from.sym, true);
right->branch_info->from.sym,
true, true);
}
return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
}
@ -407,7 +409,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
left->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->to.al_addr),
left->branch_info->from.sym, true);
left->branch_info->from.sym,
true, true);
}
if (!right->branch_info->srcline_to) {
struct map *map = right->branch_info->to.map;
@ -417,7 +420,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->to.al_addr),
right->branch_info->to.sym, true);
right->branch_info->to.sym,
true, true);
}
return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
}
@ -448,7 +452,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e)
return no_srcfile;
sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
e->ms.sym, false, true);
e->ms.sym, false, true, true);
if (!strcmp(sf, SRCLINE_UNKNOWN))
return no_srcfile;
p = strchr(sf, ':');

View File

@ -128,6 +128,7 @@ struct hist_entry {
};
char *srcline;
char *srcfile;
struct inline_node *inline_node;
struct symbol *parent;
struct branch_info *branch_info;
struct hists *hists;

View File

@ -7,11 +7,58 @@
#include "util/dso.h"
#include "util/util.h"
#include "util/debug.h"
#include "util/callchain.h"
#include "symbol.h"
bool srcline_full_filename;
static const char *dso__name(struct dso *dso)
{
const char *dso_name;
if (dso->symsrc_filename)
dso_name = dso->symsrc_filename;
else
dso_name = dso->long_name;
if (dso_name[0] == '[')
return NULL;
if (!strncmp(dso_name, "/tmp/perf-", 10))
return NULL;
return dso_name;
}
static int inline_list__append(char *filename, char *funcname, int line_nr,
struct inline_node *node, struct dso *dso)
{
struct inline_list *ilist;
char *demangled;
ilist = zalloc(sizeof(*ilist));
if (ilist == NULL)
return -1;
ilist->filename = filename;
ilist->line_nr = line_nr;
if (dso != NULL) {
demangled = dso__demangle_sym(dso, 0, funcname);
if (demangled == NULL) {
ilist->funcname = funcname;
} else {
ilist->funcname = demangled;
free(funcname);
}
}
list_add_tail(&ilist->list, &node->val);
return 0;
}
#ifdef HAVE_LIBBFD_SUPPORT
/*
@ -151,9 +198,17 @@ static void addr2line_cleanup(struct a2l_data *a2l)
#define MAX_INLINE_NEST 1024
static void inline_list__reverse(struct inline_node *node)
{
struct inline_list *ilist, *n;
list_for_each_entry_safe_reverse(ilist, n, &node->val, list)
list_move_tail(&ilist->list, &node->val);
}
static int addr2line(const char *dso_name, u64 addr,
char **file, unsigned int *line, struct dso *dso,
bool unwind_inlines)
bool unwind_inlines, struct inline_node *node)
{
int ret = 0;
struct a2l_data *a2l = dso->a2l;
@ -178,8 +233,21 @@ static int addr2line(const char *dso_name, u64 addr,
while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
&a2l->funcname, &a2l->line) &&
cnt++ < MAX_INLINE_NEST)
;
cnt++ < MAX_INLINE_NEST) {
if (node != NULL) {
if (inline_list__append(strdup(a2l->filename),
strdup(a2l->funcname),
a2l->line, node,
dso) != 0)
return 0;
}
}
if ((node != NULL) &&
(callchain_param.order != ORDER_CALLEE)) {
inline_list__reverse(node);
}
}
if (a2l->found && a2l->filename) {
@ -205,18 +273,68 @@ void dso__free_a2l(struct dso *dso)
dso->a2l = NULL;
}
static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
struct dso *dso)
{
char *file = NULL;
unsigned int line = 0;
struct inline_node *node;
node = zalloc(sizeof(*node));
if (node == NULL) {
perror("not enough memory for the inline node");
return NULL;
}
INIT_LIST_HEAD(&node->val);
node->addr = addr;
if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node))
goto out_free_inline_node;
if (list_empty(&node->val))
goto out_free_inline_node;
return node;
out_free_inline_node:
inline_node__delete(node);
return NULL;
}
#else /* HAVE_LIBBFD_SUPPORT */
static int filename_split(char *filename, unsigned int *line_nr)
{
char *sep;
sep = strchr(filename, '\n');
if (sep)
*sep = '\0';
if (!strcmp(filename, "??:0"))
return 0;
sep = strchr(filename, ':');
if (sep) {
*sep++ = '\0';
*line_nr = strtoul(sep, NULL, 0);
return 1;
}
return 0;
}
static int addr2line(const char *dso_name, u64 addr,
char **file, unsigned int *line_nr,
struct dso *dso __maybe_unused,
bool unwind_inlines __maybe_unused)
bool unwind_inlines __maybe_unused,
struct inline_node *node __maybe_unused)
{
FILE *fp;
char cmd[PATH_MAX];
char *filename = NULL;
size_t len;
char *sep;
int ret = 0;
scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
@ -233,23 +351,14 @@ static int addr2line(const char *dso_name, u64 addr,
goto out;
}
sep = strchr(filename, '\n');
if (sep)
*sep = '\0';
if (!strcmp(filename, "??:0")) {
pr_debug("no debugging info in %s\n", dso_name);
ret = filename_split(filename, line_nr);
if (ret != 1) {
free(filename);
goto out;
}
sep = strchr(filename, ':');
if (sep) {
*sep++ = '\0';
*file = filename;
*line_nr = strtoul(sep, NULL, 0);
ret = 1;
}
*file = filename;
out:
pclose(fp);
return ret;
@ -259,6 +368,58 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
{
}
static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
struct dso *dso __maybe_unused)
{
FILE *fp;
char cmd[PATH_MAX];
struct inline_node *node;
char *filename = NULL;
size_t len;
unsigned int line_nr = 0;
scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
dso_name, addr);
fp = popen(cmd, "r");
if (fp == NULL) {
pr_err("popen failed for %s\n", dso_name);
return NULL;
}
node = zalloc(sizeof(*node));
if (node == NULL) {
perror("not enough memory for the inline node");
goto out;
}
INIT_LIST_HEAD(&node->val);
node->addr = addr;
while (getline(&filename, &len, fp) != -1) {
if (filename_split(filename, &line_nr) != 1) {
free(filename);
goto out;
}
if (inline_list__append(filename, NULL, line_nr, node,
NULL) != 0)
goto out;
filename = NULL;
}
out:
pclose(fp);
if (list_empty(&node->val)) {
inline_node__delete(node);
return NULL;
}
return node;
}
#endif /* HAVE_LIBBFD_SUPPORT */
/*
@ -268,7 +429,7 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
#define A2L_FAIL_LIMIT 123
char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
bool show_sym, bool unwind_inlines)
bool show_sym, bool show_addr, bool unwind_inlines)
{
char *file = NULL;
unsigned line = 0;
@ -278,18 +439,11 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
if (!dso->has_srcline)
goto out;
if (dso->symsrc_filename)
dso_name = dso->symsrc_filename;
else
dso_name = dso->long_name;
if (dso_name[0] == '[')
dso_name = dso__name(dso);
if (dso_name == NULL)
goto out;
if (!strncmp(dso_name, "/tmp/perf-", 10))
goto out;
if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines))
if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
goto out;
if (asprintf(&srcline, "%s:%u",
@ -309,6 +463,11 @@ out:
dso->has_srcline = 0;
dso__free_a2l(dso);
}
if (!show_addr)
return (show_sym && sym) ?
strndup(sym->name, sym->namelen) : NULL;
if (sym) {
if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
addr - sym->start) < 0)
@ -325,7 +484,32 @@ void free_srcline(char *srcline)
}
char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
bool show_sym)
bool show_sym, bool show_addr)
{
return __get_srcline(dso, addr, sym, show_sym, false);
return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
}
struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
{
const char *dso_name;
dso_name = dso__name(dso);
if (dso_name == NULL)
return NULL;
return addr2inlines(dso_name, addr, dso);
}
void inline_node__delete(struct inline_node *node)
{
struct inline_list *ilist, *tmp;
list_for_each_entry_safe(ilist, tmp, &node->val, list) {
list_del_init(&ilist->list);
zfree(&ilist->filename);
zfree(&ilist->funcname);
free(ilist);
}
free(node);
}

View File

@ -390,6 +390,11 @@ out_elf_end:
return 0;
}
char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name)
{
return demangle_sym(dso, kmodule, elf_name);
}
/*
* Align offset to 4 bytes as needed for note name and descriptor data.
*/

View File

@ -373,3 +373,10 @@ int kcore_copy(const char *from_dir __maybe_unused,
void symbol__elf_init(void)
{
}
char *dso__demangle_sym(struct dso *dso __maybe_unused,
int kmodule __maybe_unused,
char *elf_name __maybe_unused)
{
return NULL;
}

View File

@ -118,7 +118,8 @@ struct symbol_conf {
show_ref_callgraph,
hide_unresolved,
raw_trace,
report_hierarchy;
report_hierarchy,
inline_name;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
@ -305,6 +306,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
struct map *map);
char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name);
void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel);
void symbols__insert(struct rb_root *symbols, struct symbol *sym);
void symbols__fixup_duplicate(struct rb_root *symbols);

View File

@ -192,7 +192,7 @@ static int read_ftrace_printk(struct pevent *pevent)
if (!size)
return 0;
buf = malloc(size);
buf = malloc(size + 1);
if (buf == NULL)
return -1;
@ -201,6 +201,8 @@ static int read_ftrace_printk(struct pevent *pevent)
return -1;
}
buf[size] = '\0';
parse_ftrace_printk(pevent, buf, size);
free(buf);

View File

@ -287,9 +287,9 @@ struct symbol;
extern bool srcline_full_filename;
char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
bool show_sym);
bool show_sym, bool show_addr);
char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
bool show_sym, bool unwind_inlines);
bool show_sym, bool show_addr, bool unwind_inlines);
void free_srcline(char *srcline);
int perf_event_paranoid(void);
@ -364,4 +364,20 @@ int is_printable_array(char *p, unsigned int len);
int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
int unit_number__scnprintf(char *buf, size_t size, u64 n);
struct inline_list {
char *filename;
char *funcname;
unsigned int line_nr;
struct list_head list;
};
struct inline_node {
u64 addr;
struct list_head val;
};
struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr);
void inline_node__delete(struct inline_node *node);
#endif /* GIT_COMPAT_UTIL_H */