Browse Source

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>
Ingo Molnar 10 years ago
parent
commit
b6b6c18fcd

+ 11 - 0
tools/build/feature/test-glibc.c

@@ -1,8 +1,19 @@
+#include <stdlib.h>
+
+#if !defined(__UCLIBC__)
 #include <gnu/libc-version.h>
 #include <gnu/libc-version.h>
+#else
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#endif
 
 
 int main(void)
 int main(void)
 {
 {
+#if !defined(__UCLIBC__)
 	const char *version = gnu_get_libc_version();
 	const char *version = gnu_get_libc_version();
+#else
+	const char *version = XSTR(__GLIBC__) "." XSTR(__GLIBC_MINOR__);
+#endif
 
 
 	return (long)version;
 	return (long)version;
 }
 }

+ 3 - 1
tools/perf/Documentation/perf-record.txt

@@ -49,7 +49,9 @@ OPTIONS
 	  These params can be used to overload default config values per event.
 	  These params can be used to overload default config values per event.
 	  Here is a list of the params.
 	  Here is a list of the params.
 	  - 'period': Set event sampling period
 	  - '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,
 	  Note: If user explicitly sets options which conflict with the params,
 	  the value set by the params will be overridden.
 	  the value set by the params will be overridden.
 
 

+ 1 - 1
tools/perf/builtin-record.c

