perf/urgent fixes:

- Fixes for handling compressed kernel modules (Namhyung Kim)
 
 - Fix handling old style build-id cache ($HOME/.debug/) (Namhyung Kim)
 
 - 'perf script' python/perl documentation fixes: outdated comments,
   invalid code snippets, etc (SeongJae Park)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJZOb/yAAoJENZQFvNTUqpAxnQP/1fzzDOFV/yqdocftOsLaWbx
 VtOTp8B8NrGz6Aa/XzIwNdvKSEEZGi8tLiLBoFKuIS4Q1tVJ/6yxJ20nNnt9ORui
 L4GMugCExIJJQ7IdPt77P3O8JzFWko3L/Pi8q87wwueXLQlswgPNBWWAdWAqOrED
 KCyLSq40iiuGjGKuXGIx2rlKSIJ6/T9ia68Jf0gv/NEk3H25x0wx688Eit0cWjYg
 odExpgDRsLxP67NFtaBMjL1CQ2Bi0cDJDz3lRYzjML5dJo4w6Ria3FJg1MgTm1jN
 O4gCAUT4o7otfDXGJJM9wFodNsz+YkL8rIjr5ao7cCXaZTswYzN0YxI0dX/9kgzx
 afSbL3OJNo0AjYBHcp4LrU0ez74tVbf3juNv11g5HnN2jwWHXY2nvVP5d5tRrK76
 l3GZTR7xCinDVT7aBG2XRbMn58YXNU6V3G9DAVeNkzJmSuQrSIuGuf+MlUKcmXZY
 I01wLH8qVY9t4+EbLJ2OjD8/cXrFxGiyH60uNtLwtx7M7vu1JT2dhjiEJFRhf7tm
 Gb03CKyZFB0vQYobz+dIgnchcgWPKeRrVMr6UUc0u2StnOgk3S9ZDW3u+9iP9u4n
 SnqnWhMUcJ/O1t3VA1/6kdX0sUeRbw+EDOHFrhh7fIi3M4+wacI8f4dFmXrX9pRU
 n/1C+NP4ZOjHNzsgKDtr
 =qHQl
 -----END PGP SIGNATURE-----

Merge tag 'perf-urgent-for-mingo-4.12-20170608' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent

Pull perf/urgent fixes from Arnaldo Carvalho de Melo:

 - Fixes for handling compressed kernel modules (Namhyung Kim)

 - Fix handling old style build-id cache ($HOME/.debug/) (Namhyung Kim)

 - 'perf script' python/perl documentation fixes: outdated comments,
   invalid code snippets, etc (SeongJae Park)

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-06-09 00:41:33 +02:00
commit 47c1ded7fe
12 changed files with 136 additions and 135 deletions

View File

@ -240,7 +240,11 @@ Add a probe on schedule() function 12th line with recording cpu local variable:
or or
./perf probe --add='schedule:12 cpu' ./perf probe --add='schedule:12 cpu'
this will add one or more probes which has the name start with "schedule". Add one or more probes which has the name start with "schedule".
./perf probe schedule*
or
./perf probe --add='schedule*'
Add probes on lines in schedule() function which calls update_rq_clock(). Add probes on lines in schedule() function which calls update_rq_clock().

View File

@ -39,7 +39,7 @@ EVENT HANDLERS
When perf script is invoked using a trace script, a user-defined When perf script is invoked using a trace script, a user-defined
'handler function' is called for each event in the trace. If there's 'handler function' is called for each event in the trace. If there's
no handler function defined for a given event type, the event is no handler function defined for a given event type, the event is
ignored (or passed to a 'trace_handled' function, see below) and the ignored (or passed to a 'trace_unhandled' function, see below) and the
next event is processed. next event is processed.
Most of the event's field values are passed as arguments to the Most of the event's field values are passed as arguments to the

View File

