forked from Minki/linux
perf/core improvements and fixes:
New features: - Deref sys_enter pointer args with contents from probe:vfs_getname, showing pathnames instead of pointers in many syscalls in 'perf trace' (Arnaldo Carvalho de Melo) - Make 'perf trace' write to stderr by default, just like 'strace' (Milian Woff) Infrastructure: - color_vfprintf() fixes (Andi Kleen, Jiri Olsa) - Allow enabling/disabling PERF_SAMPLE_TIME per event (Kan Liang) - Fix build errors with mipsel-linux-uclibc compiler (Petri Gynther) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVwm0wAAoJENZQFvNTUqpAGVYP/2BtmXxH3/b86oirAnMkZAuw LkfWsH36w/tywPlYK8ZXV580NDSj94qQXc1MporSGQHVz28z3+NkIrFBGrSMt5tW TEOIB4Qbd37P0f+xoOm7BsLNaAZWUr+kAmxXtk5ihiFFHENuuhcJH48di+toJtoM zcYQ6yayJb9opFiauBcVqHiYcSclKtJWZirQnWh25FxqzTEc+0Wt4G5V0NWLNd5+ nInwy1CMQVBIDisjI0lE9ErKEjzj92KD0SYtOLAnXnCV9FmlUaQlbn7g8jLlouRD lDT+49ntXa/yMVDS5ZHTcJ6Khc5W7S+5YyI10VC0T+T1NOiqSK09LFysfrmkq5ot oa2OOTd5iRWv5fDoovxjn24KJuhp23C4o0k4ElGrr5jrEflysWyPB8teeqCZ5FlN Vy/RRqWxUZeYcNUWBrC6h/fg6erbklPgUZkTR4dD00S14lPyYMGPutUNAFCj2vQ+ fUqacpAKarfV37k435+V+eCHAr57jDQH0AAOkNcOrI4IXCDi6T8dAzbofJD2D0aG 9IHzxMqsDMcOnYCBlVhyoKbt6pTSbEHEOUm7l7l7fLvEFrflRM7wWi04TzlYFX+i pAnpZW6yBho3OncUS6h9zGMhMYYLTGfzR2kCtP49CQCSfbqM/RCX2GiS/t95GNoE CfKn+8IptRUrYkOLw8LM =fgez -----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: New features: - Deref sys_enter pointer args with contents from probe:vfs_getname, showing pathnames instead of pointers in many syscalls in 'perf trace'. (Arnaldo Carvalho de Melo) - Make 'perf trace' write to stderr by default, just like 'strace'. (Milian Woff) Infrastructure changes: - color_vfprintf() fixes. (Andi Kleen, Jiri Olsa) - Allow enabling/disabling PERF_SAMPLE_TIME per event. (Kan Liang) - Fix build errors with mipsel-linux-uclibc compiler. (Petri Gynther) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
b6b6c18fcd
@ -1,8 +1,19 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(__UCLIBC__)
|
||||
#include <gnu/libc-version.h>
|
||||
#else
|
||||
#define XSTR(s) STR(s)
|
||||
#define STR(s) #s
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#if !defined(__UCLIBC__)
|
||||
const char *version = gnu_get_libc_version();
|
||||
#else
|
||||
const char *version = XSTR(__GLIBC__) "." XSTR(__GLIBC_MINOR__);
|
||||
#endif
|
||||
|
||||
return (long)version;
|
||||
}
|
||||
|
@ -49,7 +49,9 @@ OPTIONS
|
||||
These params can be used to overload default config values per event.
|
||||
Here is a list of the params.
|
||||
- 'period': Set event sampling period
|
||||
|
||||
- 'time': Disable/enable time stamping. Acceptable values are 1 for
|
||||
enabling time stamping. 0 for disabling time stamping.
|
||||
The default is 1.
|
||||
Note: If user explicitly sets options which conflict with the params,
|
||||
the value set by the params will be overridden.
|
||||
|
||||
|
@ -779,7 +779,7 @@ int record_parse_callchain_opt(const struct option *opt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = parse_callchain_record_opt(arg);
|
||||
ret = parse_callchain_record_opt(arg, &callchain_param);
|
||||
if (!ret)
|
||||
callchain_debug();
|
||||
|
||||
|
@ -1861,7 +1861,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
else
|
||||
symbol_conf.use_callchain = false;
|
||||
|
||||
if (pevent_set_function_resolver(session->tevent.pevent,
|
||||
if (session->tevent.pevent &&
|
||||
pevent_set_function_resolver(session->tevent.pevent,
|
||||
machine__resolve_kernel_addr,
|
||||
&session->machines.host) < 0) {
|
||||
pr_err("%s: failed to set libtraceevent function resolver\n", __func__);
|
||||
|
@ -744,6 +744,11 @@ static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
|
||||
|
||||
#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
|
||||
|
||||
static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
|
||||
struct syscall_arg *arg);
|
||||
|
||||
#define SCA_FILENAME syscall_arg__scnprintf_filename
|
||||
|
||||
static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
|
||||
struct syscall_arg *arg)
|
||||
{
|
||||
@ -971,14 +976,23 @@ static struct syscall_fmt {
|
||||
bool hexret;
|
||||
} syscall_fmts[] = {
|
||||
{ .name = "access", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
|
||||
[1] = SCA_ACCMODE, /* mode */ }, },
|
||||
{ .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
|
||||
{ .name = "brk", .hexret = true,
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
|
||||
{ .name = "chdir", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "chmod", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "chroot", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
|
||||
{ .name = "close", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
|
||||
{ .name = "connect", .errmsg = true, },
|
||||
{ .name = "creat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "dup", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "dup2", .errmsg = true,
|
||||
@ -989,7 +1003,8 @@ static struct syscall_fmt {
|
||||
{ .name = "eventfd2", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
|
||||
{ .name = "faccessat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[1] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "fadvise64", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "fallocate", .errmsg = true,
|
||||
@ -1003,7 +1018,8 @@ static struct syscall_fmt {
|
||||
{ .name = "fchown", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "fchownat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */
|
||||
[1] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "fcntl", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */
|
||||
[1] = SCA_STRARRAY, /* cmd */ },
|
||||
@ -1018,7 +1034,8 @@ static struct syscall_fmt {
|
||||
{ .name = "fstat", .errmsg = true, .alias = "newfstat",
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "fstatat", .errmsg = true, .alias = "newfstatat",
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[1] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "fstatfs", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "fsync", .errmsg = true,
|
||||
@ -1035,6 +1052,10 @@ static struct syscall_fmt {
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
|
||||
{ .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
|
||||
{ .name = "getxattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "inotify_add_watch", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "ioctl", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
@ -1049,18 +1070,33 @@ static struct syscall_fmt {
|
||||
#endif
|
||||
{ .name = "kill", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
|
||||
{ .name = "lchown", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "lgetxattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "linkat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
|
||||
{ .name = "listxattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "lseek", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */
|
||||
[2] = SCA_STRARRAY, /* whence */ },
|
||||
.arg_parm = { [2] = &strarray__whences, /* whence */ }, },
|
||||
{ .name = "lsetxattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "lstat", .errmsg = true, .alias = "newlstat", },
|
||||
{ .name = "lsxattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "madvise", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* start */
|
||||
[2] = SCA_MADV_BHV, /* behavior */ }, },
|
||||
{ .name = "mkdir", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "mkdirat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */
|
||||
[1] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "mknod", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "mknodat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
|
||||
{ .name = "mlock", .errmsg = true,
|
||||
@ -1086,14 +1122,17 @@ static struct syscall_fmt {
|
||||
{ .name = "name_to_handle_at", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
{ .name = "newfstatat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[1] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "open", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
|
||||
[1] = SCA_OPEN_FLAGS, /* flags */ }, },
|
||||
{ .name = "open_by_handle_at", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[2] = SCA_OPEN_FLAGS, /* flags */ }, },
|
||||
{ .name = "openat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[1] = SCA_FILENAME, /* filename */
|
||||
[2] = SCA_OPEN_FLAGS, /* flags */ }, },
|
||||
{ .name = "perf_event_open", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_INT, /* pid */
|
||||
@ -1115,8 +1154,11 @@ static struct syscall_fmt {
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "read", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "readlink", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
|
||||
{ .name = "readlinkat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[1] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "readv", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "recvfrom", .errmsg = true,
|
||||
@ -1125,8 +1167,12 @@ static struct syscall_fmt {
|
||||
.arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
|
||||
{ .name = "recvmsg", .errmsg = true,
|
||||
.arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
|
||||
{ .name = "removexattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "renameat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
{ .name = "rmdir", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "rt_sigaction", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
|
||||
{ .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
|
||||
@ -1143,6 +1189,8 @@ static struct syscall_fmt {
|
||||
.arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
|
||||
{ .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
|
||||
{ .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
|
||||
{ .name = "setxattr", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "shutdown", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "socket", .errmsg = true,
|
||||
@ -1154,17 +1202,31 @@ static struct syscall_fmt {
|
||||
[1] = SCA_SK_TYPE, /* type */ },
|
||||
.arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
|
||||
{ .name = "stat", .errmsg = true, .alias = "newstat", },
|
||||
{ .name = "statfs", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "swapoff", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
|
||||
{ .name = "swapon", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
|
||||
{ .name = "symlinkat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
{ .name = "tgkill", .errmsg = true,
|
||||
.arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
|
||||
{ .name = "tkill", .errmsg = true,
|
||||
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
|
||||
{ .name = "truncate", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
|
||||
{ .name = "uname", .errmsg = true, .alias = "newuname", },
|
||||
{ .name = "unlinkat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
|
||||
[1] = SCA_FILENAME, /* pathname */ }, },
|
||||
{ .name = "utime", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "utimensat", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
|
||||
.arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
|
||||
[1] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "utimes", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
|
||||
{ .name = "write", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
|
||||
{ .name = "writev", .errmsg = true,
|
||||
@ -1208,6 +1270,11 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
|
||||
return printed + fprintf(fp, "): ");
|
||||
}
|
||||
|
||||
/**
|
||||
* filename.ptr: The filename char pointer that will be vfs_getname'd
|
||||
* filename.entry_str_pos: Where to insert the string translated from
|
||||
* filename.ptr by the vfs_getname tracepoint/kprobe.
|
||||
*/
|
||||
struct thread_trace {
|
||||
u64 entry_time;
|
||||
u64 exit_time;
|
||||
@ -1216,6 +1283,10 @@ struct thread_trace {
|
||||
unsigned long pfmaj, pfmin;
|
||||
char *entry_str;
|
||||
double runtime_ms;
|
||||
struct {
|
||||
unsigned long ptr;
|
||||
int entry_str_pos;
|
||||
} filename;
|
||||
struct {
|
||||
int max;
|
||||
char **table;
|
||||
@ -1262,6 +1333,8 @@ fail:
|
||||
#define TRACE_PFMAJ (1 << 0)
|
||||
#define TRACE_PFMIN (1 << 1)
|
||||
|
||||
static const size_t trace__entry_str_size = 2048;
|
||||
|
||||
struct trace {
|
||||
struct perf_tool tool;
|
||||
struct {
|
||||
@ -1312,6 +1385,7 @@ struct trace {
|
||||
bool show_tool_stats;
|
||||
bool trace_syscalls;
|
||||
bool force;
|
||||
bool vfs_getname;
|
||||
int trace_pgfaults;
|
||||
};
|
||||
|
||||
@ -1415,6 +1489,27 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
|
||||
return printed;
|
||||
}
|
||||
|
||||
static void thread__set_filename_pos(struct thread *thread, const char *bf,
|
||||
unsigned long ptr)
|
||||
{
|
||||
struct thread_trace *ttrace = thread__priv(thread);
|
||||
|
||||
ttrace->filename.ptr = ptr;
|
||||
ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
|
||||
}
|
||||
|
||||
static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
|
||||
struct syscall_arg *arg)
|
||||
{
|
||||
unsigned long ptr = arg->val;
|
||||
|
||||
if (!arg->trace->vfs_getname)
|
||||
return scnprintf(bf, size, "%#x", ptr);
|
||||
|
||||
thread__set_filename_pos(arg->thread, bf, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool trace__filter_duration(struct trace *trace, double t)
|
||||
{
|
||||
return t < (trace->duration_filter * NSEC_PER_MSEC);
|
||||
@ -1821,7 +1916,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
|
||||
args = perf_evsel__sc_tp_ptr(evsel, args, sample);
|
||||
|
||||
if (ttrace->entry_str == NULL) {
|
||||
ttrace->entry_str = malloc(1024);
|
||||
ttrace->entry_str = malloc(trace__entry_str_size);
|
||||
if (!ttrace->entry_str)
|
||||
goto out_put;
|
||||
}
|
||||
@ -1831,9 +1926,9 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
|
||||
|
||||
ttrace->entry_time = sample->time;
|
||||
msg = ttrace->entry_str;
|
||||
printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
|
||||
printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
|
||||
|
||||
printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
|
||||
printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
|
||||
args, trace, thread);
|
||||
|
||||
if (sc->is_exit) {
|
||||
@ -1935,7 +2030,45 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
||||
struct thread_trace *ttrace;
|
||||
size_t filename_len, entry_str_len, to_move;
|
||||
ssize_t remaining_space;
|
||||
char *pos;
|
||||
const char *filename;
|
||||
|
||||
trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
|
||||
|
||||
if (!thread)
|
||||
goto out;
|
||||
|
||||
ttrace = thread__priv(thread);
|
||||
if (!ttrace)
|
||||
goto out;
|
||||
|
||||
if (!ttrace->filename.ptr)
|
||||
goto out;
|
||||
|
||||
entry_str_len = strlen(ttrace->entry_str);
|
||||
remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
|
||||
if (remaining_space <= 0)
|
||||
goto out;
|
||||
|
||||
filename = trace->last_vfs_getname;
|
||||
filename_len = strlen(filename);
|
||||
if (filename_len > (size_t)remaining_space) {
|
||||
filename += filename_len - remaining_space;
|
||||
filename_len = remaining_space;
|
||||
}
|
||||
|
||||
to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
|
||||
pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
|
||||
memmove(pos + filename_len, pos, to_move);
|
||||
memcpy(pos, filename, filename_len);
|
||||
|
||||
ttrace->filename.ptr = 0;
|
||||
ttrace->filename.entry_str_pos = 0;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2188,19 +2321,20 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
|
||||
|
||||
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
|
||||
|
||||
static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
|
||||
static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
|
||||
if (evsel == NULL)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (perf_evsel__field(evsel, "pathname") == NULL) {
|
||||
perf_evsel__delete(evsel);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
evsel->handler = trace__vfs_getname;
|
||||
perf_evlist__add(evlist, evsel);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
|
||||
@ -2330,7 +2464,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
||||
goto out_error_raw_syscalls;
|
||||
|
||||
if (trace->trace_syscalls)
|
||||
perf_evlist__add_vfs_getname(evlist);
|
||||
trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
|
||||
|
||||
if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
|
||||
perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
|
||||
@ -2394,9 +2528,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
||||
err = trace__set_ev_qualifier_filter(trace);
|
||||
if (err < 0)
|
||||
goto out_errno;
|
||||
}
|
||||
|
||||
pr_debug("%s\n", trace->syscalls.events.sys_exit->filter);
|
||||
pr_debug("event qualifier tracepoint filter: %s\n",
|
||||
trace->syscalls.events.sys_exit->filter);
|
||||
}
|
||||
|
||||
err = perf_evlist__apply_filters(evlist, &evsel);
|
||||
if (err < 0)
|
||||
@ -2830,7 +2965,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
.mmap_pages = UINT_MAX,
|
||||
.proc_map_timeout = 500,
|
||||
},
|
||||
.output = stdout,
|
||||
.output = stderr,
|
||||
.show_comm = true,
|
||||
.trace_syscalls = true,
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ static int get_stack_size(const char *str, unsigned long *_size)
|
||||
}
|
||||
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
|
||||
|
||||
int parse_callchain_record_opt(const char *arg)
|
||||
int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
|
||||
{
|
||||
char *tok, *name, *saveptr = NULL;
|
||||
char *buf;
|
||||
@ -73,7 +73,7 @@ int parse_callchain_record_opt(const char *arg)
|
||||
/* Framepointer style */
|
||||
if (!strncmp(name, "fp", sizeof("fp"))) {
|
||||
if (!strtok_r(NULL, ",", &saveptr)) {
|
||||
callchain_param.record_mode = CALLCHAIN_FP;
|
||||
param->record_mode = CALLCHAIN_FP;
|
||||
ret = 0;
|
||||
} else
|
||||
pr_err("callchain: No more arguments "
|
||||
@ -86,20 +86,20 @@ int parse_callchain_record_opt(const char *arg)
|
||||
const unsigned long default_stack_dump_size = 8192;
|
||||
|
||||
ret = 0;
|
||||
callchain_param.record_mode = CALLCHAIN_DWARF;
|
||||
callchain_param.dump_size = default_stack_dump_size;
|
||||
param->record_mode = CALLCHAIN_DWARF;
|
||||
param->dump_size = default_stack_dump_size;
|
||||
|
||||
tok = strtok_r(NULL, ",", &saveptr);
|
||||
if (tok) {
|
||||
unsigned long size = 0;
|
||||
|
||||
ret = get_stack_size(tok, &size);
|
||||
callchain_param.dump_size = size;
|
||||
param->dump_size = size;
|
||||
}
|
||||
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
|
||||
} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
|
||||
if (!strtok_r(NULL, ",", &saveptr)) {
|
||||
callchain_param.record_mode = CALLCHAIN_LBR;
|
||||
param->record_mode = CALLCHAIN_LBR;
|
||||
ret = 0;
|
||||
} else
|
||||
pr_err("callchain: No more arguments "
|
||||
@ -219,7 +219,7 @@ int perf_callchain_config(const char *var, const char *value)
|
||||
var += sizeof("call-graph.") - 1;
|
||||
|
||||
if (!strcmp(var, "record-mode"))
|
||||
return parse_callchain_record_opt(value);
|
||||
return parse_callchain_record_opt(value, &callchain_param);
|
||||
#ifdef HAVE_DWARF_UNWIND_SUPPORT
|
||||
if (!strcmp(var, "dump-size")) {
|
||||
unsigned long size = 0;
|
||||
|
@ -177,7 +177,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
|
||||
bool hide_unresolved);
|
||||
|
||||
extern const char record_callchain_help[];
|
||||
int parse_callchain_record_opt(const char *arg);
|
||||
int parse_callchain_record_opt(const char *arg, struct callchain_param *param);
|
||||
int parse_callchain_report_opt(const char *arg);
|
||||
int perf_callchain_config(const char *var, const char *value);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
unsigned long perf_event_open_cloexec_flag(void);
|
||||
|
||||
#ifdef __GLIBC_PREREQ
|
||||
#if !__GLIBC_PREREQ(2, 6)
|
||||
#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
|
||||
extern int sched_getcpu(void) __THROW;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -67,8 +67,9 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Colors are not included in return value */
|
||||
static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
|
||||
va_list args, const char *trail)
|
||||
va_list args)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
@ -83,12 +84,10 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
|
||||
}
|
||||
|
||||
if (perf_use_color_default && *color)
|
||||
r += fprintf(fp, "%s", color);
|
||||
fprintf(fp, "%s", color);
|
||||
r += vfprintf(fp, fmt, args);
|
||||
if (perf_use_color_default && *color)
|
||||
r += fprintf(fp, "%s", PERF_COLOR_RESET);
|
||||
if (trail)
|
||||
r += fprintf(fp, "%s", trail);
|
||||
fprintf(fp, "%s", PERF_COLOR_RESET);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -100,7 +99,7 @@ int color_vsnprintf(char *bf, size_t size, const char *color,
|
||||
|
||||
int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
|
||||
{
|
||||
return __color_vfprintf(fp, color, fmt, args, NULL);
|
||||
return __color_vfprintf(fp, color, fmt, args);
|
||||
}
|
||||
|
||||
int color_snprintf(char *bf, size_t size, const char *color,
|
||||
@ -126,16 +125,6 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
|
||||
return r;
|
||||
}
|
||||
|
||||
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int r;
|
||||
va_start(args, fmt);
|
||||
r = __color_vfprintf(fp, color, fmt, args, "\n");
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function splits the buffer by newlines and colors the lines individually.
|
||||
*
|
||||
|
@ -35,7 +35,6 @@ int color_vsnprintf(char *bf, size_t size, const char *color,
|
||||
int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
|
||||
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
|
||||
int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
|
||||
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
|
||||
int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
|
||||
int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
|
||||
int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
|
||||
|
@ -545,14 +545,15 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
|
||||
|
||||
static void
|
||||
perf_evsel__config_callgraph(struct perf_evsel *evsel,
|
||||
struct record_opts *opts)
|
||||
struct record_opts *opts,
|
||||
struct callchain_param *param)
|
||||
{
|
||||
bool function = perf_evsel__is_function_event(evsel);
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
|
||||
perf_evsel__set_sample_bit(evsel, CALLCHAIN);
|
||||
|
||||
if (callchain_param.record_mode == CALLCHAIN_LBR) {
|
||||
if (param->record_mode == CALLCHAIN_LBR) {
|
||||
if (!opts->branch_stack) {
|
||||
if (attr->exclude_user) {
|
||||
pr_warning("LBR callstack option is only available "
|
||||
@ -568,12 +569,12 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
|
||||
"Falling back to framepointers.\n");
|
||||
}
|
||||
|
||||
if (callchain_param.record_mode == CALLCHAIN_DWARF) {
|
||||
if (param->record_mode == CALLCHAIN_DWARF) {
|
||||
if (!function) {
|
||||
perf_evsel__set_sample_bit(evsel, REGS_USER);
|
||||
perf_evsel__set_sample_bit(evsel, STACK_USER);
|
||||
attr->sample_regs_user = PERF_REGS_MASK;
|
||||
attr->sample_stack_user = callchain_param.dump_size;
|
||||
attr->sample_stack_user = param->dump_size;
|
||||
attr->exclude_callchain_user = 1;
|
||||
} else {
|
||||
pr_info("Cannot use DWARF unwind for function trace event,"
|
||||
@ -587,15 +588,23 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_config_terms(struct perf_event_attr *attr __maybe_unused,
|
||||
struct list_head *config_terms)
|
||||
static void apply_config_terms(struct perf_evsel *evsel)
|
||||
{
|
||||
struct perf_evsel_config_term *term;
|
||||
struct list_head *config_terms = &evsel->config_terms;
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
|
||||
list_for_each_entry(term, config_terms, list) {
|
||||
switch (term->type) {
|
||||
case PERF_EVSEL__CONFIG_TERM_PERIOD:
|
||||
attr->sample_period = term->val.period;
|
||||
break;
|
||||
case PERF_EVSEL__CONFIG_TERM_TIME:
|
||||
if (term->val.time)
|
||||
perf_evsel__set_sample_bit(evsel, TIME);
|
||||
else
|
||||
perf_evsel__reset_sample_bit(evsel, TIME);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -706,7 +715,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
|
||||
evsel->attr.exclude_callchain_user = 1;
|
||||
|
||||
if (callchain_param.enabled && !evsel->no_aux_samples)
|
||||
perf_evsel__config_callgraph(evsel, opts);
|
||||
perf_evsel__config_callgraph(evsel, opts, &callchain_param);
|
||||
|
||||
if (opts->sample_intr_regs) {
|
||||
attr->sample_regs_intr = PERF_REGS_MASK;
|
||||
@ -798,7 +807,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
|
||||
* Apply event specific term settings,
|
||||
* it overloads any global configuration.
|
||||
*/
|
||||
apply_config_terms(attr, &evsel->config_terms);
|
||||
apply_config_terms(evsel);
|
||||
}
|
||||
|
||||
static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
|
@ -39,6 +39,7 @@ struct cgroup_sel;
|
||||
*/
|
||||
enum {
|
||||
PERF_EVSEL__CONFIG_TERM_PERIOD,
|
||||
PERF_EVSEL__CONFIG_TERM_TIME,
|
||||
PERF_EVSEL__CONFIG_TERM_MAX,
|
||||
};
|
||||
|
||||
@ -47,6 +48,7 @@ struct perf_evsel_config_term {
|
||||
int type;
|
||||
union {
|
||||
u64 period;
|
||||
bool time;
|
||||
} val;
|
||||
};
|
||||
|
||||
|
@ -603,6 +603,14 @@ do { \
|
||||
* attr->branch_sample_type = term->val.num;
|
||||
*/
|
||||
break;
|
||||
case PARSE_EVENTS__TERM_TYPE_TIME:
|
||||
CHECK_TYPE_VAL(NUM);
|
||||
if (term->val.num > 1) {
|
||||
err->str = strdup("expected 0 or 1");
|
||||
err->idx = term->err_val;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case PARSE_EVENTS__TERM_TYPE_NAME:
|
||||
CHECK_TYPE_VAL(STR);
|
||||
break;
|
||||
@ -650,6 +658,10 @@ do { \
|
||||
switch (term->type_term) {
|
||||
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
|
||||
ADD_CONFIG_TERM(PERIOD, period, term->val.num);
|
||||
break;
|
||||
case PARSE_EVENTS__TERM_TYPE_TIME:
|
||||
ADD_CONFIG_TERM(TIME, time, term->val.num);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ enum {
|
||||
PARSE_EVENTS__TERM_TYPE_NAME,
|
||||
PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
|
||||
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
|
||||
PARSE_EVENTS__TERM_TYPE_TIME,
|
||||
};
|
||||
|
||||
struct parse_events_term {
|
||||
|
@ -183,6 +183,7 @@ config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
|
||||
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
|
||||
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
|
||||
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
|
||||
time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
|
||||
, { return ','; }
|
||||
"/" { BEGIN(INITIAL); return '/'; }
|
||||
{name_minus} { return str(yyscanner, PE_NAME); }
|
||||
|
@ -607,7 +607,7 @@ static char *formats_error_string(struct list_head *formats)
|
||||
{
|
||||
struct perf_pmu_format *format;
|
||||
char *err, *str;
|
||||
static const char *static_terms = "config,config1,config2,name,period,branch_type\n";
|
||||
static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n";
|
||||
unsigned i = 0;
|
||||
|
||||
if (!asprintf(&str, "valid terms:"))
|
||||
|
Loading…
Reference in New Issue
Block a user