From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753581AbbC3WTs (ORCPT ); Mon, 30 Mar 2015 18:19:48 -0400 Received: from mail-pa0-f53.google.com ([209.85.220.53]:35032 "EHLO mail-pa0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752890AbbC3WTm (ORCPT ); Mon, 30 Mar 2015 18:19:42 -0400 From: Stephane Eranian To: linux-kernel@vger.kernel.org Cc: acme@redhat.com, peterz@infradead.org, mingo@elte.hu, ak@linux.intel.com, jolsa@redhat.com, namhyung@kernel.org, cel@us.ibm.com, sukadev@linux.vnet.ibm.com, sonnyrao@chromium.org, johnmccutchan@google.com, dsahern@gmail.com, adrian.hunter@intel.com, pawel.moll@arm.com Subject: [PATCH v6 1/4] perf,record: Add clockid parameter Date: Tue, 31 Mar 2015 00:19:31 +0200 Message-Id: <1427753974-13380-2-git-send-email-eranian@google.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1427753974-13380-1-git-send-email-eranian@google.com> References: <1427753974-13380-1-git-send-email-eranian@google.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Peter Zijlstra Teach perf-record about the new perf_event_attr:{use_+clockid, clockid} fields. Add a simple parameter to set the clock (if any) to be used for the events to be recorded into the dat file. Incorporated improvements suggested by from David Ahern on LKML. Signed-off-by: Peter Zijlstra --- tools/perf/Documentation/perf-record.txt | 7 +++ tools/perf/builtin-record.c | 78 ++++++++++++++++++++++++++++++++ tools/perf/perf.h | 1 + tools/perf/util/evsel.c | 31 ++++++++++++- tools/perf/util/header.c | 2 + 5 files changed, 118 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 355c4f5..4847a79 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -250,6 +250,13 @@ is off by default. --running-time:: Record running and enabled time for read events (:S) +-k:: +--clockid:: +Sets the clock id to use for the various time fields in the perf_event_type +records. See clock_gettime(). In particular CLOCK_MONOTONIC and +CLOCK_MONOTONIC_RAW are supported, some events might also allow +CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 18aad239..fc42a9a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -711,6 +711,80 @@ static int perf_record_config(const char *var, const char *value, void *cb) return perf_default_config(var, value, cb); } +struct clockid_map { + const char *name; + int clockid; +}; + +#define CLOCKID_MAP(n, c) \ + { .name = n, .clockid = (c), } + +#define CLOCKID_END { .name = NULL, } + +/* + * Doesn't appear to have made it into userspace so define here if missing. + */ +#ifndef CLOCK_TAI +#define CLOCK_TAI 11 +#endif + +static const struct clockid_map clockids[] = { + /* available for all events, NMI safe */ + CLOCKID_MAP("monotonic", CLOCK_MONOTONIC), + CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW), + + /* available for some events */ + CLOCKID_MAP("realtime", CLOCK_REALTIME), + CLOCKID_MAP("boottime", CLOCK_BOOTTIME), + CLOCKID_MAP("tai", CLOCK_TAI), + + /* available for the lazy */ + CLOCKID_MAP("mono", CLOCK_MONOTONIC), + CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW), + CLOCKID_MAP("real", CLOCK_REALTIME), + + + CLOCKID_END, +}; + +static int parse_clockid(const struct option *opt, const char *str, int unset) +{ + clockid_t *clk = (clockid_t *)opt->value; + const struct clockid_map *cm; + const char *ostr = str; + + if (unset) { + *clk = -1; + return 0; + } + + /* no arg passed */ + if (!str) + return 0; + + /* no setting it twice */ + if (*clk != -1) + return -1; + + /* if its a number, we're done */ + if (sscanf(str, "%d", clk) == 1) + return 0; + + /* allow a "CLOCK_" prefix to the name */ + if (!strncasecmp(str, "CLOCK_", 6)) + str += 6; + + for (cm = clockids; cm->name; cm++) { + if (!strcasecmp(str, cm->name)) { + *clk = cm->clockid; + return 0; + } + } + + ui__warning("unknown clockid %s, check man page\n", ostr); + return -1; +} + static const char * const __record_usage[] = { "perf record [] []", "perf record [] -- []", @@ -739,6 +813,7 @@ static struct record record = { .uses_mmap = true, .default_per_cpu = true, }, + .clockid = -1, }, .tool = { .sample = process_sample_event, @@ -842,6 +917,9 @@ struct option __record_options[] = { "Sample machine registers on interrupt"), OPT_BOOLEAN(0, "running-time", &record.opts.running_time, "Record running/enabled time of read (:S) events"), + OPT_CALLBACK('k', "clockid", &record.opts.clockid, + "clockid", "clockid to use for events, see clock_gettime()", + parse_clockid), OPT_END() }; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index c38a085..275c0c5 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -62,6 +62,7 @@ struct record_opts { u64 user_interval; bool sample_transaction; unsigned initial_delay; + clockid_t clockid; }; struct option; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 358e595..820e789 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -32,6 +32,7 @@ static struct { bool exclude_guest; bool mmap2; bool cloexec; + bool clockid; } perf_missing_features; static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) @@ -761,6 +762,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->disabled = 0; attr->enable_on_exec = 0; } + + if (opts->clockid >= 0) { + attr->use_clockid = 1; + attr->clockid = opts->clockid; + } else + attr->clockid = -1; } static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) @@ -1044,6 +1051,8 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret += PRINT_ATTR2(exclude_host, exclude_guest); ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, "excl.callchain_user", exclude_callchain_user); + ret += __PRINT_ATTR("%u",,use_clockid); + ret += PRINT_ATTR_U32(wakeup_events); ret += PRINT_ATTR_U32(wakeup_watermark); @@ -1056,6 +1065,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret += PRINT_ATTR_X64(sample_regs_user); ret += PRINT_ATTR_U32(sample_stack_user); ret += PRINT_ATTR_X64(sample_regs_intr); + ret += PRINT_ATTR_U32(clockid); ret += fprintf(fp, "%.60s\n", graph_dotted_line); @@ -1122,6 +1132,16 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, goto try_fallback; } set_rlimit = NO_CHANGE; + + /* + * If we succeeded but had to kill clockid, fail and + * have perf_evsel__open_strerror() print us a nice + * error. + */ + if (perf_missing_features.clockid) { + err = -EINVAL; + goto out_close; + } } } @@ -1155,7 +1175,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, if (err != -EINVAL || cpu > 0 || thread > 0) goto out_close; - if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { + if (!perf_missing_features.clockid && evsel->attr.use_clockid) { + perf_missing_features.clockid = true; + goto fallback_missing_features; + } else if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { perf_missing_features.cloexec = true; goto fallback_missing_features; } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { @@ -2080,6 +2103,8 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, if_print(wakeup_events); if_print(bp_type); if_print(branch_sample_type); + if_print(clockid); + } out: fputc('\n', fp); @@ -2158,6 +2183,10 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "The PMU counters are busy/taken by another profiler.\n" "We found oprofile daemon running, please stop it and try again."); break; + case EINVAL: + if (perf_missing_features.clockid) + return scnprintf(msg, size, "%d %s", evsel->attr.clockid, "clockid not supported."); + break; default: break; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index fb43215..164441a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1098,6 +1098,8 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) } fprintf(fp, " }"); } + fprintf(fp, ", clockid = %d", evsel->attr.clockid); + fputc('\n', fp); } -- 1.9.1