diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-03-30 18:19:31 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-04-08 09:04:55 -0400 |
commit | 814c8c38e13c7050259c72f89bb01f3fc903f642 (patch) | |
tree | bcefeebf548cb2bef07ee42b81518a19ccfe7795 /tools | |
parent | ff5f3bbd40bfb8632f826f1f83223d95363f36af (diff) |
perf record: Add clockid parameter
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 data file.
Since we store the entire perf_event_attr in the EVENT_DESC section we
also already store the used clockid in the data file.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: David Ahern <dsahern@gmail.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yunlong Song <yunlong.song@huawei.com>
Link: http://lkml.kernel.org/r/20150407154851.GR23123@twins.programming.kicks-ass.net
[ Conditionally define CLOCK_BOOTTIME, at least rhel6 doesn't have it - dsahern
Ditto for CLOCK_MONOTONIC_RAW, sles11sp2 doesn't have it - yunlong.song ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 7 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 87 | ||||
-rw-r--r-- | tools/perf/perf.h | 2 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 59 | ||||
-rw-r--r-- | tools/perf/util/header.c | 3 |
5 files changed, 154 insertions, 4 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 355c4f5569b5..4847a793de65 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -250,6 +250,13 @@ is off by default. | |||
250 | --running-time:: | 250 | --running-time:: |
251 | Record running and enabled time for read events (:S) | 251 | Record running and enabled time for read events (:S) |
252 | 252 | ||
253 | -k:: | ||
254 | --clockid:: | ||
255 | Sets the clock id to use for the various time fields in the perf_event_type | ||
256 | records. See clock_gettime(). In particular CLOCK_MONOTONIC and | ||
257 | CLOCK_MONOTONIC_RAW are supported, some events might also allow | ||
258 | CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI. | ||
259 | |||
253 | SEE ALSO | 260 | SEE ALSO |
254 | -------- | 261 | -------- |
255 | linkperf:perf-stat[1], linkperf:perf-list[1] | 262 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 18aad239b401..ac610488d2e1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -711,6 +711,90 @@ static int perf_record_config(const char *var, const char *value, void *cb) | |||
711 | return perf_default_config(var, value, cb); | 711 | return perf_default_config(var, value, cb); |
712 | } | 712 | } |
713 | 713 | ||
714 | struct clockid_map { | ||
715 | const char *name; | ||
716 | int clockid; | ||
717 | }; | ||
718 | |||
719 | #define CLOCKID_MAP(n, c) \ | ||
720 | { .name = n, .clockid = (c), } | ||
721 | |||
722 | #define CLOCKID_END { .name = NULL, } | ||
723 | |||
724 | |||
725 | /* | ||
726 | * Add the missing ones, we need to build on many distros... | ||
727 | */ | ||
728 | #ifndef CLOCK_MONOTONIC_RAW | ||
729 | #define CLOCK_MONOTONIC_RAW 4 | ||
730 | #endif | ||
731 | #ifndef CLOCK_BOOTTIME | ||
732 | #define CLOCK_BOOTTIME 7 | ||
733 | #endif | ||
734 | #ifndef CLOCK_TAI | ||
735 | #define CLOCK_TAI 11 | ||
736 | #endif | ||
737 | |||
738 | static const struct clockid_map clockids[] = { | ||
739 | /* available for all events, NMI safe */ | ||
740 | CLOCKID_MAP("monotonic", CLOCK_MONOTONIC), | ||
741 | CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW), | ||
742 | |||
743 | /* available for some events */ | ||
744 | CLOCKID_MAP("realtime", CLOCK_REALTIME), | ||
745 | CLOCKID_MAP("boottime", CLOCK_BOOTTIME), | ||
746 | CLOCKID_MAP("tai", CLOCK_TAI), | ||
747 | |||
748 | /* available for the lazy */ | ||
749 | CLOCKID_MAP("mono", CLOCK_MONOTONIC), | ||
750 | CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW), | ||
751 | CLOCKID_MAP("real", CLOCK_REALTIME), | ||
752 | CLOCKID_MAP("boot", CLOCK_BOOTTIME), | ||
753 | |||
754 | CLOCKID_END, | ||
755 | }; | ||
756 | |||
757 | static int parse_clockid(const struct option *opt, const char *str, int unset) | ||
758 | { | ||
759 | struct record_opts *opts = (struct record_opts *)opt->value; | ||
760 | const struct clockid_map *cm; | ||
761 | const char *ostr = str; | ||
762 | |||
763 | if (unset) { | ||
764 | opts->use_clockid = 0; | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /* no arg passed */ | ||
769 | if (!str) | ||
770 | return 0; | ||
771 | |||
772 | /* no setting it twice */ | ||
773 | if (opts->use_clockid) | ||
774 | return -1; | ||
775 | |||
776 | opts->use_clockid = true; | ||
777 | |||
778 | /* if its a number, we're done */ | ||
779 | if (sscanf(str, "%d", &opts->clockid) == 1) | ||
780 | return 0; | ||
781 | |||
782 | /* allow a "CLOCK_" prefix to the name */ | ||
783 | if (!strncasecmp(str, "CLOCK_", 6)) | ||
784 | str += 6; | ||
785 | |||
786 | for (cm = clockids; cm->name; cm++) { | ||
787 | if (!strcasecmp(str, cm->name)) { | ||
788 | opts->clockid = cm->clockid; | ||
789 | return 0; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | opts->use_clockid = false; | ||
794 | ui__warning("unknown clockid %s, check man page\n", ostr); | ||
795 | return -1; | ||
796 | } | ||
797 | |||
714 | static const char * const __record_usage[] = { | 798 | static const char * const __record_usage[] = { |
715 | "perf record [<options>] [<command>]", | 799 | "perf record [<options>] [<command>]", |
716 | "perf record [<options>] -- <command> [<options>]", | 800 | "perf record [<options>] -- <command> [<options>]", |
@@ -842,6 +926,9 @@ struct option __record_options[] = { | |||
842 | "Sample machine registers on interrupt"), | 926 | "Sample machine registers on interrupt"), |
843 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, | 927 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, |
844 | "Record running/enabled time of read (:S) events"), | 928 | "Record running/enabled time of read (:S) events"), |
929 | OPT_CALLBACK('k', "clockid", &record.opts, | ||
930 | "clockid", "clockid to use for events, see clock_gettime()", | ||
931 | parse_clockid), | ||
845 | OPT_END() | 932 | OPT_END() |
846 | }; | 933 | }; |
847 | 934 | ||
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index c38a085a5571..e14bb637255c 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -62,6 +62,8 @@ struct record_opts { | |||
62 | u64 user_interval; | 62 | u64 user_interval; |
63 | bool sample_transaction; | 63 | bool sample_transaction; |
64 | unsigned initial_delay; | 64 | unsigned initial_delay; |
65 | bool use_clockid; | ||
66 | clockid_t clockid; | ||
65 | }; | 67 | }; |
66 | 68 | ||
67 | struct option; | 69 | struct option; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 358e5954baa8..d190f99a3a97 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -32,8 +32,12 @@ static struct { | |||
32 | bool exclude_guest; | 32 | bool exclude_guest; |
33 | bool mmap2; | 33 | bool mmap2; |
34 | bool cloexec; | 34 | bool cloexec; |
35 | bool clockid; | ||
36 | bool clockid_wrong; | ||
35 | } perf_missing_features; | 37 | } perf_missing_features; |
36 | 38 | ||
39 | static clockid_t clockid; | ||
40 | |||
37 | static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) | 41 | static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) |
38 | { | 42 | { |
39 | return 0; | 43 | return 0; |
@@ -761,6 +765,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
761 | attr->disabled = 0; | 765 | attr->disabled = 0; |
762 | attr->enable_on_exec = 0; | 766 | attr->enable_on_exec = 0; |
763 | } | 767 | } |
768 | |||
769 | clockid = opts->clockid; | ||
770 | if (opts->use_clockid) { | ||
771 | attr->use_clockid = 1; | ||
772 | attr->clockid = opts->clockid; | ||
773 | } | ||
764 | } | 774 | } |
765 | 775 | ||
766 | static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 776 | static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -1036,7 +1046,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
1036 | ret += PRINT_ATTR2(exclude_user, exclude_kernel); | 1046 | ret += PRINT_ATTR2(exclude_user, exclude_kernel); |
1037 | ret += PRINT_ATTR2(exclude_hv, exclude_idle); | 1047 | ret += PRINT_ATTR2(exclude_hv, exclude_idle); |
1038 | ret += PRINT_ATTR2(mmap, comm); | 1048 | ret += PRINT_ATTR2(mmap, comm); |
1039 | ret += PRINT_ATTR2(mmap2, comm_exec); | ||
1040 | ret += PRINT_ATTR2(freq, inherit_stat); | 1049 | ret += PRINT_ATTR2(freq, inherit_stat); |
1041 | ret += PRINT_ATTR2(enable_on_exec, task); | 1050 | ret += PRINT_ATTR2(enable_on_exec, task); |
1042 | ret += PRINT_ATTR2(watermark, precise_ip); | 1051 | ret += PRINT_ATTR2(watermark, precise_ip); |
@@ -1044,6 +1053,9 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
1044 | ret += PRINT_ATTR2(exclude_host, exclude_guest); | 1053 | ret += PRINT_ATTR2(exclude_host, exclude_guest); |
1045 | ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, | 1054 | ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, |
1046 | "excl.callchain_user", exclude_callchain_user); | 1055 | "excl.callchain_user", exclude_callchain_user); |
1056 | ret += PRINT_ATTR2(mmap2, comm_exec); | ||
1057 | ret += __PRINT_ATTR("%u",,use_clockid); | ||
1058 | |||
1047 | 1059 | ||
1048 | ret += PRINT_ATTR_U32(wakeup_events); | 1060 | ret += PRINT_ATTR_U32(wakeup_events); |
1049 | ret += PRINT_ATTR_U32(wakeup_watermark); | 1061 | ret += PRINT_ATTR_U32(wakeup_watermark); |
@@ -1055,6 +1067,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
1055 | ret += PRINT_ATTR_X64(branch_sample_type); | 1067 | ret += PRINT_ATTR_X64(branch_sample_type); |
1056 | ret += PRINT_ATTR_X64(sample_regs_user); | 1068 | ret += PRINT_ATTR_X64(sample_regs_user); |
1057 | ret += PRINT_ATTR_U32(sample_stack_user); | 1069 | ret += PRINT_ATTR_U32(sample_stack_user); |
1070 | ret += PRINT_ATTR_U32(clockid); | ||
1058 | ret += PRINT_ATTR_X64(sample_regs_intr); | 1071 | ret += PRINT_ATTR_X64(sample_regs_intr); |
1059 | 1072 | ||
1060 | ret += fprintf(fp, "%.60s\n", graph_dotted_line); | 1073 | ret += fprintf(fp, "%.60s\n", graph_dotted_line); |
@@ -1085,6 +1098,12 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
1085 | } | 1098 | } |
1086 | 1099 | ||
1087 | fallback_missing_features: | 1100 | fallback_missing_features: |
1101 | if (perf_missing_features.clockid_wrong) | ||
1102 | evsel->attr.clockid = CLOCK_MONOTONIC; /* should always work */ | ||
1103 | if (perf_missing_features.clockid) { | ||
1104 | evsel->attr.use_clockid = 0; | ||
1105 | evsel->attr.clockid = 0; | ||
1106 | } | ||
1088 | if (perf_missing_features.cloexec) | 1107 | if (perf_missing_features.cloexec) |
1089 | flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; | 1108 | flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; |
1090 | if (perf_missing_features.mmap2) | 1109 | if (perf_missing_features.mmap2) |
@@ -1122,6 +1141,17 @@ retry_open: | |||
1122 | goto try_fallback; | 1141 | goto try_fallback; |
1123 | } | 1142 | } |
1124 | set_rlimit = NO_CHANGE; | 1143 | set_rlimit = NO_CHANGE; |
1144 | |||
1145 | /* | ||
1146 | * If we succeeded but had to kill clockid, fail and | ||
1147 | * have perf_evsel__open_strerror() print us a nice | ||
1148 | * error. | ||
1149 | */ | ||
1150 | if (perf_missing_features.clockid || | ||
1151 | perf_missing_features.clockid_wrong) { | ||
1152 | err = -EINVAL; | ||
1153 | goto out_close; | ||
1154 | } | ||
1125 | } | 1155 | } |
1126 | } | 1156 | } |
1127 | 1157 | ||
@@ -1155,7 +1185,17 @@ try_fallback: | |||
1155 | if (err != -EINVAL || cpu > 0 || thread > 0) | 1185 | if (err != -EINVAL || cpu > 0 || thread > 0) |
1156 | goto out_close; | 1186 | goto out_close; |
1157 | 1187 | ||
1158 | if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { | 1188 | /* |
1189 | * Must probe features in the order they were added to the | ||
1190 | * perf_event_attr interface. | ||
1191 | */ | ||
1192 | if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { | ||
1193 | perf_missing_features.clockid_wrong = true; | ||
1194 | goto fallback_missing_features; | ||
1195 | } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { | ||
1196 | perf_missing_features.clockid = true; | ||
1197 | goto fallback_missing_features; | ||
1198 | } else if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { | ||
1159 | perf_missing_features.cloexec = true; | 1199 | perf_missing_features.cloexec = true; |
1160 | goto fallback_missing_features; | 1200 | goto fallback_missing_features; |
1161 | } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { | 1201 | } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { |
@@ -2063,9 +2103,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
2063 | if_print(exclude_hv); | 2103 | if_print(exclude_hv); |
2064 | if_print(exclude_idle); | 2104 | if_print(exclude_idle); |
2065 | if_print(mmap); | 2105 | if_print(mmap); |
2066 | if_print(mmap2); | ||
2067 | if_print(comm); | 2106 | if_print(comm); |
2068 | if_print(comm_exec); | ||
2069 | if_print(freq); | 2107 | if_print(freq); |
2070 | if_print(inherit_stat); | 2108 | if_print(inherit_stat); |
2071 | if_print(enable_on_exec); | 2109 | if_print(enable_on_exec); |
@@ -2076,10 +2114,17 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
2076 | if_print(sample_id_all); | 2114 | if_print(sample_id_all); |
2077 | if_print(exclude_host); | 2115 | if_print(exclude_host); |
2078 | if_print(exclude_guest); | 2116 | if_print(exclude_guest); |
2117 | if_print(mmap2); | ||
2118 | if_print(comm_exec); | ||
2119 | if_print(use_clockid); | ||
2079 | if_print(__reserved_1); | 2120 | if_print(__reserved_1); |
2080 | if_print(wakeup_events); | 2121 | if_print(wakeup_events); |
2081 | if_print(bp_type); | 2122 | if_print(bp_type); |
2082 | if_print(branch_sample_type); | 2123 | if_print(branch_sample_type); |
2124 | if_print(sample_regs_user); | ||
2125 | if_print(sample_stack_user); | ||
2126 | if_print(clockid); | ||
2127 | if_print(sample_regs_intr); | ||
2083 | } | 2128 | } |
2084 | out: | 2129 | out: |
2085 | fputc('\n', fp); | 2130 | fputc('\n', fp); |
@@ -2158,6 +2203,12 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2158 | "The PMU counters are busy/taken by another profiler.\n" | 2203 | "The PMU counters are busy/taken by another profiler.\n" |
2159 | "We found oprofile daemon running, please stop it and try again."); | 2204 | "We found oprofile daemon running, please stop it and try again."); |
2160 | break; | 2205 | break; |
2206 | case EINVAL: | ||
2207 | if (perf_missing_features.clockid) | ||
2208 | return scnprintf(msg, size, "clockid feature not supported."); | ||
2209 | if (perf_missing_features.clockid_wrong) | ||
2210 | return scnprintf(msg, size, "wrong clockid (%d).", clockid); | ||
2211 | break; | ||
2161 | default: | 2212 | default: |
2162 | break; | 2213 | break; |
2163 | } | 2214 | } |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index fb432153e2aa..de5f4669ba5f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1098,6 +1098,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1098 | } | 1098 | } |
1099 | fprintf(fp, " }"); | 1099 | fprintf(fp, " }"); |
1100 | } | 1100 | } |
1101 | if (evsel->attr.use_clockid) | ||
1102 | fprintf(fp, ", clockid = %d", evsel->attr.clockid); | ||
1103 | |||
1101 | 1104 | ||
1102 | fputc('\n', fp); | 1105 | fputc('\n', fp); |
1103 | } | 1106 | } |