diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 280533ebf9df43b933e517750c29c141dd3feddc..6fdf78625c51cdcd08048dec45adad287a3e452e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -152,12 +152,16 @@ OPTIONS -d:: --data:: - Sample addresses. + Record the sample addresses. -T:: --timestamp:: - Sample timestamps. Use it with 'perf report -D' to see the timestamps, - for instance. + Record the sample timestamps. Use it with 'perf report -D' to see the + timestamps, for instance. + +-P:: +--period:: + Record the sample period. -n:: --no-samples:: diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index a0bdd6124583d0c8d02bcb29d852124a8d7bea69..fe50a1b34aa0035dec38a07a752ae33df9ad0e5d 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -50,24 +50,20 @@ include/asm-generic/bitops/const_hweight.h include/asm-generic/bitops/fls64.h include/asm-generic/bitops/__fls.h include/asm-generic/bitops/fls.h -include/linux/const.h include/linux/perf_event.h include/linux/rbtree.h include/linux/list.h include/linux/hash.h include/linux/stringify.h -lib/find_next_bit.c lib/hweight.c lib/rbtree.c include/linux/swab.h arch/*/include/asm/unistd*.h -arch/*/include/asm/perf_regs.h arch/*/include/uapi/asm/unistd*.h arch/*/include/uapi/asm/perf_regs.h arch/*/lib/memcpy*.S arch/*/lib/memset*.S include/linux/poison.h -include/linux/magic.h include/linux/hw_breakpoint.h include/linux/rbtree_augmented.h include/uapi/linux/perf_event.h diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d3731cce7c1cc5d498977f31427895487ed723b9..4d6cdeb94fe1e34876391098fb5302a1ae76bf33 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1027,10 +1027,9 @@ struct option __record_options[] = { OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, "per thread counts"), - OPT_BOOLEAN('d', "data", &record.opts.sample_address, - "Sample addresses"), - OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), - OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), + OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"), + OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Record the sample timestamps"), + OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, "don't sample"), OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 628090b478ab38e48fee8c6c3fddca4f60bace35..32626ea3e2276b11279db88207e42c29eeed391a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, { struct perf_evsel *pos; - fprintf(stdout, "#\n# Total Lost Samples: %lu\n#\n", evlist->stats.total_lost_samples); + fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", evlist->stats.total_lost_samples); evlist__for_each(evlist, pos) { struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ff3d25803400af60a00714b0e37d171cb15dca8d..b24ecee95fec1683d9d812e51e9392c260196c67 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -549,7 +549,10 @@ static int __run_perf_stat(int argc, const char **argv) ui__warning("%s event is not supported by the kernel.\n", perf_evsel__name(counter)); counter->supported = false; - continue; + + if ((counter->leader != counter) || + !(counter->leader->nr_members > 1)) + continue; } perf_evsel__open_strerror(counter, &target, diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index a05490d06374d30a6488781adf0e2f812b48fcb7..4bf805b2fbf66fe77725cd4fa722a8dcb6e0699d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -68,6 +68,23 @@ # define MSG_CMSG_CLOEXEC 0x40000000 #endif +#ifndef PERF_FLAG_FD_NO_GROUP +# define PERF_FLAG_FD_NO_GROUP (1UL << 0) +#endif + +#ifndef PERF_FLAG_FD_OUTPUT +# define PERF_FLAG_FD_OUTPUT (1UL << 1) +#endif + +#ifndef PERF_FLAG_PID_CGROUP +# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ +#endif + +#ifndef PERF_FLAG_FD_CLOEXEC +# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ +#endif + + struct tp_field { int offset; union { @@ -358,6 +375,14 @@ static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, #define SCA_HEX syscall_arg__scnprintf_hex +static size_t syscall_arg__scnprintf_int(char *bf, size_t size, + struct syscall_arg *arg) +{ + return scnprintf(bf, size, "%d", arg->val); +} + +#define SCA_INT syscall_arg__scnprintf_int + static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, struct syscall_arg *arg) { @@ -810,6 +835,34 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags +static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, + struct syscall_arg *arg) +{ + int printed = 0, flags = arg->val; + + if (flags == 0) + return 0; + +#define P_FLAG(n) \ + if (flags & PERF_FLAG_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ + flags &= ~PERF_FLAG_##n; \ + } + + P_FLAG(FD_NO_GROUP); + P_FLAG(FD_OUTPUT); + P_FLAG(PID_CGROUP); + P_FLAG(FD_CLOEXEC); +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags + static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, struct syscall_arg *arg) { @@ -1077,6 +1130,11 @@ static struct syscall_fmt { { .name = "openat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ [2] = SCA_OPEN_FLAGS, /* flags */ }, }, + { .name = "perf_event_open", .errmsg = true, + .arg_scnprintf = { [1] = SCA_INT, /* pid */ + [2] = SCA_INT, /* cpu */ + [3] = SCA_FD, /* group_fd */ + [4] = SCA_PERF_FLAGS, /* flags */ }, }, { .name = "pipe2", .errmsg = true, .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, }, { .name = "poll", .errmsg = true, .timeout = true, }, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a3e36fc634dc40005e77f7b228ec8ffb5ad001af..d4f9994ae47fc6f594980ea828c31fb2e9ad4f11 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1058,7 +1058,7 @@ static void __p_read_format(char *buf, size_t size, u64 value) #define BUF_SIZE 1024 -#define p_hex(val) snprintf(buf, BUF_SIZE, "%"PRIx64, (uint64_t)(val)) +#define p_hex(val) snprintf(buf, BUF_SIZE, "%#"PRIx64, (uint64_t)(val)) #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 88d87bf3049f6b43e235fb7a9075f62a6be4e47f..f31e024ddf7dd683b7073fc858bdeb530748e6a0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1299,7 +1299,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session) drop_rate = (double)stats->total_lost_samples / (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); if (drop_rate > 0.05) { - ui__warning("Processed %lu samples and lost %3.2f%% samples!\n\n", + ui__warning("Processed %" PRIu64 " samples and lost %3.2f%% samples!\n\n", stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, drop_rate * 100.0); } diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 0c264bc685aceb94c544358c38caa8158d441b68..edc2d633b33224530e9dcb7780877bf7d1be08b3 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -115,20 +115,17 @@ int rm_rf(char *path) return rmdir(path); } -static int slow_copyfile(const char *from, const char *to, mode_t mode) +static int slow_copyfile(const char *from, const char *to) { int err = -1; char *line = NULL; size_t n; FILE *from_fp = fopen(from, "r"), *to_fp; - mode_t old_umask; if (from_fp == NULL) goto out; - old_umask = umask(mode ^ 0777); to_fp = fopen(to, "w"); - umask(old_umask); if (to_fp == NULL) goto out_fclose_from; @@ -178,29 +175,48 @@ int copyfile_mode(const char *from, const char *to, mode_t mode) int fromfd, tofd; struct stat st; int err = -1; + char *tmp = NULL, *ptr = NULL; if (stat(from, &st)) goto out; - if (st.st_size == 0) /* /proc? do it slowly... */ - return slow_copyfile(from, to, mode); - - fromfd = open(from, O_RDONLY); - if (fromfd < 0) + /* extra 'x' at the end is to reserve space for '.' */ + if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) { + tmp = NULL; goto out; + } + ptr = strrchr(tmp, '/'); + if (!ptr) + goto out; + ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1); + *ptr = '.'; - tofd = creat(to, mode); + tofd = mkstemp(tmp); if (tofd < 0) - goto out_close_from; + goto out; + + if (fchmod(tofd, mode)) + goto out_close_to; + + if (st.st_size == 0) { /* /proc? do it slowly... */ + err = slow_copyfile(from, tmp); + goto out_close_to; + } + + fromfd = open(from, O_RDONLY); + if (fromfd < 0) + goto out_close_to; err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size); - close(tofd); - if (err) - unlink(to); -out_close_from: close(fromfd); +out_close_to: + close(tofd); + if (!err) + err = link(tmp, to); + unlink(tmp); out: + free(tmp); return err; }