diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-09-23 01:21:38 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-09-23 01:21:38 -0400 |
commit | 6b652de2b27c0a4020ce0e8f277e782b6af76096 (patch) | |
tree | a79c2f151cb0b3a0cb19c3058b4bd4d003e03f86 /tools/perf | |
parent | 739f1bcd045f473d79358aac94439722d41a2650 (diff) | |
parent | 2d831454140f28fa643b78deede4511b9e2c9e5f (diff) |
Merge tag 'perf-core-for-mingo-20160922' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements from Arnaldo Carvalho de Melo:
New features:
- Add support for interacting with Coresight PMU ETMs/PTMs, that are IP blocks
to perform hardware assisted tracing on a ARM CPU core (Mathieu Poirier)
Infrastructure changes:
- Histogram prep work for the upcoming c2c tool (Jiri Olsa)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile.config | 11 | ||||
-rw-r--r-- | tools/perf/arch/arm/util/Build | 2 | ||||
-rw-r--r-- | tools/perf/arch/arm/util/auxtrace.c | 54 | ||||
-rw-r--r-- | tools/perf/arch/arm/util/cs-etm.c | 617 | ||||
-rw-r--r-- | tools/perf/arch/arm/util/cs-etm.h | 26 | ||||
-rw-r--r-- | tools/perf/arch/arm/util/pmu.c | 36 | ||||
-rw-r--r-- | tools/perf/arch/arm64/util/Build | 4 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 9 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 13 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 2 | ||||
-rw-r--r-- | tools/perf/ui/hist.c | 2 | ||||
-rw-r--r-- | tools/perf/ui/stdio/hist.c | 14 | ||||
-rw-r--r-- | tools/perf/util/Build | 1 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.c | 1 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.h | 1 | ||||
-rw-r--r-- | tools/perf/util/cs-etm.h | 74 | ||||
-rw-r--r-- | tools/perf/util/drv_configs.c | 77 | ||||
-rw-r--r-- | tools/perf/util/drv_configs.h | 26 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 5 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 2 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 16 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 11 |
24 files changed, 996 insertions, 20 deletions
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 24803c58049a..72edf83d76b7 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -746,10 +746,13 @@ ifdef LIBBABELTRACE | |||
746 | endif | 746 | endif |
747 | 747 | ||
748 | ifndef NO_AUXTRACE | 748 | ifndef NO_AUXTRACE |
749 | ifeq ($(feature-get_cpuid), 0) | 749 | ifeq ($(ARCH),x86) |
750 | msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc); | 750 | ifeq ($(feature-get_cpuid), 0) |
751 | NO_AUXTRACE := 1 | 751 | msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc); |
752 | else | 752 | NO_AUXTRACE := 1 |
753 | endif | ||
754 | endif | ||
755 | ifndef NO_AUXTRACE | ||
753 | $(call detected,CONFIG_AUXTRACE) | 756 | $(call detected,CONFIG_AUXTRACE) |
754 | CFLAGS += -DHAVE_AUXTRACE_SUPPORT | 757 | CFLAGS += -DHAVE_AUXTRACE_SUPPORT |
755 | endif | 758 | endif |
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build index f98da17357c0..e64c5f216448 100644 --- a/tools/perf/arch/arm/util/Build +++ b/tools/perf/arch/arm/util/Build | |||
@@ -2,3 +2,5 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o | |||
2 | 2 | ||
3 | libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o | 3 | libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o |
4 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | 4 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o |
5 | |||
6 | libperf-$(CONFIG_AUXTRACE) += pmu.o auxtrace.o cs-etm.o | ||
diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c new file mode 100644 index 000000000000..8edf2cb71564 --- /dev/null +++ b/tools/perf/arch/arm/util/auxtrace.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | ||
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <stdbool.h> | ||
19 | #include <linux/coresight-pmu.h> | ||
20 | |||
21 | #include "../../util/auxtrace.h" | ||
22 | #include "../../util/evlist.h" | ||
23 | #include "../../util/pmu.h" | ||
24 | #include "cs-etm.h" | ||
25 | |||
26 | struct auxtrace_record | ||
27 | *auxtrace_record__init(struct perf_evlist *evlist, int *err) | ||
28 | { | ||
29 | struct perf_pmu *cs_etm_pmu; | ||
30 | struct perf_evsel *evsel; | ||
31 | bool found_etm = false; | ||
32 | |||
33 | cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); | ||
34 | |||
35 | if (evlist) { | ||
36 | evlist__for_each_entry(evlist, evsel) { | ||
37 | if (cs_etm_pmu && | ||
38 | evsel->attr.type == cs_etm_pmu->type) | ||
39 | found_etm = true; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | if (found_etm) | ||
44 | return cs_etm_record_init(err); | ||
45 | |||
46 | /* | ||
47 | * Clear 'err' even if we haven't found a cs_etm event - that way perf | ||
48 | * record can still be used even if tracers aren't present. The NULL | ||
49 | * return value will take care of telling the infrastructure HW tracing | ||
50 | * isn't available. | ||
51 | */ | ||
52 | *err = 0; | ||
53 | return NULL; | ||
54 | } | ||
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c new file mode 100644 index 000000000000..47d584da5819 --- /dev/null +++ b/tools/perf/arch/arm/util/cs-etm.c | |||
@@ -0,0 +1,617 @@ | |||
1 | /* | ||
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | ||
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <api/fs/fs.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/coresight-pmu.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/log2.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include "cs-etm.h" | ||
26 | #include "../../perf.h" | ||
27 | #include "../../util/auxtrace.h" | ||
28 | #include "../../util/cpumap.h" | ||
29 | #include "../../util/evlist.h" | ||
30 | #include "../../util/evsel.h" | ||
31 | #include "../../util/pmu.h" | ||
32 | #include "../../util/thread_map.h" | ||
33 | #include "../../util/cs-etm.h" | ||
34 | |||
35 | #include <stdlib.h> | ||
36 | |||
37 | #define ENABLE_SINK_MAX 128 | ||
38 | #define CS_BUS_DEVICE_PATH "/bus/coresight/devices/" | ||
39 | |||
40 | struct cs_etm_recording { | ||
41 | struct auxtrace_record itr; | ||
42 | struct perf_pmu *cs_etm_pmu; | ||
43 | struct perf_evlist *evlist; | ||
44 | bool snapshot_mode; | ||
45 | size_t snapshot_size; | ||
46 | }; | ||
47 | |||
48 | static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); | ||
49 | |||
50 | static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, | ||
51 | struct record_opts *opts, | ||
52 | const char *str) | ||
53 | { | ||
54 | struct cs_etm_recording *ptr = | ||
55 | container_of(itr, struct cs_etm_recording, itr); | ||
56 | unsigned long long snapshot_size = 0; | ||
57 | char *endptr; | ||
58 | |||
59 | if (str) { | ||
60 | snapshot_size = strtoull(str, &endptr, 0); | ||
61 | if (*endptr || snapshot_size > SIZE_MAX) | ||
62 | return -1; | ||
63 | } | ||
64 | |||
65 | opts->auxtrace_snapshot_mode = true; | ||
66 | opts->auxtrace_snapshot_size = snapshot_size; | ||
67 | ptr->snapshot_size = snapshot_size; | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int cs_etm_recording_options(struct auxtrace_record *itr, | ||
73 | struct perf_evlist *evlist, | ||
74 | struct record_opts *opts) | ||
75 | { | ||
76 | struct cs_etm_recording *ptr = | ||
77 | container_of(itr, struct cs_etm_recording, itr); | ||
78 | struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; | ||
79 | struct perf_evsel *evsel, *cs_etm_evsel = NULL; | ||
80 | const struct cpu_map *cpus = evlist->cpus; | ||
81 | bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0); | ||
82 | |||
83 | ptr->evlist = evlist; | ||
84 | ptr->snapshot_mode = opts->auxtrace_snapshot_mode; | ||
85 | |||
86 | evlist__for_each_entry(evlist, evsel) { | ||
87 | if (evsel->attr.type == cs_etm_pmu->type) { | ||
88 | if (cs_etm_evsel) { | ||
89 | pr_err("There may be only one %s event\n", | ||
90 | CORESIGHT_ETM_PMU_NAME); | ||
91 | return -EINVAL; | ||
92 | } | ||
93 | evsel->attr.freq = 0; | ||
94 | evsel->attr.sample_period = 1; | ||
95 | cs_etm_evsel = evsel; | ||
96 | opts->full_auxtrace = true; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* no need to continue if at least one event of interest was found */ | ||
101 | if (!cs_etm_evsel) | ||
102 | return 0; | ||
103 | |||
104 | if (opts->use_clockid) { | ||
105 | pr_err("Cannot use clockid (-k option) with %s\n", | ||
106 | CORESIGHT_ETM_PMU_NAME); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | /* we are in snapshot mode */ | ||
111 | if (opts->auxtrace_snapshot_mode) { | ||
112 | /* | ||
113 | * No size were given to '-S' or '-m,', so go with | ||
114 | * the default | ||
115 | */ | ||
116 | if (!opts->auxtrace_snapshot_size && | ||
117 | !opts->auxtrace_mmap_pages) { | ||
118 | if (privileged) { | ||
119 | opts->auxtrace_mmap_pages = MiB(4) / page_size; | ||
120 | } else { | ||
121 | opts->auxtrace_mmap_pages = | ||
122 | KiB(128) / page_size; | ||
123 | if (opts->mmap_pages == UINT_MAX) | ||
124 | opts->mmap_pages = KiB(256) / page_size; | ||
125 | } | ||
126 | } else if (!opts->auxtrace_mmap_pages && !privileged && | ||
127 | opts->mmap_pages == UINT_MAX) { | ||
128 | opts->mmap_pages = KiB(256) / page_size; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * '-m,xyz' was specified but no snapshot size, so make the | ||
133 | * snapshot size as big as the auxtrace mmap area. | ||
134 | */ | ||
135 | if (!opts->auxtrace_snapshot_size) { | ||
136 | opts->auxtrace_snapshot_size = | ||
137 | opts->auxtrace_mmap_pages * (size_t)page_size; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * -Sxyz was specified but no auxtrace mmap area, so make the | ||
142 | * auxtrace mmap area big enough to fit the requested snapshot | ||
143 | * size. | ||
144 | */ | ||
145 | if (!opts->auxtrace_mmap_pages) { | ||
146 | size_t sz = opts->auxtrace_snapshot_size; | ||
147 | |||
148 | sz = round_up(sz, page_size) / page_size; | ||
149 | opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); | ||
150 | } | ||
151 | |||
152 | /* Snapshost size can't be bigger than the auxtrace area */ | ||
153 | if (opts->auxtrace_snapshot_size > | ||
154 | opts->auxtrace_mmap_pages * (size_t)page_size) { | ||
155 | pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", | ||
156 | opts->auxtrace_snapshot_size, | ||
157 | opts->auxtrace_mmap_pages * (size_t)page_size); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | /* Something went wrong somewhere - this shouldn't happen */ | ||
162 | if (!opts->auxtrace_snapshot_size || | ||
163 | !opts->auxtrace_mmap_pages) { | ||
164 | pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | /* We are in full trace mode but '-m,xyz' wasn't specified */ | ||
170 | if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { | ||
171 | if (privileged) { | ||
172 | opts->auxtrace_mmap_pages = MiB(4) / page_size; | ||
173 | } else { | ||
174 | opts->auxtrace_mmap_pages = KiB(128) / page_size; | ||
175 | if (opts->mmap_pages == UINT_MAX) | ||
176 | opts->mmap_pages = KiB(256) / page_size; | ||
177 | } | ||
178 | |||
179 | } | ||
180 | |||
181 | /* Validate auxtrace_mmap_pages provided by user */ | ||
182 | if (opts->auxtrace_mmap_pages) { | ||
183 | unsigned int max_page = (KiB(128) / page_size); | ||
184 | size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; | ||
185 | |||
186 | if (!privileged && | ||
187 | opts->auxtrace_mmap_pages > max_page) { | ||
188 | opts->auxtrace_mmap_pages = max_page; | ||
189 | pr_err("auxtrace too big, truncating to %d\n", | ||
190 | max_page); | ||
191 | } | ||
192 | |||
193 | if (!is_power_of_2(sz)) { | ||
194 | pr_err("Invalid mmap size for %s: must be a power of 2\n", | ||
195 | CORESIGHT_ETM_PMU_NAME); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | if (opts->auxtrace_snapshot_mode) | ||
201 | pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, | ||
202 | opts->auxtrace_snapshot_size); | ||
203 | |||
204 | if (cs_etm_evsel) { | ||
205 | /* | ||
206 | * To obtain the auxtrace buffer file descriptor, the auxtrace | ||
207 | * event must come first. | ||
208 | */ | ||
209 | perf_evlist__to_front(evlist, cs_etm_evsel); | ||
210 | /* | ||
211 | * In the case of per-cpu mmaps, we need the CPU on the | ||
212 | * AUX event. | ||
213 | */ | ||
214 | if (!cpu_map__empty(cpus)) | ||
215 | perf_evsel__set_sample_bit(cs_etm_evsel, CPU); | ||
216 | } | ||
217 | |||
218 | /* Add dummy event to keep tracking */ | ||
219 | if (opts->full_auxtrace) { | ||
220 | struct perf_evsel *tracking_evsel; | ||
221 | int err; | ||
222 | |||
223 | err = parse_events(evlist, "dummy:u", NULL); | ||
224 | if (err) | ||
225 | return err; | ||
226 | |||
227 | tracking_evsel = perf_evlist__last(evlist); | ||
228 | perf_evlist__set_tracking_event(evlist, tracking_evsel); | ||
229 | |||
230 | tracking_evsel->attr.freq = 0; | ||
231 | tracking_evsel->attr.sample_period = 1; | ||
232 | |||
233 | /* In per-cpu case, always need the time of mmap events etc */ | ||
234 | if (!cpu_map__empty(cpus)) | ||
235 | perf_evsel__set_sample_bit(tracking_evsel, TIME); | ||
236 | } | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static u64 cs_etm_get_config(struct auxtrace_record *itr) | ||
242 | { | ||
243 | u64 config = 0; | ||
244 | struct cs_etm_recording *ptr = | ||
245 | container_of(itr, struct cs_etm_recording, itr); | ||
246 | struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; | ||
247 | struct perf_evlist *evlist = ptr->evlist; | ||
248 | struct perf_evsel *evsel; | ||
249 | |||
250 | evlist__for_each_entry(evlist, evsel) { | ||
251 | if (evsel->attr.type == cs_etm_pmu->type) { | ||
252 | /* | ||
253 | * Variable perf_event_attr::config is assigned to | ||
254 | * ETMv3/PTM. The bit fields have been made to match | ||
255 | * the ETMv3.5 ETRMCR register specification. See the | ||
256 | * PMU_FORMAT_ATTR() declarations in | ||
257 | * drivers/hwtracing/coresight/coresight-perf.c for | ||
258 | * details. | ||
259 | */ | ||
260 | config = evsel->attr.config; | ||
261 | break; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | return config; | ||
266 | } | ||
267 | |||
268 | static size_t | ||
269 | cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, | ||
270 | struct perf_evlist *evlist __maybe_unused) | ||
271 | { | ||
272 | int i; | ||
273 | int etmv3 = 0, etmv4 = 0; | ||
274 | const struct cpu_map *cpus = evlist->cpus; | ||
275 | |||
276 | /* cpu map is not empty, we have specific CPUs to work with */ | ||
277 | if (!cpu_map__empty(cpus)) { | ||
278 | for (i = 0; i < cpu_map__nr(cpus); i++) { | ||
279 | if (cs_etm_is_etmv4(itr, cpus->map[i])) | ||
280 | etmv4++; | ||
281 | else | ||
282 | etmv3++; | ||
283 | } | ||
284 | } else { | ||
285 | /* get configuration for all CPUs in the system */ | ||
286 | for (i = 0; i < cpu__max_cpu(); i++) { | ||
287 | if (cs_etm_is_etmv4(itr, i)) | ||
288 | etmv4++; | ||
289 | else | ||
290 | etmv3++; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return (CS_ETM_HEADER_SIZE + | ||
295 | (etmv4 * CS_ETMV4_PRIV_SIZE) + | ||
296 | (etmv3 * CS_ETMV3_PRIV_SIZE)); | ||
297 | } | ||
298 | |||
299 | static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { | ||
300 | [CS_ETM_ETMCCER] = "mgmt/etmccer", | ||
301 | [CS_ETM_ETMIDR] = "mgmt/etmidr", | ||
302 | }; | ||
303 | |||
304 | static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { | ||
305 | [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", | ||
306 | [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", | ||
307 | [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", | ||
308 | [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", | ||
309 | [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", | ||
310 | }; | ||
311 | |||
312 | static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) | ||
313 | { | ||
314 | bool ret = false; | ||
315 | char path[PATH_MAX]; | ||
316 | int scan; | ||
317 | unsigned int val; | ||
318 | struct cs_etm_recording *ptr = | ||
319 | container_of(itr, struct cs_etm_recording, itr); | ||
320 | struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; | ||
321 | |||
322 | /* Take any of the RO files for ETMv4 and see if it present */ | ||
323 | snprintf(path, PATH_MAX, "cpu%d/%s", | ||
324 | cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); | ||
325 | scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); | ||
326 | |||
327 | /* The file was read successfully, we have a winner */ | ||
328 | if (scan == 1) | ||
329 | ret = true; | ||
330 | |||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) | ||
335 | { | ||
336 | char pmu_path[PATH_MAX]; | ||
337 | int scan; | ||
338 | unsigned int val = 0; | ||
339 | |||
340 | /* Get RO metadata from sysfs */ | ||
341 | snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); | ||
342 | |||
343 | scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); | ||
344 | if (scan != 1) | ||
345 | pr_err("%s: error reading: %s\n", __func__, pmu_path); | ||
346 | |||
347 | return val; | ||
348 | } | ||
349 | |||
350 | static void cs_etm_get_metadata(int cpu, u32 *offset, | ||
351 | struct auxtrace_record *itr, | ||
352 | struct auxtrace_info_event *info) | ||
353 | { | ||
354 | u32 increment; | ||
355 | u64 magic; | ||
356 | struct cs_etm_recording *ptr = | ||
357 | container_of(itr, struct cs_etm_recording, itr); | ||
358 | struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; | ||
359 | |||
360 | /* first see what kind of tracer this cpu is affined to */ | ||
361 | if (cs_etm_is_etmv4(itr, cpu)) { | ||
362 | magic = __perf_cs_etmv4_magic; | ||
363 | /* Get trace configuration register */ | ||
364 | info->priv[*offset + CS_ETMV4_TRCCONFIGR] = | ||
365 | cs_etm_get_config(itr); | ||
366 | /* Get traceID from the framework */ | ||
367 | info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = | ||
368 | coresight_get_trace_id(cpu); | ||
369 | /* Get read-only information from sysFS */ | ||
370 | info->priv[*offset + CS_ETMV4_TRCIDR0] = | ||
371 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
372 | metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); | ||
373 | info->priv[*offset + CS_ETMV4_TRCIDR1] = | ||
374 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
375 | metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); | ||
376 | info->priv[*offset + CS_ETMV4_TRCIDR2] = | ||
377 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
378 | metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); | ||
379 | info->priv[*offset + CS_ETMV4_TRCIDR8] = | ||
380 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
381 | metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); | ||
382 | info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] = | ||
383 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
384 | metadata_etmv4_ro | ||
385 | [CS_ETMV4_TRCAUTHSTATUS]); | ||
386 | |||
387 | /* How much space was used */ | ||
388 | increment = CS_ETMV4_PRIV_MAX; | ||
389 | } else { | ||
390 | magic = __perf_cs_etmv3_magic; | ||
391 | /* Get configuration register */ | ||
392 | info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); | ||
393 | /* Get traceID from the framework */ | ||
394 | info->priv[*offset + CS_ETM_ETMTRACEIDR] = | ||
395 | coresight_get_trace_id(cpu); | ||
396 | /* Get read-only information from sysFS */ | ||
397 | info->priv[*offset + CS_ETM_ETMCCER] = | ||
398 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
399 | metadata_etmv3_ro[CS_ETM_ETMCCER]); | ||
400 | info->priv[*offset + CS_ETM_ETMIDR] = | ||
401 | cs_etm_get_ro(cs_etm_pmu, cpu, | ||
402 | metadata_etmv3_ro[CS_ETM_ETMIDR]); | ||
403 | |||
404 | /* How much space was used */ | ||
405 | increment = CS_ETM_PRIV_MAX; | ||
406 | } | ||
407 | |||
408 | /* Build generic header portion */ | ||
409 | info->priv[*offset + CS_ETM_MAGIC] = magic; | ||
410 | info->priv[*offset + CS_ETM_CPU] = cpu; | ||
411 | /* Where the next CPU entry should start from */ | ||
412 | *offset += increment; | ||
413 | } | ||
414 | |||
415 | static int cs_etm_info_fill(struct auxtrace_record *itr, | ||
416 | struct perf_session *session, | ||
417 | struct auxtrace_info_event *info, | ||
418 | size_t priv_size) | ||
419 | { | ||
420 | int i; | ||
421 | u32 offset; | ||
422 | u64 nr_cpu, type; | ||
423 | const struct cpu_map *cpus = session->evlist->cpus; | ||
424 | struct cs_etm_recording *ptr = | ||
425 | container_of(itr, struct cs_etm_recording, itr); | ||
426 | struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; | ||
427 | |||
428 | if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) | ||
429 | return -EINVAL; | ||
430 | |||
431 | if (!session->evlist->nr_mmaps) | ||
432 | return -EINVAL; | ||
433 | |||
434 | /* If the cpu_map is empty all CPUs are involved */ | ||
435 | nr_cpu = cpu_map__empty(cpus) ? cpu__max_cpu() : cpu_map__nr(cpus); | ||
436 | /* Get PMU type as dynamically assigned by the core */ | ||
437 | type = cs_etm_pmu->type; | ||
438 | |||
439 | /* First fill out the session header */ | ||
440 | info->type = PERF_AUXTRACE_CS_ETM; | ||
441 | info->priv[CS_HEADER_VERSION_0] = 0; | ||
442 | info->priv[CS_PMU_TYPE_CPUS] = type << 32; | ||
443 | info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; | ||
444 | info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; | ||
445 | |||
446 | offset = CS_ETM_SNAPSHOT + 1; | ||
447 | |||
448 | /* cpu map is not empty, we have specific CPUs to work with */ | ||
449 | if (!cpu_map__empty(cpus)) { | ||
450 | for (i = 0; i < cpu_map__nr(cpus) && offset < priv_size; i++) | ||
451 | cs_etm_get_metadata(cpus->map[i], &offset, itr, info); | ||
452 | } else { | ||
453 | /* get configuration for all CPUs in the system */ | ||
454 | for (i = 0; i < cpu__max_cpu(); i++) | ||
455 | cs_etm_get_metadata(i, &offset, itr, info); | ||
456 | } | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused, | ||
462 | int idx, struct auxtrace_mmap *mm, | ||
463 | unsigned char *data __maybe_unused, | ||
464 | u64 *head, u64 *old) | ||
465 | { | ||
466 | pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", | ||
467 | __func__, idx, (size_t)*old, (size_t)*head, mm->len); | ||
468 | |||
469 | *old = *head; | ||
470 | *head += mm->len; | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int cs_etm_snapshot_start(struct auxtrace_record *itr) | ||
476 | { | ||
477 | struct cs_etm_recording *ptr = | ||
478 | container_of(itr, struct cs_etm_recording, itr); | ||
479 | struct perf_evsel *evsel; | ||
480 | |||
481 | evlist__for_each_entry(ptr->evlist, evsel) { | ||
482 | if (evsel->attr.type == ptr->cs_etm_pmu->type) | ||
483 | return perf_evsel__disable(evsel); | ||
484 | } | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | |||
488 | static int cs_etm_snapshot_finish(struct auxtrace_record *itr) | ||
489 | { | ||
490 | struct cs_etm_recording *ptr = | ||
491 | container_of(itr, struct cs_etm_recording, itr); | ||
492 | struct perf_evsel *evsel; | ||
493 | |||
494 | evlist__for_each_entry(ptr->evlist, evsel) { | ||
495 | if (evsel->attr.type == ptr->cs_etm_pmu->type) | ||
496 | return perf_evsel__enable(evsel); | ||
497 | } | ||
498 | return -EINVAL; | ||
499 | } | ||
500 | |||
501 | static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) | ||
502 | { | ||
503 | return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | | ||
504 | (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); | ||
505 | } | ||
506 | |||
507 | static void cs_etm_recording_free(struct auxtrace_record *itr) | ||
508 | { | ||
509 | struct cs_etm_recording *ptr = | ||
510 | container_of(itr, struct cs_etm_recording, itr); | ||
511 | free(ptr); | ||
512 | } | ||
513 | |||
514 | static int cs_etm_read_finish(struct auxtrace_record *itr, int idx) | ||
515 | { | ||
516 | struct cs_etm_recording *ptr = | ||
517 | container_of(itr, struct cs_etm_recording, itr); | ||
518 | struct perf_evsel *evsel; | ||
519 | |||
520 | evlist__for_each_entry(ptr->evlist, evsel) { | ||
521 | if (evsel->attr.type == ptr->cs_etm_pmu->type) | ||
522 | return perf_evlist__enable_event_idx(ptr->evlist, | ||
523 | evsel, idx); | ||
524 | } | ||
525 | |||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | struct auxtrace_record *cs_etm_record_init(int *err) | ||
530 | { | ||
531 | struct perf_pmu *cs_etm_pmu; | ||
532 | struct cs_etm_recording *ptr; | ||
533 | |||
534 | cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); | ||
535 | |||
536 | if (!cs_etm_pmu) { | ||
537 | *err = -EINVAL; | ||
538 | goto out; | ||
539 | } | ||
540 | |||
541 | ptr = zalloc(sizeof(struct cs_etm_recording)); | ||
542 | if (!ptr) { | ||
543 | *err = -ENOMEM; | ||
544 | goto out; | ||
545 | } | ||
546 | |||
547 | ptr->cs_etm_pmu = cs_etm_pmu; | ||
548 | ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; | ||
549 | ptr->itr.recording_options = cs_etm_recording_options; | ||
550 | ptr->itr.info_priv_size = cs_etm_info_priv_size; | ||
551 | ptr->itr.info_fill = cs_etm_info_fill; | ||
552 | ptr->itr.find_snapshot = cs_etm_find_snapshot; | ||
553 | ptr->itr.snapshot_start = cs_etm_snapshot_start; | ||
554 | ptr->itr.snapshot_finish = cs_etm_snapshot_finish; | ||
555 | ptr->itr.reference = cs_etm_reference; | ||
556 | ptr->itr.free = cs_etm_recording_free; | ||
557 | ptr->itr.read_finish = cs_etm_read_finish; | ||
558 | |||
559 | *err = 0; | ||
560 | return &ptr->itr; | ||
561 | out: | ||
562 | return NULL; | ||
563 | } | ||
564 | |||
565 | static FILE *cs_device__open_file(const char *name) | ||
566 | { | ||
567 | struct stat st; | ||
568 | char path[PATH_MAX]; | ||
569 | const char *sysfs; | ||
570 | |||
571 | sysfs = sysfs__mountpoint(); | ||
572 | if (!sysfs) | ||
573 | return NULL; | ||
574 | |||
575 | snprintf(path, PATH_MAX, | ||
576 | "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name); | ||
577 | |||
578 | printf("path: %s\n", path); | ||
579 | |||
580 | if (stat(path, &st) < 0) | ||
581 | return NULL; | ||
582 | |||
583 | return fopen(path, "w"); | ||
584 | |||
585 | } | ||
586 | |||
587 | static __attribute__((format(printf, 2, 3))) | ||
588 | int cs_device__print_file(const char *name, const char *fmt, ...) | ||
589 | { | ||
590 | va_list args; | ||
591 | FILE *file; | ||
592 | int ret = -EINVAL; | ||
593 | |||
594 | va_start(args, fmt); | ||
595 | file = cs_device__open_file(name); | ||
596 | if (file) { | ||
597 | ret = vfprintf(file, fmt, args); | ||
598 | fclose(file); | ||
599 | } | ||
600 | va_end(args); | ||
601 | return ret; | ||
602 | } | ||
603 | |||
604 | int cs_etm_set_drv_config(struct perf_evsel_config_term *term) | ||
605 | { | ||
606 | int ret; | ||
607 | char enable_sink[ENABLE_SINK_MAX]; | ||
608 | |||
609 | snprintf(enable_sink, ENABLE_SINK_MAX, "%s/%s", | ||
610 | term->val.drv_cfg, "enable_sink"); | ||
611 | |||
612 | ret = cs_device__print_file(enable_sink, "%d", 1); | ||
613 | if (ret < 0) | ||
614 | return ret; | ||
615 | |||
616 | return 0; | ||
617 | } | ||
diff --git a/tools/perf/arch/arm/util/cs-etm.h b/tools/perf/arch/arm/util/cs-etm.h new file mode 100644 index 000000000000..5256741be549 --- /dev/null +++ b/tools/perf/arch/arm/util/cs-etm.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | ||
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef INCLUDE__PERF_CS_ETM_H__ | ||
19 | #define INCLUDE__PERF_CS_ETM_H__ | ||
20 | |||
21 | #include "../../util/evsel.h" | ||
22 | |||
23 | struct auxtrace_record *cs_etm_record_init(int *err); | ||
24 | int cs_etm_set_drv_config(struct perf_evsel_config_term *term); | ||
25 | |||
26 | #endif | ||
diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c new file mode 100644 index 000000000000..98d67399a0d6 --- /dev/null +++ b/tools/perf/arch/arm/util/pmu.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | ||
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <string.h> | ||
19 | #include <linux/coresight-pmu.h> | ||
20 | #include <linux/perf_event.h> | ||
21 | |||
22 | #include "cs-etm.h" | ||
23 | #include "../../util/pmu.h" | ||
24 | |||
25 | struct perf_event_attr | ||
26 | *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) | ||
27 | { | ||
28 | #ifdef HAVE_AUXTRACE_SUPPORT | ||
29 | if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) { | ||
30 | /* add ETM default config here */ | ||
31 | pmu->selectable = true; | ||
32 | pmu->set_drv_config = cs_etm_set_drv_config; | ||
33 | } | ||
34 | #endif | ||
35 | return NULL; | ||
36 | } | ||
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index 02f41dba4f4f..cef6fb38d17e 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build | |||
@@ -1,2 +1,6 @@ | |||
1 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 1 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
2 | libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o | 2 | libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o |
3 | |||
4 | libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \ | ||
5 | ../../arm/util/auxtrace.o \ | ||
6 | ../../arm/util/cs-etm.o | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 03251c7f14ec..2d0d69be3bf8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "util/evlist.h" | 22 | #include "util/evlist.h" |
23 | #include "util/evsel.h" | 23 | #include "util/evsel.h" |
24 | #include "util/debug.h" | 24 | #include "util/debug.h" |
25 | #include "util/drv_configs.h" | ||
25 | #include "util/session.h" | 26 | #include "util/session.h" |
26 | #include "util/tool.h" | 27 | #include "util/tool.h" |
27 | #include "util/symbol.h" | 28 | #include "util/symbol.h" |
@@ -383,6 +384,7 @@ static int record__open(struct record *rec) | |||
383 | struct perf_evlist *evlist = rec->evlist; | 384 | struct perf_evlist *evlist = rec->evlist; |
384 | struct perf_session *session = rec->session; | 385 | struct perf_session *session = rec->session; |
385 | struct record_opts *opts = &rec->opts; | 386 | struct record_opts *opts = &rec->opts; |
387 | struct perf_evsel_config_term *err_term; | ||
386 | int rc = 0; | 388 | int rc = 0; |
387 | 389 | ||
388 | perf_evlist__config(evlist, opts, &callchain_param); | 390 | perf_evlist__config(evlist, opts, &callchain_param); |
@@ -412,6 +414,14 @@ try_again: | |||
412 | goto out; | 414 | goto out; |
413 | } | 415 | } |
414 | 416 | ||
417 | if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) { | ||
418 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | ||
419 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, | ||
420 | str_error_r(errno, msg, sizeof(msg))); | ||
421 | rc = -1; | ||
422 | goto out; | ||
423 | } | ||
424 | |||
415 | rc = record__mmap(rec); | 425 | rc = record__mmap(rec); |
416 | if (rc) | 426 | if (rc) |
417 | goto out; | 427 | goto out; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 90882b1d6a91..688dea7cb08f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include "util/evlist.h" | 52 | #include "util/evlist.h" |
53 | #include "util/evsel.h" | 53 | #include "util/evsel.h" |
54 | #include "util/debug.h" | 54 | #include "util/debug.h" |
55 | #include "util/drv_configs.h" | ||
55 | #include "util/color.h" | 56 | #include "util/color.h" |
56 | #include "util/stat.h" | 57 | #include "util/stat.h" |
57 | #include "util/header.h" | 58 | #include "util/header.h" |
@@ -540,6 +541,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
540 | int status = 0; | 541 | int status = 0; |
541 | const bool forks = (argc > 0); | 542 | const bool forks = (argc > 0); |
542 | bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false; | 543 | bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false; |
544 | struct perf_evsel_config_term *err_term; | ||
543 | 545 | ||
544 | if (interval) { | 546 | if (interval) { |
545 | ts.tv_sec = interval / USEC_PER_MSEC; | 547 | ts.tv_sec = interval / USEC_PER_MSEC; |
@@ -611,6 +613,13 @@ try_again: | |||
611 | return -1; | 613 | return -1; |
612 | } | 614 | } |
613 | 615 | ||
616 | if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { | ||
617 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | ||
618 | err_term->val.drv_cfg, perf_evsel__name(counter), errno, | ||
619 | str_error_r(errno, msg, sizeof(msg))); | ||
620 | return -1; | ||
621 | } | ||
622 | |||
614 | if (STAT_RECORD) { | 623 | if (STAT_RECORD) { |
615 | int err, fd = perf_data_file__fd(&perf_stat.file); | 624 | int err, fd = perf_data_file__fd(&perf_stat.file); |
616 | 625 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 400785702566..fe3af9535e85 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "util/annotate.h" | 24 | #include "util/annotate.h" |
25 | #include "util/config.h" | 25 | #include "util/config.h" |
26 | #include "util/color.h" | 26 | #include "util/color.h" |
27 | #include "util/drv_configs.h" | ||
27 | #include "util/evlist.h" | 28 | #include "util/evlist.h" |
28 | #include "util/evsel.h" | 29 | #include "util/evsel.h" |
29 | #include "util/machine.h" | 30 | #include "util/machine.h" |
@@ -913,6 +914,10 @@ static int callchain_param__setup_sample_type(struct callchain_param *callchain) | |||
913 | 914 | ||
914 | static int __cmd_top(struct perf_top *top) | 915 | static int __cmd_top(struct perf_top *top) |
915 | { | 916 | { |
917 | char msg[512]; | ||
918 | struct perf_evsel *pos; | ||
919 | struct perf_evsel_config_term *err_term; | ||
920 | struct perf_evlist *evlist = top->evlist; | ||
916 | struct record_opts *opts = &top->record_opts; | 921 | struct record_opts *opts = &top->record_opts; |
917 | pthread_t thread; | 922 | pthread_t thread; |
918 | int ret; | 923 | int ret; |
@@ -947,6 +952,14 @@ static int __cmd_top(struct perf_top *top) | |||
947 | if (ret) | 952 | if (ret) |
948 | goto out_delete; | 953 | goto out_delete; |
949 | 954 | ||
955 | ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term); | ||
956 | if (ret) { | ||
957 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | ||
958 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, | ||
959 | str_error_r(errno, msg, sizeof(msg))); | ||
960 | goto out_delete; | ||
961 | } | ||
962 | |||
950 | top->session->evlist = top->evlist; | 963 | top->session->evlist = top->evlist; |
951 | perf_session__set_id_hdr_size(top->session); | 964 | perf_session__set_id_hdr_size(top->session); |
952 | 965 | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a6d5d248b8fb..fb8e42c7507a 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1080,7 +1080,7 @@ struct hpp_arg { | |||
1080 | bool current_entry; | 1080 | bool current_entry; |
1081 | }; | 1081 | }; |
1082 | 1082 | ||
1083 | static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) | 1083 | int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) |
1084 | { | 1084 | { |
1085 | struct hpp_arg *arg = hpp->ptr; | 1085 | struct hpp_arg *arg = hpp->ptr; |
1086 | int ret, len; | 1086 | int ret, len; |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 60c4a4d08374..37388397b5bc 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -237,7 +237,7 @@ static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | |||
237 | return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); | 237 | return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); |
238 | } | 238 | } |
239 | 239 | ||
240 | static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) | 240 | int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) |
241 | { | 241 | { |
242 | va_list args; | 242 | va_list args; |
243 | ssize_t ssize = hpp->size; | 243 | ssize_t ssize = hpp->size; |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 8e1840bff29d..89d8441f9890 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -373,7 +373,8 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, | |||
373 | return 0; | 373 | return 0; |
374 | } | 374 | } |
375 | 375 | ||
376 | static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) | 376 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, |
377 | struct perf_hpp_list *hpp_list) | ||
377 | { | 378 | { |
378 | const char *sep = symbol_conf.field_sep; | 379 | const char *sep = symbol_conf.field_sep; |
379 | struct perf_hpp_fmt *fmt; | 380 | struct perf_hpp_fmt *fmt; |
@@ -384,7 +385,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) | |||
384 | if (symbol_conf.exclude_other && !he->parent) | 385 | if (symbol_conf.exclude_other && !he->parent) |
385 | return 0; | 386 | return 0; |
386 | 387 | ||
387 | hists__for_each_format(he->hists, fmt) { | 388 | perf_hpp_list__for_each_format(hpp_list, fmt) { |
388 | if (perf_hpp__should_skip(fmt, he->hists)) | 389 | if (perf_hpp__should_skip(fmt, he->hists)) |
389 | continue; | 390 | continue; |
390 | 391 | ||
@@ -410,6 +411,11 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) | |||
410 | return hpp->buf - start; | 411 | return hpp->buf - start; |
411 | } | 412 | } |
412 | 413 | ||
414 | static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) | ||
415 | { | ||
416 | return __hist_entry__snprintf(he, hpp, he->hists->hpp_list); | ||
417 | } | ||
418 | |||
413 | static int hist_entry__hierarchy_fprintf(struct hist_entry *he, | 419 | static int hist_entry__hierarchy_fprintf(struct hist_entry *he, |
414 | struct perf_hpp *hpp, | 420 | struct perf_hpp *hpp, |
415 | struct hists *hists, | 421 | struct hists *hists, |
@@ -696,9 +702,9 @@ hists__fprintf_standard_headers(struct hists *hists, | |||
696 | return hpp_list->nr_header_lines + 2; | 702 | return hpp_list->nr_header_lines + 2; |
697 | } | 703 | } |
698 | 704 | ||
699 | static int hists__fprintf_headers(struct hists *hists, FILE *fp) | 705 | int hists__fprintf_headers(struct hists *hists, FILE *fp) |
700 | { | 706 | { |
701 | char bf[96]; | 707 | char bf[1024]; |
702 | struct perf_hpp dummy_hpp = { | 708 | struct perf_hpp dummy_hpp = { |
703 | .buf = bf, | 709 | .buf = bf, |
704 | .size = sizeof(bf), | 710 | .size = sizeof(bf), |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 96f99d608d00..eb60e613d795 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -86,6 +86,7 @@ libperf-y += term.o | |||
86 | libperf-y += help-unknown-cmd.o | 86 | libperf-y += help-unknown-cmd.o |
87 | libperf-y += mem-events.o | 87 | libperf-y += mem-events.o |
88 | libperf-y += vsprintf.o | 88 | libperf-y += vsprintf.o |
89 | libperf-y += drv_configs.o | ||
89 | 90 | ||
90 | libperf-$(CONFIG_LIBBPF) += bpf-loader.o | 91 | libperf-$(CONFIG_LIBBPF) += bpf-loader.o |
91 | libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o | 92 | libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index c9169011e55e..c0aba8e839aa 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -892,6 +892,7 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, | |||
892 | return intel_pt_process_auxtrace_info(event, session); | 892 | return intel_pt_process_auxtrace_info(event, session); |
893 | case PERF_AUXTRACE_INTEL_BTS: | 893 | case PERF_AUXTRACE_INTEL_BTS: |
894 | return intel_bts_process_auxtrace_info(event, session); | 894 | return intel_bts_process_auxtrace_info(event, session); |
895 | case PERF_AUXTRACE_CS_ETM: | ||
895 | case PERF_AUXTRACE_UNKNOWN: | 896 | case PERF_AUXTRACE_UNKNOWN: |
896 | default: | 897 | default: |
897 | return -EINVAL; | 898 | return -EINVAL; |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index ac5f0d7167e6..09286f193532 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -41,6 +41,7 @@ enum auxtrace_type { | |||
41 | PERF_AUXTRACE_UNKNOWN, | 41 | PERF_AUXTRACE_UNKNOWN, |
42 | PERF_AUXTRACE_INTEL_PT, | 42 | PERF_AUXTRACE_INTEL_PT, |
43 | PERF_AUXTRACE_INTEL_BTS, | 43 | PERF_AUXTRACE_INTEL_BTS, |
44 | PERF_AUXTRACE_CS_ETM, | ||
44 | }; | 45 | }; |
45 | 46 | ||
46 | enum itrace_period_type { | 47 | enum itrace_period_type { |
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h new file mode 100644 index 000000000000..3cc6bc3263fe --- /dev/null +++ b/tools/perf/util/cs-etm.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | ||
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef INCLUDE__UTIL_PERF_CS_ETM_H__ | ||
19 | #define INCLUDE__UTIL_PERF_CS_ETM_H__ | ||
20 | |||
21 | /* Versionning header in case things need tro change in the future. That way | ||
22 | * decoding of old snapshot is still possible. | ||
23 | */ | ||
24 | enum { | ||
25 | /* Starting with 0x0 */ | ||
26 | CS_HEADER_VERSION_0, | ||
27 | /* PMU->type (32 bit), total # of CPUs (32 bit) */ | ||
28 | CS_PMU_TYPE_CPUS, | ||
29 | CS_ETM_SNAPSHOT, | ||
30 | CS_HEADER_VERSION_0_MAX, | ||
31 | }; | ||
32 | |||
33 | /* Beginning of header common to both ETMv3 and V4 */ | ||
34 | enum { | ||
35 | CS_ETM_MAGIC, | ||
36 | CS_ETM_CPU, | ||
37 | }; | ||
38 | |||
39 | /* ETMv3/PTM metadata */ | ||
40 | enum { | ||
41 | /* Dynamic, configurable parameters */ | ||
42 | CS_ETM_ETMCR = CS_ETM_CPU + 1, | ||
43 | CS_ETM_ETMTRACEIDR, | ||
44 | /* RO, taken from sysFS */ | ||
45 | CS_ETM_ETMCCER, | ||
46 | CS_ETM_ETMIDR, | ||
47 | CS_ETM_PRIV_MAX, | ||
48 | }; | ||
49 | |||
50 | /* ETMv4 metadata */ | ||
51 | enum { | ||
52 | /* Dynamic, configurable parameters */ | ||
53 | CS_ETMV4_TRCCONFIGR = CS_ETM_CPU + 1, | ||
54 | CS_ETMV4_TRCTRACEIDR, | ||
55 | /* RO, taken from sysFS */ | ||
56 | CS_ETMV4_TRCIDR0, | ||
57 | CS_ETMV4_TRCIDR1, | ||
58 | CS_ETMV4_TRCIDR2, | ||
59 | CS_ETMV4_TRCIDR8, | ||
60 | CS_ETMV4_TRCAUTHSTATUS, | ||
61 | CS_ETMV4_PRIV_MAX, | ||
62 | }; | ||
63 | |||
64 | #define KiB(x) ((x) * 1024) | ||
65 | #define MiB(x) ((x) * 1024 * 1024) | ||
66 | |||
67 | #define CS_ETM_HEADER_SIZE (CS_HEADER_VERSION_0_MAX * sizeof(u64)) | ||
68 | |||
69 | static const u64 __perf_cs_etmv3_magic = 0x3030303030303030ULL; | ||
70 | static const u64 __perf_cs_etmv4_magic = 0x4040404040404040ULL; | ||
71 | #define CS_ETMV3_PRIV_SIZE (CS_ETM_PRIV_MAX * sizeof(u64)) | ||
72 | #define CS_ETMV4_PRIV_SIZE (CS_ETMV4_PRIV_MAX * sizeof(u64)) | ||
73 | |||
74 | #endif | ||
diff --git a/tools/perf/util/drv_configs.c b/tools/perf/util/drv_configs.c new file mode 100644 index 000000000000..1647f285c629 --- /dev/null +++ b/tools/perf/util/drv_configs.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * drv_configs.h: Interface to apply PMU specific configuration | ||
3 | * Copyright (c) 2016-2018, Linaro Ltd. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include "drv_configs.h" | ||
17 | #include "evlist.h" | ||
18 | #include "evsel.h" | ||
19 | #include "pmu.h" | ||
20 | |||
21 | static int | ||
22 | perf_evsel__apply_drv_configs(struct perf_evsel *evsel, | ||
23 | struct perf_evsel_config_term **err_term) | ||
24 | { | ||
25 | bool found = false; | ||
26 | int err = 0; | ||
27 | struct perf_evsel_config_term *term; | ||
28 | struct perf_pmu *pmu = NULL; | ||
29 | |||
30 | while ((pmu = perf_pmu__scan(pmu)) != NULL) | ||
31 | if (pmu->type == evsel->attr.type) { | ||
32 | found = true; | ||
33 | break; | ||
34 | } | ||
35 | |||
36 | list_for_each_entry(term, &evsel->config_terms, list) { | ||
37 | if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG) | ||
38 | continue; | ||
39 | |||
40 | /* | ||
41 | * We have a configuration term, report an error if we | ||
42 | * can't find the PMU or if the PMU driver doesn't support | ||
43 | * cmd line driver configuration. | ||
44 | */ | ||
45 | if (!found || !pmu->set_drv_config) { | ||
46 | err = -EINVAL; | ||
47 | *err_term = term; | ||
48 | break; | ||
49 | } | ||
50 | |||
51 | err = pmu->set_drv_config(term); | ||
52 | if (err) { | ||
53 | *err_term = term; | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | return err; | ||
59 | } | ||
60 | |||
61 | int perf_evlist__apply_drv_configs(struct perf_evlist *evlist, | ||
62 | struct perf_evsel **err_evsel, | ||
63 | struct perf_evsel_config_term **err_term) | ||
64 | { | ||
65 | struct perf_evsel *evsel; | ||
66 | int err = 0; | ||
67 | |||
68 | evlist__for_each_entry(evlist, evsel) { | ||
69 | err = perf_evsel__apply_drv_configs(evsel, err_term); | ||
70 | if (err) { | ||
71 | *err_evsel = evsel; | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | return err; | ||
77 | } | ||
diff --git a/tools/perf/util/drv_configs.h b/tools/perf/util/drv_configs.h new file mode 100644 index 000000000000..32bc9babc2e0 --- /dev/null +++ b/tools/perf/util/drv_configs.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * drv_configs.h: Interface to apply PMU specific configuration | ||
3 | * Copyright (c) 2016-2018, Linaro Ltd. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #ifndef __PERF_DRV_CONFIGS_H | ||
17 | #define __PERF_DRV_CONFIGS_H | ||
18 | |||
19 | #include "drv_configs.h" | ||
20 | #include "evlist.h" | ||
21 | #include "evsel.h" | ||
22 | |||
23 | int perf_evlist__apply_drv_configs(struct perf_evlist *evlist, | ||
24 | struct perf_evsel **err_evsel, | ||
25 | struct perf_evsel_config_term **term); | ||
26 | #endif | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 21fd573106ed..f3225a2e6eee 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1728,7 +1728,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1728 | data->cpu = data->pid = data->tid = -1; | 1728 | data->cpu = data->pid = data->tid = -1; |
1729 | data->stream_id = data->id = data->time = -1ULL; | 1729 | data->stream_id = data->id = data->time = -1ULL; |
1730 | data->period = evsel->attr.sample_period; | 1730 | data->period = evsel->attr.sample_period; |
1731 | data->weight = 0; | ||
1732 | data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1731 | data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
1733 | 1732 | ||
1734 | if (event->header.type != PERF_RECORD_SAMPLE) { | 1733 | if (event->header.type != PERF_RECORD_SAMPLE) { |
@@ -1935,7 +1934,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1935 | } | 1934 | } |
1936 | } | 1935 | } |
1937 | 1936 | ||
1938 | data->weight = 0; | ||
1939 | if (type & PERF_SAMPLE_WEIGHT) { | 1937 | if (type & PERF_SAMPLE_WEIGHT) { |
1940 | OVERFLOW_CHECK_u64(array); | 1938 | OVERFLOW_CHECK_u64(array); |
1941 | data->weight = *array; | 1939 | data->weight = *array; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index defa957f27df..9928fed8bc59 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -485,5 +485,10 @@ static inline struct rb_node *rb_hierarchy_next(struct rb_node *node) | |||
485 | #define HIERARCHY_INDENT 3 | 485 | #define HIERARCHY_INDENT 3 |
486 | 486 | ||
487 | bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit); | 487 | bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit); |
488 | int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...); | ||
489 | int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...); | ||
490 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, | ||
491 | struct perf_hpp_list *hpp_list); | ||
492 | int hists__fprintf_headers(struct hists *hists, FILE *fp); | ||
488 | 493 | ||
489 | #endif /* __PERF_HIST_H */ | 494 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 5d7e84466bee..743422ad900b 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/bitmap.h> | 4 | #include <linux/bitmap.h> |
5 | #include <linux/perf_event.h> | 5 | #include <linux/perf_event.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include "evsel.h" | ||
7 | #include "parse-events.h" | 8 | #include "parse-events.h" |
8 | 9 | ||
9 | enum { | 10 | enum { |
@@ -25,6 +26,7 @@ struct perf_pmu { | |||
25 | struct list_head format; /* HEAD struct perf_pmu_format -> list */ | 26 | struct list_head format; /* HEAD struct perf_pmu_format -> list */ |
26 | struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ | 27 | struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ |
27 | struct list_head list; /* ELEM */ | 28 | struct list_head list; /* ELEM */ |
29 | int (*set_drv_config) (struct perf_evsel_config_term *term); | ||
28 | }; | 30 | }; |
29 | 31 | ||
30 | struct perf_pmu_info { | 32 | struct perf_pmu_info { |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 1884d7f9b9d2..452e15a10dd2 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -867,7 +867,7 @@ struct sort_entry sort_cycles = { | |||
867 | }; | 867 | }; |
868 | 868 | ||
869 | /* --sort daddr_sym */ | 869 | /* --sort daddr_sym */ |
870 | static int64_t | 870 | int64_t |
871 | sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) | 871 | sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) |
872 | { | 872 | { |
873 | uint64_t l = 0, r = 0; | 873 | uint64_t l = 0, r = 0; |
@@ -896,7 +896,7 @@ static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf, | |||
896 | width); | 896 | width); |
897 | } | 897 | } |
898 | 898 | ||
899 | static int64_t | 899 | int64_t |
900 | sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right) | 900 | sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right) |
901 | { | 901 | { |
902 | uint64_t l = 0, r = 0; | 902 | uint64_t l = 0, r = 0; |
@@ -1062,7 +1062,7 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, | |||
1062 | return repsep_snprintf(bf, size, "%-*s", width, out); | 1062 | return repsep_snprintf(bf, size, "%-*s", width, out); |
1063 | } | 1063 | } |
1064 | 1064 | ||
1065 | static int64_t | 1065 | int64_t |
1066 | sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) | 1066 | sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) |
1067 | { | 1067 | { |
1068 | u64 l, r; | 1068 | u64 l, r; |
@@ -2308,9 +2308,9 @@ int hpp_dimension__add_output(unsigned col) | |||
2308 | return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]); | 2308 | return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]); |
2309 | } | 2309 | } |
2310 | 2310 | ||
2311 | static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | 2311 | int sort_dimension__add(struct perf_hpp_list *list, const char *tok, |
2312 | struct perf_evlist *evlist, | 2312 | struct perf_evlist *evlist, |
2313 | int level) | 2313 | int level) |
2314 | { | 2314 | { |
2315 | unsigned int i; | 2315 | unsigned int i; |
2316 | 2316 | ||
@@ -2685,7 +2685,7 @@ void sort__setup_elide(FILE *output) | |||
2685 | } | 2685 | } |
2686 | } | 2686 | } |
2687 | 2687 | ||
2688 | static int output_field_add(struct perf_hpp_list *list, char *tok) | 2688 | int output_field_add(struct perf_hpp_list *list, char *tok) |
2689 | { | 2689 | { |
2690 | unsigned int i; | 2690 | unsigned int i; |
2691 | 2691 | ||
@@ -2748,7 +2748,7 @@ static int setup_output_list(struct perf_hpp_list *list, char *str) | |||
2748 | return ret; | 2748 | return ret; |
2749 | } | 2749 | } |
2750 | 2750 | ||
2751 | static void reset_dimensions(void) | 2751 | void reset_dimensions(void) |
2752 | { | 2752 | { |
2753 | unsigned int i; | 2753 | unsigned int i; |
2754 | 2754 | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 9505483cb95c..099c97557d33 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -269,4 +269,15 @@ int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, i | |||
269 | bool is_strict_order(const char *order); | 269 | bool is_strict_order(const char *order); |
270 | 270 | ||
271 | int hpp_dimension__add_output(unsigned col); | 271 | int hpp_dimension__add_output(unsigned col); |
272 | void reset_dimensions(void); | ||
273 | int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | ||
274 | struct perf_evlist *evlist, | ||
275 | int level); | ||
276 | int output_field_add(struct perf_hpp_list *list, char *tok); | ||
277 | int64_t | ||
278 | sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right); | ||
279 | int64_t | ||
280 | sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right); | ||
281 | int64_t | ||
282 | sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right); | ||
272 | #endif /* __PERF_SORT_H */ | 283 | #endif /* __PERF_SORT_H */ |