@ -149,10 +149,8 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
print "id=%d, args=%s\n" % \ print "id=%d, args=%s\n" % \
(id, args), (id, args),
def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, def trace_unhandled(event_name, context, event_fields_dict):
common_pid, common_comm): print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
print_header(event_name, common_cpu, common_secs, common_nsecs,
common_pid, common_comm)
def print_header(event_name, cpu, secs, nsecs, pid, comm): def print_header(event_name, cpu, secs, nsecs, pid, comm):
print "%-20s %5u %05u.%09u %8u %-20s " % \ print "%-20s %5u %05u.%09u %8u %-20s " % \
@ -321,7 +319,7 @@ So those are the essential steps in writing and running a script. The
process can be generalized to any tracepoint or set of tracepoints process can be generalized to any tracepoint or set of tracepoints
you're interested in - basically find the tracepoint(s) you're you're interested in - basically find the tracepoint(s) you're
interested in by looking at the list of available events shown by interested in by looking at the list of available events shown by
'perf list' and/or look in /sys/kernel/debug/tracing events for 'perf list' and/or look in /sys/kernel/debug/tracing/events/ for
detailed event and field info, record the corresponding trace data detailed event and field info, record the corresponding trace data
using 'perf record', passing it the list of interesting events, using 'perf record', passing it the list of interesting events,
generate a skeleton script using 'perf script -g python' and modify the generate a skeleton script using 'perf script -g python' and modify the
@ -334,7 +332,7 @@ right place, you can have your script listed alongside the other
scripts listed by the 'perf script -l' command e.g.: scripts listed by the 'perf script -l' command e.g.:
---- ----
root@tropicana:~# perf script -l # perf script -l
List of available trace scripts: List of available trace scripts:
wakeup-latency system-wide min/max/avg wakeup latency wakeup-latency system-wide min/max/avg wakeup latency
rw-by-file <comm> r/w activity for a program, by file rw-by-file <comm> r/w activity for a program, by file
@ -383,8 +381,6 @@ source tree:
---- ----
# ls -al kernel-source/tools/perf/scripts/python # ls -al kernel-source/tools/perf/scripts/python
root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
total 32 total 32
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
@ -399,7 +395,7 @@ otherwise your script won't show up at run-time), 'perf script -l'
should show a new entry for your script: should show a new entry for your script:
---- ----
root@tropicana:~# perf script -l # perf script -l
List of available trace scripts: List of available trace scripts:
wakeup-latency system-wide min/max/avg wakeup latency wakeup-latency system-wide min/max/avg wakeup latency
rw-by-file <comm> r/w activity for a program, by file rw-by-file <comm> r/w activity for a program, by file
@ -437,7 +433,7 @@ EVENT HANDLERS
When perf script is invoked using a trace script, a user-defined When perf script is invoked using a trace script, a user-defined
'handler function' is called for each event in the trace. If there's 'handler function' is called for each event in the trace. If there's
no handler function defined for a given event type, the event is no handler function defined for a given event type, the event is
ignored (or passed to a 'trace_handled' function, see below) and the ignored (or passed to a 'trace_unhandled' function, see below) and the
next event is processed. next event is processed.
Most of the event's field values are passed as arguments to the Most of the event's field values are passed as arguments to the
@ -532,7 +528,7 @@ can implement a set of optional functions:
gives scripts a chance to do setup tasks: gives scripts a chance to do setup tasks:
---- ----
def trace_begin: def trace_begin():
pass pass
---- ----
@ -541,7 +537,7 @@ def trace_begin:
as display results: as display results:
---- ----
def trace_end: def trace_end():
pass pass
---- ----
@ -550,8 +546,7 @@ def trace_end:
of common arguments are passed into it: of common arguments are passed into it:
---- ----
def trace_unhandled(event_name, context, common_cpu, common_secs, def trace_unhandled(event_name, context, event_fields_dict):
common_nsecs, common_pid, common_comm):
pass pass
---- ----

View File

