aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-08-06 02:51:18 -0400
committerIngo Molnar <mingo@kernel.org>2015-08-06 02:51:18 -0400
commitb6b6c18fcd9af2a71d7b2cfca0388a928308f963 (patch)
tree2ccdd26199ce3fc1183b7ba636d73c4d8643112a
parent75f80859b130a1cc84e59e71295ce2dd51fe1c81 (diff)
parentf151f53aa4f54a647353e1935e4c6cef7f094dd4 (diff)
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>
-rw-r--r--tools/build/feature/test-glibc.c11
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/builtin-record.c2
-rw-r--r--tools/perf/builtin-script.c3
-rw-r--r--tools/perf/builtin-trace.c175
-rw-r--r--tools/perf/util/callchain.c14
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/cloexec.h2
-rw-r--r--tools/perf/util/color.c21
-rw-r--r--tools/perf/util/color.h1
-rw-r--r--tools/perf/util/evsel.c25
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/parse-events.c12
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/parse-events.l1
-rw-r--r--tools/perf/util/pmu.c2
16 files changed, 220 insertions, 58 deletions
diff --git a/tools/build/feature/test-glibc.c b/tools/build/feature/test-glibc.c
index b0820345cd98..9367f7586676 100644
--- a/tools/build/feature/test-glibc.c
+++ b/tools/build/feature/test-glibc.c
@@ -1,8 +1,19 @@
1#include <stdlib.h>
2
3#if !defined(__UCLIBC__)
1#include <gnu/libc-version.h> 4#include <gnu/libc-version.h>
5#else
6#define XSTR(s) STR(s)
7#define STR(s) #s
8#endif
2 9
3int main(void) 10int main(void)
4{ 11{
12#if !defined(__UCLIBC__)
5 const char *version = gnu_get_libc_version(); 13 const char *version = gnu_get_libc_version();
14#else
15 const char *version = XSTR(__GLIBC__) "." XSTR(__GLIBC_MINOR__);
16#endif
6 17
7 return (long)version; 18 return (long)version;
8} 19}
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index ac41350ca485..0d852d1bc90f 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -49,7 +49,9 @@ OPTIONS
49 These params can be used to overload default config values per event. 49 These params can be used to overload default config values per event.
50 Here is a list of the params. 50 Here is a list of the params.
51 - 'period': Set event sampling period 51 - 'period': Set event sampling period
52 52 - 'time': Disable/enable time stamping. Acceptable values are 1 for
53 enabling time stamping. 0 for disabling time stamping.
54 The default is 1.
53 Note: If user explicitly sets options which conflict with the params, 55 Note: If user explicitly sets options which conflict with the params,
54 the value set by the params will be overridden. 56 the value set by the params will be overridden.
55 57
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f51131b11ad7..25cf6b404e8a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -779,7 +779,7 @@ int record_parse_callchain_opt(const struct option *opt,
779 return 0; 779 return 0;
780 } 780 }
781 781
782 ret = parse_callchain_record_opt(arg); 782 ret = parse_callchain_record_opt(arg, &callchain_param);
783 if (!ret) 783 if (!ret)
784 callchain_debug(); 784 callchain_debug();
785 785
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index bd31380122f9..7912feb9a024 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1861,7 +1861,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1861 else 1861 else
1862 symbol_conf.use_callchain = false; 1862 symbol_conf.use_callchain = false;
1863 1863
1864 if (pevent_set_function_resolver(session->tevent.pevent, 1864 if (session->tevent.pevent &&
1865 pevent_set_function_resolver(session->tevent.pevent,
1865 machine__resolve_kernel_addr, 1866 machine__resolve_kernel_addr,
1866 &session->machines.host) < 0) { 1867 &session->machines.host) < 0) {
1867 pr_err("%s: failed to set libtraceevent function resolver\n", __func__); 1868 pr_err("%s: failed to set libtraceevent function resolver\n", __func__);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 06cfa93c0305..a47497011c93 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -744,6 +744,11 @@ static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
744 744
745#define SCA_ACCMODE syscall_arg__scnprintf_access_mode 745#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
746 746
747static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
748 struct syscall_arg *arg);
749
750#define SCA_FILENAME syscall_arg__scnprintf_filename
751
747static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, 752static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
748 struct syscall_arg *arg) 753 struct syscall_arg *arg)
749{ 754{
@@ -971,14 +976,23 @@ static struct syscall_fmt {
971 bool hexret; 976 bool hexret;
972} syscall_fmts[] = { 977} syscall_fmts[] = {
973 { .name = "access", .errmsg = true, 978 { .name = "access", .errmsg = true,
974 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, }, 979 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
980 [1] = SCA_ACCMODE, /* mode */ }, },
975 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 981 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
976 { .name = "brk", .hexret = true, 982 { .name = "brk", .hexret = true,
977 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, 983 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
984 { .name = "chdir", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
986 { .name = "chmod", .errmsg = true,
987 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
988 { .name = "chroot", .errmsg = true,
989 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
978 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, 990 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
979 { .name = "close", .errmsg = true, 991 { .name = "close", .errmsg = true,
980 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, 992 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
981 { .name = "connect", .errmsg = true, }, 993 { .name = "connect", .errmsg = true, },
994 { .name = "creat", .errmsg = true,
995 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
982 { .name = "dup", .errmsg = true, 996 { .name = "dup", .errmsg = true,
983 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
984 { .name = "dup2", .errmsg = true, 998 { .name = "dup2", .errmsg = true,
@@ -989,7 +1003,8 @@ static struct syscall_fmt {
989 { .name = "eventfd2", .errmsg = true, 1003 { .name = "eventfd2", .errmsg = true,
990 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, }, 1004 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
991 { .name = "faccessat", .errmsg = true, 1005 { .name = "faccessat", .errmsg = true,
992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1006 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1007 [1] = SCA_FILENAME, /* filename */ }, },
993 { .name = "fadvise64", .errmsg = true, 1008 { .name = "fadvise64", .errmsg = true,
994 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1009 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
995 { .name = "fallocate", .errmsg = true, 1010 { .name = "fallocate", .errmsg = true,
@@ -1003,7 +1018,8 @@ static struct syscall_fmt {
1003 { .name = "fchown", .errmsg = true, 1018 { .name = "fchown", .errmsg = true,
1004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1019 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1005 { .name = "fchownat", .errmsg = true, 1020 { .name = "fchownat", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1021 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1022 [1] = SCA_FILENAME, /* filename */ }, },
1007 { .name = "fcntl", .errmsg = true, 1023 { .name = "fcntl", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 1024 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1009 [1] = SCA_STRARRAY, /* cmd */ }, 1025 [1] = SCA_STRARRAY, /* cmd */ },
@@ -1018,7 +1034,8 @@ static struct syscall_fmt {
1018 { .name = "fstat", .errmsg = true, .alias = "newfstat", 1034 { .name = "fstat", .errmsg = true, .alias = "newfstat",
1019 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1020 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", 1036 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
1021 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1037 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1038 [1] = SCA_FILENAME, /* filename */ }, },
1022 { .name = "fstatfs", .errmsg = true, 1039 { .name = "fstatfs", .errmsg = true,
1023 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1040 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1024 { .name = "fsync", .errmsg = true, 1041 { .name = "fsync", .errmsg = true,
@@ -1035,6 +1052,10 @@ static struct syscall_fmt {
1035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1052 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1036 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 1053 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1037 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 1054 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
1055 { .name = "getxattr", .errmsg = true,
1056 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1057 { .name = "inotify_add_watch", .errmsg = true,
1058 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
1038 { .name = "ioctl", .errmsg = true, 1059 { .name = "ioctl", .errmsg = true,
1039 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1040#if defined(__i386__) || defined(__x86_64__) 1061#if defined(__i386__) || defined(__x86_64__)
@@ -1049,18 +1070,33 @@ static struct syscall_fmt {
1049#endif 1070#endif
1050 { .name = "kill", .errmsg = true, 1071 { .name = "kill", .errmsg = true,
1051 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, 1072 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1073 { .name = "lchown", .errmsg = true,
1074 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1075 { .name = "lgetxattr", .errmsg = true,
1076 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1052 { .name = "linkat", .errmsg = true, 1077 { .name = "linkat", .errmsg = true,
1053 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1078 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1079 { .name = "listxattr", .errmsg = true,
1080 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1054 { .name = "lseek", .errmsg = true, 1081 { .name = "lseek", .errmsg = true,
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 1082 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1056 [2] = SCA_STRARRAY, /* whence */ }, 1083 [2] = SCA_STRARRAY, /* whence */ },
1057 .arg_parm = { [2] = &strarray__whences, /* whence */ }, }, 1084 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
1085 { .name = "lsetxattr", .errmsg = true,
1086 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1058 { .name = "lstat", .errmsg = true, .alias = "newlstat", }, 1087 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
1088 { .name = "lsxattr", .errmsg = true,
1089 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1059 { .name = "madvise", .errmsg = true, 1090 { .name = "madvise", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 1091 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1061 [2] = SCA_MADV_BHV, /* behavior */ }, }, 1092 [2] = SCA_MADV_BHV, /* behavior */ }, },
1093 { .name = "mkdir", .errmsg = true,
1094 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1062 { .name = "mkdirat", .errmsg = true, 1095 { .name = "mkdirat", .errmsg = true,
1063 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1096 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1097 [1] = SCA_FILENAME, /* pathname */ }, },
1098 { .name = "mknod", .errmsg = true,
1099 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1064 { .name = "mknodat", .errmsg = true, 1100 { .name = "mknodat", .errmsg = true,
1065 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1101 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1066 { .name = "mlock", .errmsg = true, 1102 { .name = "mlock", .errmsg = true,
@@ -1086,14 +1122,17 @@ static struct syscall_fmt {
1086 { .name = "name_to_handle_at", .errmsg = true, 1122 { .name = "name_to_handle_at", .errmsg = true,
1087 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1123 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1088 { .name = "newfstatat", .errmsg = true, 1124 { .name = "newfstatat", .errmsg = true,
1089 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1125 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1126 [1] = SCA_FILENAME, /* filename */ }, },
1090 { .name = "open", .errmsg = true, 1127 { .name = "open", .errmsg = true,
1091 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, 1128 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1129 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
1092 { .name = "open_by_handle_at", .errmsg = true, 1130 { .name = "open_by_handle_at", .errmsg = true,
1093 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 1131 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1094 [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 1132 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
1095 { .name = "openat", .errmsg = true, 1133 { .name = "openat", .errmsg = true,
1096 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 1134 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1135 [1] = SCA_FILENAME, /* filename */
1097 [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 1136 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
1098 { .name = "perf_event_open", .errmsg = true, 1137 { .name = "perf_event_open", .errmsg = true,
1099 .arg_scnprintf = { [1] = SCA_INT, /* pid */ 1138 .arg_scnprintf = { [1] = SCA_INT, /* pid */
@@ -1115,8 +1154,11 @@ static struct syscall_fmt {
1115 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1154 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1116 { .name = "read", .errmsg = true, 1155 { .name = "read", .errmsg = true,
1117 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1156 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1157 { .name = "readlink", .errmsg = true,
1158 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
1118 { .name = "readlinkat", .errmsg = true, 1159 { .name = "readlinkat", .errmsg = true,
1119 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1160 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1161 [1] = SCA_FILENAME, /* pathname */ }, },
1120 { .name = "readv", .errmsg = true, 1162 { .name = "readv", .errmsg = true,
1121 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1163 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1122 { .name = "recvfrom", .errmsg = true, 1164 { .name = "recvfrom", .errmsg = true,
@@ -1125,8 +1167,12 @@ static struct syscall_fmt {
1125 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, 1167 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1126 { .name = "recvmsg", .errmsg = true, 1168 { .name = "recvmsg", .errmsg = true,
1127 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, 1169 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1170 { .name = "removexattr", .errmsg = true,
1171 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1128 { .name = "renameat", .errmsg = true, 1172 { .name = "renameat", .errmsg = true,
1129 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1173 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1174 { .name = "rmdir", .errmsg = true,
1175 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1130 { .name = "rt_sigaction", .errmsg = true, 1176 { .name = "rt_sigaction", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, 1177 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
1132 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, 1178 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
@@ -1143,6 +1189,8 @@ static struct syscall_fmt {
1143 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, 1189 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1144 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 1190 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1145 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 1191 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
1192 { .name = "setxattr", .errmsg = true,
1193 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1146 { .name = "shutdown", .errmsg = true, 1194 { .name = "shutdown", .errmsg = true,
1147 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1195 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1148 { .name = "socket", .errmsg = true, 1196 { .name = "socket", .errmsg = true,
@@ -1154,17 +1202,31 @@ static struct syscall_fmt {
1154 [1] = SCA_SK_TYPE, /* type */ }, 1202 [1] = SCA_SK_TYPE, /* type */ },
1155 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, 1203 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1156 { .name = "stat", .errmsg = true, .alias = "newstat", }, 1204 { .name = "stat", .errmsg = true, .alias = "newstat", },
1205 { .name = "statfs", .errmsg = true,
1206 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1207 { .name = "swapoff", .errmsg = true,
1208 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1209 { .name = "swapon", .errmsg = true,
1210 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1157 { .name = "symlinkat", .errmsg = true, 1211 { .name = "symlinkat", .errmsg = true,
1158 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1212 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1159 { .name = "tgkill", .errmsg = true, 1213 { .name = "tgkill", .errmsg = true,
1160 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, 1214 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1161 { .name = "tkill", .errmsg = true, 1215 { .name = "tkill", .errmsg = true,
1162 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, 1216 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1217 { .name = "truncate", .errmsg = true,
1218 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
1163 { .name = "uname", .errmsg = true, .alias = "newuname", }, 1219 { .name = "uname", .errmsg = true, .alias = "newuname", },
1164 { .name = "unlinkat", .errmsg = true, 1220 { .name = "unlinkat", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1221 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1222 [1] = SCA_FILENAME, /* pathname */ }, },
1223 { .name = "utime", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1166 { .name = "utimensat", .errmsg = true, 1225 { .name = "utimensat", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, }, 1226 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1227 [1] = SCA_FILENAME, /* filename */ }, },
1228 { .name = "utimes", .errmsg = true,
1229 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1168 { .name = "write", .errmsg = true, 1230 { .name = "write", .errmsg = true,
1169 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1231 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1170 { .name = "writev", .errmsg = true, 1232 { .name = "writev", .errmsg = true,
@@ -1208,6 +1270,11 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
1208 return printed + fprintf(fp, "): "); 1270 return printed + fprintf(fp, "): ");
1209} 1271}
1210 1272
1273/**
1274 * filename.ptr: The filename char pointer that will be vfs_getname'd
1275 * filename.entry_str_pos: Where to insert the string translated from
1276 * filename.ptr by the vfs_getname tracepoint/kprobe.
1277 */
1211struct thread_trace { 1278struct thread_trace {
1212 u64 entry_time; 1279 u64 entry_time;
1213 u64 exit_time; 1280 u64 exit_time;
@@ -1216,6 +1283,10 @@ struct thread_trace {
1216 unsigned long pfmaj, pfmin; 1283 unsigned long pfmaj, pfmin;
1217 char *entry_str; 1284 char *entry_str;
1218 double runtime_ms; 1285 double runtime_ms;
1286 struct {
1287 unsigned long ptr;
1288 int entry_str_pos;
1289 } filename;
1219 struct { 1290 struct {
1220 int max; 1291 int max;
1221 char **table; 1292 char **table;
@@ -1262,6 +1333,8 @@ fail:
1262#define TRACE_PFMAJ (1 << 0) 1333#define TRACE_PFMAJ (1 << 0)
1263#define TRACE_PFMIN (1 << 1) 1334#define TRACE_PFMIN (1 << 1)
1264 1335
1336static const size_t trace__entry_str_size = 2048;
1337
1265struct trace { 1338struct trace {
1266 struct perf_tool tool; 1339 struct perf_tool tool;
1267 struct { 1340 struct {
@@ -1312,6 +1385,7 @@ struct trace {
1312 bool show_tool_stats; 1385 bool show_tool_stats;
1313 bool trace_syscalls; 1386 bool trace_syscalls;
1314 bool force; 1387 bool force;
1388 bool vfs_getname;
1315 int trace_pgfaults; 1389 int trace_pgfaults;
1316}; 1390};
1317 1391
@@ -1415,6 +1489,27 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1415 return printed; 1489 return printed;
1416} 1490}
1417 1491
1492static void thread__set_filename_pos(struct thread *thread, const char *bf,
1493 unsigned long ptr)
1494{
1495 struct thread_trace *ttrace = thread__priv(thread);
1496
1497 ttrace->filename.ptr = ptr;
1498 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1499}
1500
1501static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1502 struct syscall_arg *arg)
1503{
1504 unsigned long ptr = arg->val;
1505
1506 if (!arg->trace->vfs_getname)
1507 return scnprintf(bf, size, "%#x", ptr);
1508
1509 thread__set_filename_pos(arg->thread, bf, ptr);
1510 return 0;
1511}
1512
1418static bool trace__filter_duration(struct trace *trace, double t) 1513static bool trace__filter_duration(struct trace *trace, double t)
1419{ 1514{
1420 return t < (trace->duration_filter * NSEC_PER_MSEC); 1515 return t < (trace->duration_filter * NSEC_PER_MSEC);
@@ -1821,7 +1916,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1821 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1916 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1822 1917
1823 if (ttrace->entry_str == NULL) { 1918 if (ttrace->entry_str == NULL) {
1824 ttrace->entry_str = malloc(1024); 1919 ttrace->entry_str = malloc(trace__entry_str_size);
1825 if (!ttrace->entry_str) 1920 if (!ttrace->entry_str)
1826 goto out_put; 1921 goto out_put;
1827 } 1922 }
@@ -1831,9 +1926,9 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1831 1926
1832 ttrace->entry_time = sample->time; 1927 ttrace->entry_time = sample->time;
1833 msg = ttrace->entry_str; 1928 msg = ttrace->entry_str;
1834 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name); 1929 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
1835 1930
1836 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, 1931 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
1837 args, trace, thread); 1932 args, trace, thread);
1838 1933
1839 if (sc->is_exit) { 1934 if (sc->is_exit) {
@@ -1935,7 +2030,45 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1935 union perf_event *event __maybe_unused, 2030 union perf_event *event __maybe_unused,
1936 struct perf_sample *sample) 2031 struct perf_sample *sample)
1937{ 2032{
2033 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2034 struct thread_trace *ttrace;
2035 size_t filename_len, entry_str_len, to_move;
2036 ssize_t remaining_space;
2037 char *pos;
2038 const char *filename;
2039
1938 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); 2040 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
2041
2042 if (!thread)
2043 goto out;
2044
2045 ttrace = thread__priv(thread);
2046 if (!ttrace)
2047 goto out;
2048
2049 if (!ttrace->filename.ptr)
2050 goto out;
2051
2052 entry_str_len = strlen(ttrace->entry_str);
2053 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2054 if (remaining_space <= 0)
2055 goto out;
2056
2057 filename = trace->last_vfs_getname;
2058 filename_len = strlen(filename);
2059 if (filename_len > (size_t)remaining_space) {
2060 filename += filename_len - remaining_space;
2061 filename_len = remaining_space;
2062 }
2063
2064 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2065 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2066 memmove(pos + filename_len, pos, to_move);
2067 memcpy(pos, filename, filename_len);
2068
2069 ttrace->filename.ptr = 0;
2070 ttrace->filename.entry_str_pos = 0;
2071out:
1939 return 0; 2072 return 0;
1940} 2073}
1941 2074
@@ -2188,19 +2321,20 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
2188 2321
2189static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 2322static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2190 2323
2191static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist) 2324static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2192{ 2325{
2193 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname"); 2326 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
2194 if (evsel == NULL) 2327 if (evsel == NULL)
2195 return; 2328 return false;
2196 2329
2197 if (perf_evsel__field(evsel, "pathname") == NULL) { 2330 if (perf_evsel__field(evsel, "pathname") == NULL) {
2198 perf_evsel__delete(evsel); 2331 perf_evsel__delete(evsel);
2199 return; 2332 return false;
2200 } 2333 }
2201 2334
2202 evsel->handler = trace__vfs_getname; 2335 evsel->handler = trace__vfs_getname;
2203 perf_evlist__add(evlist, evsel); 2336 perf_evlist__add(evlist, evsel);
2337 return true;
2204} 2338}
2205 2339
2206static int perf_evlist__add_pgfault(struct perf_evlist *evlist, 2340static 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)
2330 goto out_error_raw_syscalls; 2464 goto out_error_raw_syscalls;
2331 2465
2332 if (trace->trace_syscalls) 2466 if (trace->trace_syscalls)
2333 perf_evlist__add_vfs_getname(evlist); 2467 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
2334 2468
2335 if ((trace->trace_pgfaults & TRACE_PFMAJ) && 2469 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2336 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) { 2470 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)
2394 err = trace__set_ev_qualifier_filter(trace); 2528 err = trace__set_ev_qualifier_filter(trace);
2395 if (err < 0) 2529 if (err < 0)
2396 goto out_errno; 2530 goto out_errno;
2397 }
2398 2531
2399 pr_debug("%s\n", trace->syscalls.events.sys_exit->filter); 2532 pr_debug("event qualifier tracepoint filter: %s\n",
2533 trace->syscalls.events.sys_exit->filter);
2534 }
2400 2535
2401 err = perf_evlist__apply_filters(evlist, &evsel); 2536 err = perf_evlist__apply_filters(evlist, &evsel);
2402 if (err < 0) 2537 if (err < 0)
@@ -2830,7 +2965,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2830 .mmap_pages = UINT_MAX, 2965 .mmap_pages = UINT_MAX,
2831 .proc_map_timeout = 500, 2966 .proc_map_timeout = 500,
2832 }, 2967 },
2833 .output = stdout, 2968 .output = stderr,
2834 .show_comm = true, 2969 .show_comm = true,
2835 .trace_syscalls = true, 2970 .trace_syscalls = true,
2836 }; 2971 };
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9f643ee77001..931cca8e6ae8 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -53,7 +53,7 @@ static int get_stack_size(const char *str, unsigned long *_size)
53} 53}
54#endif /* HAVE_DWARF_UNWIND_SUPPORT */ 54#endif /* HAVE_DWARF_UNWIND_SUPPORT */
55 55
56int parse_callchain_record_opt(const char *arg) 56int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
57{ 57{
58 char *tok, *name, *saveptr = NULL; 58 char *tok, *name, *saveptr = NULL;
59 char *buf; 59 char *buf;
@@ -73,7 +73,7 @@ int parse_callchain_record_opt(const char *arg)
73 /* Framepointer style */ 73 /* Framepointer style */
74 if (!strncmp(name, "fp", sizeof("fp"))) { 74 if (!strncmp(name, "fp", sizeof("fp"))) {
75 if (!strtok_r(NULL, ",", &saveptr)) { 75 if (!strtok_r(NULL, ",", &saveptr)) {
76 callchain_param.record_mode = CALLCHAIN_FP; 76 param->record_mode = CALLCHAIN_FP;
77 ret = 0; 77 ret = 0;
78 } else 78 } else
79 pr_err("callchain: No more arguments " 79 pr_err("callchain: No more arguments "
@@ -86,20 +86,20 @@ int parse_callchain_record_opt(const char *arg)
86 const unsigned long default_stack_dump_size = 8192; 86 const unsigned long default_stack_dump_size = 8192;
87 87
88 ret = 0; 88 ret = 0;
89 callchain_param.record_mode = CALLCHAIN_DWARF; 89 param->record_mode = CALLCHAIN_DWARF;
90 callchain_param.dump_size = default_stack_dump_size; 90 param->dump_size = default_stack_dump_size;
91 91
92 tok = strtok_r(NULL, ",", &saveptr); 92 tok = strtok_r(NULL, ",", &saveptr);
93 if (tok) { 93 if (tok) {
94 unsigned long size = 0; 94 unsigned long size = 0;
95 95
96 ret = get_stack_size(tok, &size); 96 ret = get_stack_size(tok, &size);
97 callchain_param.dump_size = size; 97 param->dump_size = size;
98 } 98 }
99#endif /* HAVE_DWARF_UNWIND_SUPPORT */ 99#endif /* HAVE_DWARF_UNWIND_SUPPORT */
100 } else if (!strncmp(name, "lbr", sizeof("lbr"))) { 100 } else if (!strncmp(name, "lbr", sizeof("lbr"))) {
101 if (!strtok_r(NULL, ",", &saveptr)) { 101 if (!strtok_r(NULL, ",", &saveptr)) {
102 callchain_param.record_mode = CALLCHAIN_LBR; 102 param->record_mode = CALLCHAIN_LBR;
103 ret = 0; 103 ret = 0;
104 } else 104 } else
105 pr_err("callchain: No more arguments " 105 pr_err("callchain: No more arguments "
@@ -219,7 +219,7 @@ int perf_callchain_config(const char *var, const char *value)
219 var += sizeof("call-graph.") - 1; 219 var += sizeof("call-graph.") - 1;
220 220
221 if (!strcmp(var, "record-mode")) 221 if (!strcmp(var, "record-mode"))
222 return parse_callchain_record_opt(value); 222 return parse_callchain_record_opt(value, &callchain_param);
223#ifdef HAVE_DWARF_UNWIND_SUPPORT 223#ifdef HAVE_DWARF_UNWIND_SUPPORT
224 if (!strcmp(var, "dump-size")) { 224 if (!strcmp(var, "dump-size")) {
225 unsigned long size = 0; 225 unsigned long size = 0;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 679c2c6d8ade..68a32c2fe87a 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -177,7 +177,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
177 bool hide_unresolved); 177 bool hide_unresolved);
178 178
179extern const char record_callchain_help[]; 179extern const char record_callchain_help[];
180int parse_callchain_record_opt(const char *arg); 180int parse_callchain_record_opt(const char *arg, struct callchain_param *param);
181int parse_callchain_report_opt(const char *arg); 181int parse_callchain_report_opt(const char *arg);
182int perf_callchain_config(const char *var, const char *value); 182int perf_callchain_config(const char *var, const char *value);
183 183
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
index 68888c29b04a..3bee6773ddb0 100644
--- a/tools/perf/util/cloexec.h
+++ b/tools/perf/util/cloexec.h
@@ -4,7 +4,7 @@
4unsigned long perf_event_open_cloexec_flag(void); 4unsigned long perf_event_open_cloexec_flag(void);
5 5
6#ifdef __GLIBC_PREREQ 6#ifdef __GLIBC_PREREQ
7#if !__GLIBC_PREREQ(2, 6) 7#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
8extern int sched_getcpu(void) __THROW; 8extern int sched_getcpu(void) __THROW;
9#endif 9#endif
10#endif 10#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 55355b3d4f85..9b9565416f90 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -67,8 +67,9 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
67 return r; 67 return r;
68} 68}
69 69
70/* Colors are not included in return value */
70static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, 71static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
71 va_list args, const char *trail) 72 va_list args)
72{ 73{
73 int r = 0; 74 int r = 0;
74 75
@@ -83,12 +84,10 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
83 } 84 }
84 85
85 if (perf_use_color_default && *color) 86 if (perf_use_color_default && *color)
86 r += fprintf(fp, "%s", color); 87 fprintf(fp, "%s", color);
87 r += vfprintf(fp, fmt, args); 88 r += vfprintf(fp, fmt, args);
88 if (perf_use_color_default && *color) 89 if (perf_use_color_default && *color)
89 r += fprintf(fp, "%s", PERF_COLOR_RESET); 90 fprintf(fp, "%s", PERF_COLOR_RESET);
90 if (trail)
91 r += fprintf(fp, "%s", trail);
92 return r; 91 return r;
93} 92}
94 93
@@ -100,7 +99,7 @@ int color_vsnprintf(char *bf, size_t size, const char *color,
100 99
101int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) 100int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
102{ 101{
103 return __color_vfprintf(fp, color, fmt, args, NULL); 102 return __color_vfprintf(fp, color, fmt, args);
104} 103}
105 104
106int color_snprintf(char *bf, size_t size, const char *color, 105int 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, ...)
126 return r; 125 return r;
127} 126}
128 127
129int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
130{
131 va_list args;
132 int r;
133 va_start(args, fmt);
134 r = __color_vfprintf(fp, color, fmt, args, "\n");
135 va_end(args);
136 return r;
137}
138
139/* 128/*
140 * This function splits the buffer by newlines and colors the lines individually. 129 * This function splits the buffer by newlines and colors the lines individually.
141 * 130 *
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 38146f922c54..a93997f16dec 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -35,7 +35,6 @@ int color_vsnprintf(char *bf, size_t size, const char *color,
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); 35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
37int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); 37int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
38int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
39int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
40int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); 39int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
41int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); 40int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7d3acba5a512..f572f469a30d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -545,14 +545,15 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
545 545
546static void 546static void
547perf_evsel__config_callgraph(struct perf_evsel *evsel, 547perf_evsel__config_callgraph(struct perf_evsel *evsel,
548 struct record_opts *opts) 548 struct record_opts *opts,
549 struct callchain_param *param)
549{ 550{
550 bool function = perf_evsel__is_function_event(evsel); 551 bool function = perf_evsel__is_function_event(evsel);
551 struct perf_event_attr *attr = &evsel->attr; 552 struct perf_event_attr *attr = &evsel->attr;
552 553
553 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 554 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
554 555
555 if (callchain_param.record_mode == CALLCHAIN_LBR) { 556 if (param->record_mode == CALLCHAIN_LBR) {
556 if (!opts->branch_stack) { 557 if (!opts->branch_stack) {
557 if (attr->exclude_user) { 558 if (attr->exclude_user) {
558 pr_warning("LBR callstack option is only available " 559 pr_warning("LBR callstack option is only available "
@@ -568,12 +569,12 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
568 "Falling back to framepointers.\n"); 569 "Falling back to framepointers.\n");
569 } 570 }
570 571
571 if (callchain_param.record_mode == CALLCHAIN_DWARF) { 572 if (param->record_mode == CALLCHAIN_DWARF) {
572 if (!function) { 573 if (!function) {
573 perf_evsel__set_sample_bit(evsel, REGS_USER); 574 perf_evsel__set_sample_bit(evsel, REGS_USER);
574 perf_evsel__set_sample_bit(evsel, STACK_USER); 575 perf_evsel__set_sample_bit(evsel, STACK_USER);
575 attr->sample_regs_user = PERF_REGS_MASK; 576 attr->sample_regs_user = PERF_REGS_MASK;
576 attr->sample_stack_user = callchain_param.dump_size; 577 attr->sample_stack_user = param->dump_size;
577 attr->exclude_callchain_user = 1; 578 attr->exclude_callchain_user = 1;
578 } else { 579 } else {
579 pr_info("Cannot use DWARF unwind for function trace event," 580 pr_info("Cannot use DWARF unwind for function trace event,"
@@ -587,15 +588,23 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
587 } 588 }
588} 589}
589 590
590static void apply_config_terms(struct perf_event_attr *attr __maybe_unused, 591static void apply_config_terms(struct perf_evsel *evsel)
591 struct list_head *config_terms)
592{ 592{
593 struct perf_evsel_config_term *term; 593 struct perf_evsel_config_term *term;
594 struct list_head *config_terms = &evsel->config_terms;
595 struct perf_event_attr *attr = &evsel->attr;
594 596
595 list_for_each_entry(term, config_terms, list) { 597 list_for_each_entry(term, config_terms, list) {
596 switch (term->type) { 598 switch (term->type) {
597 case PERF_EVSEL__CONFIG_TERM_PERIOD: 599 case PERF_EVSEL__CONFIG_TERM_PERIOD:
598 attr->sample_period = term->val.period; 600 attr->sample_period = term->val.period;
601 break;
602 case PERF_EVSEL__CONFIG_TERM_TIME:
603 if (term->val.time)
604 perf_evsel__set_sample_bit(evsel, TIME);
605 else
606 perf_evsel__reset_sample_bit(evsel, TIME);
607 break;
599 default: 608 default:
600 break; 609 break;
601 } 610 }
@@ -706,7 +715,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
706 evsel->attr.exclude_callchain_user = 1; 715 evsel->attr.exclude_callchain_user = 1;
707 716
708 if (callchain_param.enabled && !evsel->no_aux_samples) 717 if (callchain_param.enabled && !evsel->no_aux_samples)
709 perf_evsel__config_callgraph(evsel, opts); 718 perf_evsel__config_callgraph(evsel, opts, &callchain_param);
710 719
711 if (opts->sample_intr_regs) { 720 if (opts->sample_intr_regs) {
712 attr->sample_regs_intr = PERF_REGS_MASK; 721 attr->sample_regs_intr = PERF_REGS_MASK;
@@ -798,7 +807,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
798 * Apply event specific term settings, 807 * Apply event specific term settings,
799 * it overloads any global configuration. 808 * it overloads any global configuration.
800 */ 809 */
801 apply_config_terms(attr, &evsel->config_terms); 810 apply_config_terms(evsel);
802} 811}
803 812
804static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 813static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a7d2175358b8..6a129081f3ad 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -39,6 +39,7 @@ struct cgroup_sel;
39*/ 39*/
40enum { 40enum {
41 PERF_EVSEL__CONFIG_TERM_PERIOD, 41 PERF_EVSEL__CONFIG_TERM_PERIOD,
42 PERF_EVSEL__CONFIG_TERM_TIME,
42 PERF_EVSEL__CONFIG_TERM_MAX, 43 PERF_EVSEL__CONFIG_TERM_MAX,
43}; 44};
44 45
@@ -47,6 +48,7 @@ struct perf_evsel_config_term {
47 int type; 48 int type;
48 union { 49 union {
49 u64 period; 50 u64 period;
51 bool time;
50 } val; 52 } val;
51}; 53};
52 54
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 09bee93fd0ec..a6cb9afc20e2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -603,6 +603,14 @@ do { \
603 * attr->branch_sample_type = term->val.num; 603 * attr->branch_sample_type = term->val.num;
604 */ 604 */
605 break; 605 break;
606 case PARSE_EVENTS__TERM_TYPE_TIME:
607 CHECK_TYPE_VAL(NUM);
608 if (term->val.num > 1) {
609 err->str = strdup("expected 0 or 1");
610 err->idx = term->err_val;
611 return -EINVAL;
612 }
613 break;
606 case PARSE_EVENTS__TERM_TYPE_NAME: 614 case PARSE_EVENTS__TERM_TYPE_NAME:
607 CHECK_TYPE_VAL(STR); 615 CHECK_TYPE_VAL(STR);
608 break; 616 break;
@@ -650,6 +658,10 @@ do { \
650 switch (term->type_term) { 658 switch (term->type_term) {
651 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 659 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
652 ADD_CONFIG_TERM(PERIOD, period, term->val.num); 660 ADD_CONFIG_TERM(PERIOD, period, term->val.num);
661 break;
662 case PARSE_EVENTS__TERM_TYPE_TIME:
663 ADD_CONFIG_TERM(TIME, time, term->val.num);
664 break;
653 default: 665 default:
654 break; 666 break;
655 } 667 }
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2063048a4354..e6f9aacc1cce 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -63,6 +63,7 @@ enum {
63 PARSE_EVENTS__TERM_TYPE_NAME, 63 PARSE_EVENTS__TERM_TYPE_NAME,
64 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, 64 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
65 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 65 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
66 PARSE_EVENTS__TERM_TYPE_TIME,
66}; 67};
67 68
68struct parse_events_term { 69struct parse_events_term {
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 13cef3c65565..f5427505ae77 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -183,6 +183,7 @@ config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
183name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } 183name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
184period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } 184period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
185branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 185branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
186time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
186, { return ','; } 187, { return ','; }
187"/" { BEGIN(INITIAL); return '/'; } 188"/" { BEGIN(INITIAL); return '/'; }
188{name_minus} { return str(yyscanner, PE_NAME); } 189{name_minus} { return str(yyscanner, PE_NAME); }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7bcb8c315615..b615cdf211d6 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -607,7 +607,7 @@ static char *formats_error_string(struct list_head *formats)
607{ 607{
608 struct perf_pmu_format *format; 608 struct perf_pmu_format *format;
609 char *err, *str; 609 char *err, *str;
610 static const char *static_terms = "config,config1,config2,name,period,branch_type\n"; 610 static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n";
611 unsigned i = 0; 611 unsigned i = 0;
612 612
613 if (!asprintf(&str, "valid terms:")) 613 if (!asprintf(&str, "valid terms:"))