@@ -779,7 +779,7 @@ int record_parse_callchain_opt(const struct option *opt,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	ret = parse_callchain_record_opt(arg);
+	ret = parse_callchain_record_opt(arg, &callchain_param);
 	if (!ret)
 	if (!ret)
 		callchain_debug();
 		callchain_debug();
 
 

+ 2 - 1
tools/perf/builtin-script.c

@@ -1861,7 +1861,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 	else
 	else
 		symbol_conf.use_callchain = false;
 		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,
 					 machine__resolve_kernel_addr,
 					 &session->machines.host) < 0) {
 					 &session->machines.host) < 0) {
 		pr_err("%s: failed to set libtraceevent function resolver\n", __func__);
 		pr_err("%s: failed to set libtraceevent function resolver\n", __func__);

+ 155 - 20
tools/perf/builtin-trace.c

@@ -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
 #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,
 static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
 					       struct syscall_arg *arg)
 					       struct syscall_arg *arg)
 {
 {
@@ -971,14 +976,23 @@ static struct syscall_fmt {
 	bool	   hexret;
 	bool	   hexret;
 } syscall_fmts[] = {
 } syscall_fmts[] = {
 	{ .name	    = "access",	    .errmsg = true,
 	{ .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	    = "arch_prctl", .errmsg = true, .alias = "prctl", },
 	{ .name	    = "brk",	    .hexret = true,
 	{ .name	    = "brk",	    .hexret = true,
 	  .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
 	  .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     = "clock_gettime",  .errmsg = true, STRARRAY(0, clk_id, clockid), },
 	{ .name	    = "close",	    .errmsg = true,
 	{ .name	    = "close",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
 	{ .name	    = "connect",    .errmsg = true, },
 	{ .name	    = "connect",    .errmsg = true, },
+	{ .name	    = "creat",	    .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "dup",	    .errmsg = true,
 	{ .name	    = "dup",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "dup2",	    .errmsg = true,
 	{ .name	    = "dup2",	    .errmsg = true,
@@ -989,7 +1003,8 @@ static struct syscall_fmt {
 	{ .name	    = "eventfd2",   .errmsg = true,
 	{ .name	    = "eventfd2",   .errmsg = true,
 	  .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
 	  .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
 	{ .name	    = "faccessat",  .errmsg = true,
 	{ .name	    = "faccessat",  .errmsg = true,
-	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
+	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
+			     [1] = SCA_FILENAME, /* filename */ }, },
 	{ .name	    = "fadvise64",  .errmsg = true,
 	{ .name	    = "fadvise64",  .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "fallocate",  .errmsg = true,
 	{ .name	    = "fallocate",  .errmsg = true,
@@ -1003,7 +1018,8 @@ static struct syscall_fmt {
 	{ .name	    = "fchown",	    .errmsg = true,
 	{ .name	    = "fchown",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "fchownat",   .errmsg = true,
 	{ .name	    = "fchownat",   .errmsg = true,
-	  .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
+	  .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
+			     [1] = SCA_FILENAME, /* filename */ }, },
 	{ .name	    = "fcntl",	    .errmsg = true,
 	{ .name	    = "fcntl",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */
 			     [1] = SCA_STRARRAY, /* cmd */ },
 			     [1] = SCA_STRARRAY, /* cmd */ },
@@ -1018,7 +1034,8 @@ static struct syscall_fmt {
 	{ .name	    = "fstat",	    .errmsg = true, .alias = "newfstat",
 	{ .name	    = "fstat",	    .errmsg = true, .alias = "newfstat",
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "fstatat",    .errmsg = true, .alias = "newfstatat",
 	{ .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,
 	{ .name	    = "fstatfs",    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "fsync",    .errmsg = true,
 	{ .name	    = "fsync",    .errmsg = true,
@@ -1035,6 +1052,10 @@ static struct syscall_fmt {
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "getitimer",  .errmsg = true, STRARRAY(0, which, itimers), },
 	{ .name	    = "getitimer",  .errmsg = true, STRARRAY(0, which, itimers), },
 	{ .name	    = "getrlimit",  .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
 	{ .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,
 	{ .name	    = "ioctl",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */
 #if defined(__i386__) || defined(__x86_64__)
 #if defined(__i386__) || defined(__x86_64__)
@@ -1049,18 +1070,33 @@ static struct syscall_fmt {
 #endif
 #endif
 	{ .name	    = "kill",	    .errmsg = true,
 	{ .name	    = "kill",	    .errmsg = true,
 	  .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
 	  .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,
 	{ .name	    = "linkat",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
+	{ .name	    = "listxattr",  .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "lseek",	    .errmsg = true,
 	{ .name	    = "lseek",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */
 			     [2] = SCA_STRARRAY, /* whence */ },
 			     [2] = SCA_STRARRAY, /* whence */ },
 	  .arg_parm	 = { [2] = &strarray__whences, /* whence */ }, },
 	  .arg_parm	 = { [2] = &strarray__whences, /* whence */ }, },
+	{ .name	    = "lsetxattr",  .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "lstat",	    .errmsg = true, .alias = "newlstat", },
 	{ .name	    = "lstat",	    .errmsg = true, .alias = "newlstat", },
+	{ .name	    = "lsxattr",    .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name     = "madvise",    .errmsg = true,
 	{ .name     = "madvise",    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_HEX,	 /* start */
 	  .arg_scnprintf = { [0] = SCA_HEX,	 /* start */
 			     [2] = SCA_MADV_BHV, /* behavior */ }, },
 			     [2] = SCA_MADV_BHV, /* behavior */ }, },
+	{ .name	    = "mkdir",    .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "mkdirat",    .errmsg = true,
 	{ .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,
 	{ .name	    = "mknodat",    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
 	{ .name	    = "mlock",	    .errmsg = true,
 	{ .name	    = "mlock",	    .errmsg = true,
@@ -1086,14 +1122,17 @@ static struct syscall_fmt {
 	{ .name	    = "name_to_handle_at", .errmsg = true,
 	{ .name	    = "name_to_handle_at", .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
 	{ .name	    = "newfstatat", .errmsg = true,
 	{ .name	    = "newfstatat", .errmsg = true,
-	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
+	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
+			     [1] = SCA_FILENAME, /* filename */ }, },
 	{ .name	    = "open",	    .errmsg = true,
 	{ .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,
 	{ .name	    = "open_by_handle_at", .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
 			     [2] = SCA_OPEN_FLAGS, /* flags */ }, },
 			     [2] = SCA_OPEN_FLAGS, /* flags */ }, },
 	{ .name	    = "openat",	    .errmsg = true,
 	{ .name	    = "openat",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
+			     [1] = SCA_FILENAME, /* filename */
 			     [2] = SCA_OPEN_FLAGS, /* flags */ }, },
 			     [2] = SCA_OPEN_FLAGS, /* flags */ }, },
 	{ .name	    = "perf_event_open", .errmsg = true,
 	{ .name	    = "perf_event_open", .errmsg = true,
 	  .arg_scnprintf = { [1] = SCA_INT, /* pid */
 	  .arg_scnprintf = { [1] = SCA_INT, /* pid */
@@ -1115,8 +1154,11 @@ static struct syscall_fmt {
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "read",	    .errmsg = true,
 	{ .name	    = "read",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
+	{ .name	    = "readlink",   .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
 	{ .name	    = "readlinkat", .errmsg = true,
 	{ .name	    = "readlinkat", .errmsg = true,
-	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
+	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
+			     [1] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "readv",	    .errmsg = true,
 	{ .name	    = "readv",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "recvfrom",   .errmsg = true,
 	{ .name	    = "recvfrom",   .errmsg = true,
@@ -1125,8 +1167,12 @@ static struct syscall_fmt {
 	  .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
 	  .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
 	{ .name	    = "recvmsg",    .errmsg = true,
 	{ .name	    = "recvmsg",    .errmsg = true,
 	  .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
 	  .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
+	{ .name	    = "removexattr", .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "renameat",   .errmsg = true,
 	{ .name	    = "renameat",   .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
+	{ .name	    = "rmdir",    .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "rt_sigaction", .errmsg = true,
 	{ .name	    = "rt_sigaction", .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
 	  .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
 	{ .name	    = "rt_sigprocmask",  .errmsg = true, STRARRAY(0, how, sighow), },
 	{ .name	    = "rt_sigprocmask",  .errmsg = true, STRARRAY(0, how, sighow), },
@@ -1143,6 +1189,8 @@ static struct syscall_fmt {
 	  .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
 	  .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
 	{ .name	    = "setitimer",  .errmsg = true, STRARRAY(0, which, itimers), },
 	{ .name	    = "setitimer",  .errmsg = true, STRARRAY(0, which, itimers), },
 	{ .name	    = "setrlimit",  .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
 	{ .name	    = "setrlimit",  .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
+	{ .name	    = "setxattr",   .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
 	{ .name	    = "shutdown",   .errmsg = true,
 	{ .name	    = "shutdown",   .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "socket",	    .errmsg = true,
 	{ .name	    = "socket",	    .errmsg = true,
@@ -1154,17 +1202,31 @@ static struct syscall_fmt {
 			     [1] = SCA_SK_TYPE, /* type */ },
 			     [1] = SCA_SK_TYPE, /* type */ },
 	  .arg_parm	 = { [0] = &strarray__socket_families, /* family */ }, },
 	  .arg_parm	 = { [0] = &strarray__socket_families, /* family */ }, },
 	{ .name	    = "stat",	    .errmsg = true, .alias = "newstat", },
 	{ .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,
 	{ .name	    = "symlinkat",  .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
 	{ .name	    = "tgkill",	    .errmsg = true,
 	{ .name	    = "tgkill",	    .errmsg = true,
 	  .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
 	  .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
 	{ .name	    = "tkill",	    .errmsg = true,
 	{ .name	    = "tkill",	    .errmsg = true,
 	  .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
 	  .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
+	{ .name	    = "truncate",   .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
 	{ .name	    = "uname",	    .errmsg = true, .alias = "newuname", },
 	{ .name	    = "uname",	    .errmsg = true, .alias = "newuname", },
 	{ .name	    = "unlinkat",   .errmsg = true,
 	{ .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,
 	{ .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,
 	{ .name	    = "write",	    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	  .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
 	{ .name	    = "writev",	    .errmsg = true,
 	{ .name	    = "writev",	    .errmsg = true,
@@ -1208,6 +1270,11 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
 	return printed + fprintf(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 {
 struct thread_trace {
 	u64		  entry_time;
 	u64		  entry_time;
 	u64		  exit_time;
 	u64		  exit_time;
@@ -1216,6 +1283,10 @@ struct thread_trace {
 	unsigned long	  pfmaj, pfmin;
 	unsigned long	  pfmaj, pfmin;
 	char		  *entry_str;
 	char		  *entry_str;
 	double		  runtime_ms;
 	double		  runtime_ms;
+        struct {
+		unsigned long ptr;
+		int           entry_str_pos;
+	} filename;
 	struct {
 	struct {
 		int	  max;
 		int	  max;
 		char	  **table;
 		char	  **table;
@@ -1262,6 +1333,8 @@ fail:
 #define TRACE_PFMAJ		(1 << 0)
 #define TRACE_PFMAJ		(1 << 0)
 #define TRACE_PFMIN		(1 << 1)
 #define TRACE_PFMIN		(1 << 1)
 
 
+static const size_t trace__entry_str_size = 2048;
+
 struct trace {
 struct trace {
 	struct perf_tool	tool;
 	struct perf_tool	tool;
 	struct {
 	struct {
@@ -1312,6 +1385,7 @@ struct trace {
 	bool			show_tool_stats;
 	bool			show_tool_stats;
 	bool			trace_syscalls;
 	bool			trace_syscalls;
 	bool			force;
 	bool			force;
+	bool			vfs_getname;
 	int			trace_pgfaults;
 	int			trace_pgfaults;
 };
 };
 
 
@@ -1415,6 +1489,27 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
 	return printed;
 	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)
 static bool trace__filter_duration(struct trace *trace, double t)
 {
 {
 	return t < (trace->duration_filter * NSEC_PER_MSEC);
 	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);
 	args = perf_evsel__sc_tp_ptr(evsel, args, sample);
 
 
 	if (ttrace->entry_str == NULL) {
 	if (ttrace->entry_str == NULL) {
-		ttrace->entry_str = malloc(1024);
+		ttrace->entry_str = malloc(trace__entry_str_size);
 		if (!ttrace->entry_str)
 		if (!ttrace->entry_str)
 			goto out_put;
 			goto out_put;
 	}
 	}
@@ -1831,9 +1926,9 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 
 
 	ttrace->entry_time = sample->time;
 	ttrace->entry_time = sample->time;
 	msg = ttrace->entry_str;
 	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);
 					   args, trace, thread);
 
 
 	if (sc->is_exit) {
 	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,
 			      union perf_event *event __maybe_unused,
 			      struct perf_sample *sample)
 			      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");
 	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;
 	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 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");
 	struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
 	if (evsel == NULL)
 	if (evsel == NULL)
-		return;
+		return false;
 
 
 	if (perf_evsel__field(evsel, "pathname") == NULL) {
 	if (perf_evsel__field(evsel, "pathname") == NULL) {
 		perf_evsel__delete(evsel);
 		perf_evsel__delete(evsel);
-		return;
+		return false;
 	}
 	}
 
 
 	evsel->handler = trace__vfs_getname;
 	evsel->handler = trace__vfs_getname;
 	perf_evlist__add(evlist, evsel);
 	perf_evlist__add(evlist, evsel);
+	return true;
 }
 }
 
 
 static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
 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;
 		goto out_error_raw_syscalls;
 
 
 	if (trace->trace_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) &&
 	if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
 	    perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
 	    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);
 		err = trace__set_ev_qualifier_filter(trace);
 		if (err < 0)
 		if (err < 0)
 			goto out_errno;
 			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);
 	err = perf_evlist__apply_filters(evlist, &evsel);
 	if (err < 0)
 	if (err < 0)
@@ -2830,7 +2965,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 			.mmap_pages    = UINT_MAX,
 			.mmap_pages    = UINT_MAX,
 			.proc_map_timeout  = 500,
 			.proc_map_timeout  = 500,
 		},
 		},
-		.output = stdout,
+		.output = stderr,
 		.show_comm = true,
 		.show_comm = true,
 		.trace_syscalls = true,
 		.trace_syscalls = true,
 	};
 	};

+ 7 - 7
tools/perf/util/callchain.c

@@ -53,7 +53,7 @@ static int get_stack_size(const char *str, unsigned long *_size)
 }
 }
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #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 *tok, *name, *saveptr = NULL;
 	char *buf;
 	char *buf;
@@ -73,7 +73,7 @@ int parse_callchain_record_opt(const char *arg)
 		/* Framepointer style */
 		/* Framepointer style */
 		if (!strncmp(name, "fp", sizeof("fp"))) {
 		if (!strncmp(name, "fp", sizeof("fp"))) {
 			if (!strtok_r(NULL, ",", &saveptr)) {
 			if (!strtok_r(NULL, ",", &saveptr)) {
-				callchain_param.record_mode = CALLCHAIN_FP;
+				param->record_mode = CALLCHAIN_FP;
 				ret = 0;
 				ret = 0;
 			} else
 			} else
 				pr_err("callchain: No more arguments "
 				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;
 			const unsigned long default_stack_dump_size = 8192;
 
 
 			ret = 0;
 			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);
 			tok = strtok_r(NULL, ",", &saveptr);
 			if (tok) {
 			if (tok) {
 				unsigned long size = 0;
 				unsigned long size = 0;
 
 
 				ret = get_stack_size(tok, &size);
 				ret = get_stack_size(tok, &size);
-				callchain_param.dump_size = size;
+				param->dump_size = size;
 			}
 			}
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 		} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
 		} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
 			if (!strtok_r(NULL, ",", &saveptr)) {
 			if (!strtok_r(NULL, ",", &saveptr)) {
-				callchain_param.record_mode = CALLCHAIN_LBR;
+				param->record_mode = CALLCHAIN_LBR;
 				ret = 0;
 				ret = 0;
 			} else
 			} else
 				pr_err("callchain: No more arguments "
 				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;
 	var += sizeof("call-graph.") - 1;
 
 
 	if (!strcmp(var, "record-mode"))
 	if (!strcmp(var, "record-mode"))
-		return parse_callchain_record_opt(value);
+		return parse_callchain_record_opt(value, &callchain_param);
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 	if (!strcmp(var, "dump-size")) {
 	if (!strcmp(var, "dump-size")) {
 		unsigned long size = 0;
 		unsigned long size = 0;

+ 1 - 1
tools/perf/util/callchain.h

@@ -177,7 +177,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
 			bool hide_unresolved);
 			bool hide_unresolved);
 
 
 extern const char record_callchain_help[];
 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 parse_callchain_report_opt(const char *arg);
 int perf_callchain_config(const char *var, const char *value);
 int perf_callchain_config(const char *var, const char *value);
 
 

+ 1 - 1
tools/perf/util/cloexec.h

@@ -4,7 +4,7 @@
 unsigned long perf_event_open_cloexec_flag(void);
 unsigned long perf_event_open_cloexec_flag(void);
 
 
 #ifdef __GLIBC_PREREQ
 #ifdef __GLIBC_PREREQ
-#if !__GLIBC_PREREQ(2, 6)
+#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
 extern int sched_getcpu(void) __THROW;
 extern int sched_getcpu(void) __THROW;
 #endif
 #endif
 #endif
 #endif

+ 5 - 16
tools/perf/util/color.c

@@ -67,8 +67,9 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
 	return r;
 	return r;
 }
 }
 
 
+/* Colors are not included in return value */
 static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
 static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
-		va_list args, const char *trail)
+		va_list args)
 {
 {
 	int r = 0;
 	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)
 	if (perf_use_color_default && *color)
-		r += fprintf(fp, "%s", color);
+		fprintf(fp, "%s", color);
 	r += vfprintf(fp, fmt, args);
 	r += vfprintf(fp, fmt, args);
 	if (perf_use_color_default && *color)
 	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;
 	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)
 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,
 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;
 	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.
  * This function splits the buffer by newlines and colors the lines individually.
  *
  *

+ 0 - 1
tools/perf/util/color.h

@@ -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_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_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_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 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 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, ...);
 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);

+ 17 - 8
tools/perf/util/evsel.c

@@ -545,14 +545,15 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
 
 
 static void
 static void
 perf_evsel__config_callgraph(struct perf_evsel *evsel,
 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);
 	bool function = perf_evsel__is_function_event(evsel);
 	struct perf_event_attr *attr = &evsel->attr;
 	struct perf_event_attr *attr = &evsel->attr;
 
 
 	perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 	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 (!opts->branch_stack) {
 			if (attr->exclude_user) {
 			if (attr->exclude_user) {
 				pr_warning("LBR callstack option is only available "
 				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");
 				    "Falling back to framepointers.\n");
 	}
 	}
 
 
-	if (callchain_param.record_mode == CALLCHAIN_DWARF) {
+	if (param->record_mode == CALLCHAIN_DWARF) {
 		if (!function) {
 		if (!function) {
 			perf_evsel__set_sample_bit(evsel, REGS_USER);
 			perf_evsel__set_sample_bit(evsel, REGS_USER);
 			perf_evsel__set_sample_bit(evsel, STACK_USER);
 			perf_evsel__set_sample_bit(evsel, STACK_USER);
 			attr->sample_regs_user = PERF_REGS_MASK;
 			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;
 			attr->exclude_callchain_user = 1;
 		} else {
 		} else {
 			pr_info("Cannot use DWARF unwind for function trace event,"
 			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 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) {
 	list_for_each_entry(term, config_terms, list) {
 		switch (term->type) {
 		switch (term->type) {
 		case PERF_EVSEL__CONFIG_TERM_PERIOD:
 		case PERF_EVSEL__CONFIG_TERM_PERIOD:
 			attr->sample_period = term->val.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:
 		default:
 			break;
 			break;
 		}
 		}
@@ -706,7 +715,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 		evsel->attr.exclude_callchain_user = 1;
 		evsel->attr.exclude_callchain_user = 1;
 
 
 	if (callchain_param.enabled && !evsel->no_aux_samples)
 	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) {
 	if (opts->sample_intr_regs) {
 		attr->sample_regs_intr = PERF_REGS_MASK;
 		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,
 	 * Apply event specific term settings,
 	 * it overloads any global configuration.
 	 * 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)
 static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)

+ 2 - 0
tools/perf/util/evsel.h

@@ -39,6 +39,7 @@ struct cgroup_sel;
 */
 */
 enum {
 enum {
 	PERF_EVSEL__CONFIG_TERM_PERIOD,
 	PERF_EVSEL__CONFIG_TERM_PERIOD,
+	PERF_EVSEL__CONFIG_TERM_TIME,
 	PERF_EVSEL__CONFIG_TERM_MAX,
 	PERF_EVSEL__CONFIG_TERM_MAX,
 };
 };
 
 
@@ -47,6 +48,7 @@ struct perf_evsel_config_term {
 	int	type;
 	int	type;
 	union {
 	union {
 		u64	period;
 		u64	period;
+		bool	time;
 	} val;
 	} val;
 };
 };
 
 

+ 12 - 0
tools/perf/util/parse-events.c

@@ -603,6 +603,14 @@ do {									   \
 		 * attr->branch_sample_type = term->val.num;
 		 * attr->branch_sample_type = term->val.num;
 		 */
 		 */
 		break;
 		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:
 	case PARSE_EVENTS__TERM_TYPE_NAME:
 		CHECK_TYPE_VAL(STR);
 		CHECK_TYPE_VAL(STR);
 		break;
 		break;
@@ -650,6 +658,10 @@ do {								\
 		switch (term->type_term) {
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
 			ADD_CONFIG_TERM(PERIOD, period, term->val.num);
 			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:
 		default:
 			break;
 			break;
 		}
 		}

+ 1 - 0
tools/perf/util/parse-events.h

@@ -63,6 +63,7 @@ enum {
 	PARSE_EVENTS__TERM_TYPE_NAME,
 	PARSE_EVENTS__TERM_TYPE_NAME,
 	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
 	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
+	PARSE_EVENTS__TERM_TYPE_TIME,
 };
 };
 
 
 struct parse_events_term {
 struct parse_events_term {

+ 1 - 0
tools/perf/util/parse-events.l

@@ -183,6 +183,7 @@ config2			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
 name			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
 name			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
 period			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 period			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 branch_type		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
 branch_type		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+time			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
 ,			{ return ','; }
 ,			{ return ','; }
 "/"			{ BEGIN(INITIAL); return '/'; }
 "/"			{ BEGIN(INITIAL); return '/'; }
 {name_minus}		{ return str(yyscanner, PE_NAME); }
 {name_minus}		{ return str(yyscanner, PE_NAME); }

+ 1 - 1
tools/perf/util/pmu.c

@@ -607,7 +607,7 @@ static char *formats_error_string(struct list_head *formats)
 {
 {
 	struct perf_pmu_format *format;
 	struct perf_pmu_format *format;
 	char *err, *str;
 	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;
 	unsigned i = 0;
 
 
 	if (!asprintf(&str, "valid terms:"))
 	if (!asprintf(&str, "valid terms:"))