@ -229,6 +229,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
unsigned char buf2[BUFSZ]; unsigned char buf2[BUFSZ];
size_t ret_len; size_t ret_len;
u64 objdump_addr; u64 objdump_addr;
const char *objdump_name;
char decomp_name[KMOD_DECOMP_LEN];
int ret; int ret;
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
@ -289,9 +291,25 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
state->done[state->done_cnt++] = al.map->start; state->done[state->done_cnt++] = al.map->start;
} }
objdump_name = al.map->dso->long_name;
if (dso__needs_decompress(al.map->dso)) {
if (dso__decompress_kmodule_path(al.map->dso, objdump_name,
decomp_name,
sizeof(decomp_name)) < 0) {
pr_debug("decompression failed\n");
return -1;
}
objdump_name = decomp_name;
}
/* Read the object code using objdump */ /* Read the object code using objdump */
objdump_addr = map__rip_2objdump(al.map, al.addr); objdump_addr = map__rip_2objdump(al.map, al.addr);
ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len); ret = read_via_objdump(objdump_name, objdump_addr, buf2, len);
if (dso__needs_decompress(al.map->dso))
unlink(objdump_name);
if (ret > 0) { if (ret > 0) {
/* /*
* The kernel maps are inaccurate - assume objdump is right in * The kernel maps are inaccurate - assume objdump is right in

View File

@ -1321,6 +1321,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
char linkname[PATH_MAX]; char linkname[PATH_MAX];
char *build_id_filename; char *build_id_filename;
char *build_id_path = NULL; char *build_id_path = NULL;
char *pos;
if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
!dso__is_kcore(dso)) !dso__is_kcore(dso))
@ -1340,6 +1341,13 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
if (!build_id_path) if (!build_id_path)
return -1; return -1;
/*
* old style build-id cache has name of XX/XXXXXXX.. while
* new style has XX/XXXXXXX../{elf,kallsyms,vdso}.
* extract the build-id part of dirname in the new style only.
*/
pos = strrchr(build_id_path, '/');
if (pos && strlen(pos) < SBUILD_ID_SIZE - 2)
dirname(build_id_path); dirname(build_id_path);
if (dso__is_kcore(dso) || if (dso__is_kcore(dso) ||
@ -1423,31 +1431,10 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
sizeof(symfs_filename)); sizeof(symfs_filename));
} }
} else if (dso__needs_decompress(dso)) { } else if (dso__needs_decompress(dso)) {
char tmp[PATH_MAX]; char tmp[KMOD_DECOMP_LEN];
struct kmod_path m;
int fd;
bool ret;
if (kmod_path__parse_ext(&m, symfs_filename)) if (dso__decompress_kmodule_path(dso, symfs_filename,
goto out; tmp, sizeof(tmp)) < 0)
snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX");
fd = mkstemp(tmp);
if (fd < 0) {
free(m.ext);
goto out;
}
ret = decompress_to_file(m.ext, symfs_filename, fd);
if (ret)
pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
free(m.ext);
close(fd);
if (!ret)
goto out; goto out;
strcpy(symfs_filename, tmp); strcpy(symfs_filename, tmp);

View File

@ -278,51 +278,6 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
return bf; return bf;
} }
bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
{
char *id_name = NULL, *ch;
struct stat sb;
char sbuild_id[SBUILD_ID_SIZE];
if (!dso->has_build_id)
goto err;
build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
if (!id_name)
goto err;
if (access(id_name, F_OK))
goto err;
if (lstat(id_name, &sb) == -1)
goto err;
if ((size_t)sb.st_size > size - 1)
goto err;
if (readlink(id_name, bf, size - 1) < 0)
goto err;
bf[sb.st_size] = '\0';
/*
* link should be:
* ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
*/
ch = strrchr(bf, '/');
if (!ch)
goto err;
if (ch - 3 < bf)
goto err;
free(id_name);
return strncmp(".ko", ch - 3, 3) == 0;
err:
pr_err("Invalid build id: %s\n", id_name ? :
dso->long_name ? :
dso->short_name ? :
"[unknown]");
free(id_name);
return false;
}
#define dsos__for_each_with_build_id(pos, head) \ #define dsos__for_each_with_build_id(pos, head) \
list_for_each_entry(pos, head, node) \ list_for_each_entry(pos, head, node) \
if (!pos->has_build_id) \ if (!pos->has_build_id) \

View File

@ -17,7 +17,6 @@ char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
size_t size); size_t size);
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct perf_evsel *evsel, struct perf_sample *sample, struct perf_evsel *evsel,

View File

@ -248,6 +248,64 @@ bool dso__needs_decompress(struct dso *dso)
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
} }
static int decompress_kmodule(struct dso *dso, const char *name, char *tmpbuf)
{
int fd = -1;
struct kmod_path m;
if (!dso__needs_decompress(dso))
return -1;
if (kmod_path__parse_ext(&m, dso->long_name))
return -1;
if (!m.comp)
goto out;
fd = mkstemp(tmpbuf);
if (fd < 0) {
dso->load_errno = errno;
goto out;
}
if (!decompress_to_file(m.ext, name, fd)) {
dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
close(fd);
fd = -1;
}
out:
free(m.ext);
return fd;
}
int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
{
char tmpbuf[] = KMOD_DECOMP_NAME;
int fd;
fd = decompress_kmodule(dso, name, tmpbuf);
unlink(tmpbuf);
return fd;
}
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
char *pathname, size_t len)
{
char tmpbuf[] = KMOD_DECOMP_NAME;
int fd;
fd = decompress_kmodule(dso, name, tmpbuf);
if (fd < 0) {
unlink(tmpbuf);
return -1;
}
strncpy(pathname, tmpbuf, len);
close(fd);
return 0;
}
/* /*
* Parses kernel module specified in @path and updates * Parses kernel module specified in @path and updates
* @m argument like: * @m argument like:
@ -396,7 +454,7 @@ static int do_open(char *name)
static int __open_dso(struct dso *dso, struct machine *machine) static int __open_dso(struct dso *dso, struct machine *machine)
{ {
int fd; int fd = -EINVAL;
char *root_dir = (char *)""; char *root_dir = (char *)"";
char *name = malloc(PATH_MAX); char *name = malloc(PATH_MAX);
@ -407,15 +465,30 @@ static int __open_dso(struct dso *dso, struct machine *machine)
root_dir = machine->root_dir; root_dir = machine->root_dir;
if (dso__read_binary_type_filename(dso, dso->binary_type, if (dso__read_binary_type_filename(dso, dso->binary_type,
root_dir, name, PATH_MAX)) { root_dir, name, PATH_MAX))
free(name); goto out;
return -EINVAL;
}
if (!is_regular_file(name)) if (!is_regular_file(name))
return -EINVAL; goto out;
if (dso__needs_decompress(dso)) {
char newpath[KMOD_DECOMP_LEN];
size_t len = sizeof(newpath);
if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
fd = -dso->load_errno;
goto out;
}
strcpy(name, newpath);
}
fd = do_open(name); fd = do_open(name);
if (dso__needs_decompress(dso))
unlink(name);
out:
free(name); free(name);
return fd; return fd;
} }

View File

@ -244,6 +244,12 @@ bool is_supported_compression(const char *ext);
bool is_kernel_module(const char *pathname, int cpumode); bool is_kernel_module(const char *pathname, int cpumode);
bool decompress_to_file(const char *ext, const char *filename, int output_fd); bool decompress_to_file(const char *ext, const char *filename, int output_fd);
bool dso__needs_decompress(struct dso *dso); bool dso__needs_decompress(struct dso *dso);
int dso__decompress_kmodule_fd(struct dso *dso, const char *name);
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
char *pathname, size_t len);
#define KMOD_DECOMP_NAME "/tmp/perf-kmod-XXXXXX"
#define KMOD_DECOMP_LEN sizeof(KMOD_DECOMP_NAME)
struct kmod_path { struct kmod_path {
char *name; char *name;

View File

@ -1219,7 +1219,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
fprintf(ofp, "# be retrieved using Python functions of the form " fprintf(ofp, "# be retrieved using Python functions of the form "
"common_*(context).\n"); "common_*(context).\n");
fprintf(ofp, "# See the perf-trace-python Documentation for the list " fprintf(ofp, "# See the perf-script-python Documentation for the list "
"of available functions.\n\n"); "of available functions.\n\n");
fprintf(ofp, "import os\n"); fprintf(ofp, "import os\n");

View File

@ -637,40 +637,6 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
return 0; return 0;
} }
static int decompress_kmodule(struct dso *dso, const char *name,
enum dso_binary_type type)
{
int fd = -1;
char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
struct kmod_path m;
if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP &&
type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
return -1;
if (kmod_path__parse_ext(&m, dso->long_name) || !m.comp)
return -1;
fd = mkstemp(tmpbuf);
if (fd < 0) {
dso->load_errno = errno;
goto out;
}
if (!decompress_to_file(m.ext, name, fd)) {
dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
close(fd);
fd = -1;
}
unlink(tmpbuf);
out:
free(m.ext);
return fd;
}
bool symsrc__possibly_runtime(struct symsrc *ss) bool symsrc__possibly_runtime(struct symsrc *ss)
{ {
return ss->dynsym || ss->opdsec; return ss->dynsym || ss->opdsec;
@ -702,9 +668,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
int fd; int fd;
if (dso__needs_decompress(dso)) { if (dso__needs_decompress(dso)) {
fd = decompress_kmodule(dso, name, type); fd = dso__decompress_kmodule_fd(dso, name);
if (fd < 0) if (fd < 0)
return -1; return -1;
type = dso->symtab_type;
} else { } else {
fd = open(name, O_RDONLY); fd = open(name, O_RDONLY);
if (fd < 0) { if (fd < 0) {

View File

@ -1562,10 +1562,6 @@ int dso__load(struct dso *dso, struct map *map)
if (!runtime_ss && syms_ss) if (!runtime_ss && syms_ss)
runtime_ss = syms_ss; runtime_ss = syms_ss;
if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
if (dso__build_id_is_kmod(dso, name, PATH_MAX))
kmod = true;
if (syms_ss) if (syms_ss)
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod);
else else