diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-07-01 02:40:39 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-07-01 02:40:39 -0400 |
commit | dc29bb47a34130459fadd58f05e2acd051a6327d (patch) | |
tree | 16e36c1b28e054b765b8f104ca9debbcf10de99e | |
parent | d905768c9e1addfa35d9731dbaa9242e8991f6ac (diff) | |
parent | a24020e6b7cf6eb8b75d8bca6b89870b1cee6ba7 (diff) |
Merge tag 'perf-core-for-mingo-20160630' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New features:
- Allow running 'perf test' entries in the same process, not forking to
test each testcase, useful for debugging (Jiri Olsa)
- Show number of samples in the stdio annotate header (Peter Zijlstra)
Documentation changes:
- Add documentation for perf.data on disk format (Andi Kleen)
Build fixes:
- Fix 'perf trace' build on old systems wrt missing SCHED_RESET_ON_FORK and
eventfd.h (Arnaldo Carvalho de Melo)
Infrastructure changes:
- Utility function to fetch arch from evsel/evlist (Ravi Bangoria)
Trivial changes:
- Fix spelling mistake: "missmatch" -> "mismatch" in libbpf (Colin Ian King)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/lib/bpf/libbpf.c | 2 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 2 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-test.txt | 4 | ||||
-rw-r--r-- | tools/perf/Documentation/perf.data-file-format.txt | 442 | ||||
-rw-r--r-- | tools/perf/tests/builtin-test.c | 59 | ||||
-rw-r--r-- | tools/perf/tests/cpumap.c | 24 | ||||
-rw-r--r-- | tools/perf/tests/dso-data.c | 6 | ||||
-rw-r--r-- | tools/perf/tests/tests.h | 1 | ||||
-rw-r--r-- | tools/perf/tests/thread-map.c | 16 | ||||
-rw-r--r-- | tools/perf/trace/beauty/eventfd.c | 2 | ||||
-rw-r--r-- | tools/perf/trace/beauty/sched_policy.c | 3 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 12 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 54 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 1 | ||||
-rw-r--r-- | tools/perf/util/dso.c | 22 | ||||
-rw-r--r-- | tools/perf/util/dso.h | 2 | ||||
-rw-r--r-- | tools/perf/util/event.c | 2 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 7 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 2 |
19 files changed, 614 insertions, 49 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 462e526a4465..a7cb40abe634 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -71,7 +71,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = { | |||
71 | [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", | 71 | [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", |
72 | [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", | 72 | [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", |
73 | [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", | 73 | [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", |
74 | [ERRCODE_OFFSET(ENDIAN)] = "Endian missmatch", | 74 | [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch", |
75 | [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", | 75 | [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", |
76 | [ERRCODE_OFFSET(RELOC)] = "Relocation failed", | 76 | [ERRCODE_OFFSET(RELOC)] = "Relocation failed", |
77 | [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", | 77 | [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", |
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 722f46b2d553..148df3640ba0 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h | |||
@@ -19,7 +19,7 @@ enum libbpf_errno { | |||
19 | LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START, | 19 | LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START, |
20 | LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */ | 20 | LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */ |
21 | LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */ | 21 | LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */ |
22 | LIBBPF_ERRNO__ENDIAN, /* Endian missmatch */ | 22 | LIBBPF_ERRNO__ENDIAN, /* Endian mismatch */ |
23 | LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */ | 23 | LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */ |
24 | LIBBPF_ERRNO__RELOC, /* Relocation failed */ | 24 | LIBBPF_ERRNO__RELOC, /* Relocation failed */ |
25 | LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */ | 25 | LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */ |
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 31a5c3ea7f74..b329c65d7f40 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt | |||
@@ -30,3 +30,7 @@ OPTIONS | |||
30 | -v:: | 30 | -v:: |
31 | --verbose:: | 31 | --verbose:: |
32 | Be more verbose. | 32 | Be more verbose. |
33 | |||
34 | -F:: | ||
35 | --dont-fork:: | ||
36 | Do not fork child for each test, run all tests within single process. | ||
diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt new file mode 100644 index 000000000000..fdc99fe6bbc3 --- /dev/null +++ b/tools/perf/Documentation/perf.data-file-format.txt | |||
@@ -0,0 +1,442 @@ | |||
1 | perf.data format | ||
2 | |||
3 | Uptodate as of v4.7 | ||
4 | |||
5 | This document describes the on-disk perf.data format, generated by perf record | ||
6 | or perf inject and consumed by the other perf tools. | ||
7 | |||
8 | On a high level perf.data contains the events generated by the PMUs, plus metadata. | ||
9 | |||
10 | All fields are in native-endian of the machine that generated the perf.data. | ||
11 | |||
12 | When perf is writing to a pipe it uses a special version of the file | ||
13 | format that does not rely on seeking to adjust data offsets. This | ||
14 | format is not described here. The pipe version can be converted to | ||
15 | normal perf.data with perf inject. | ||
16 | |||
17 | The file starts with a perf_header: | ||
18 | |||
19 | struct perf_header { | ||
20 | char magic[8]; /* PERFILE2 */ | ||
21 | uint64_t size; /* size of the header */ | ||
22 | uint64_t attr_size; /* size of an attribute in attrs */ | ||
23 | struct perf_file_section attrs; | ||
24 | struct perf_file_section data; | ||
25 | struct perf_file_section event_types; | ||
26 | uint64_t flags; | ||
27 | uint64_t flags1[3]; | ||
28 | }; | ||
29 | |||
30 | The magic number identifies the perf file and the version. Current perf versions | ||
31 | use PERFILE2. Old perf versions generated a version 1 format (PERFFILE). Version 1 | ||
32 | is not described here. The magic number also identifies the endian. When the | ||
33 | magic value is 64bit byte swapped compared the file is in non-native | ||
34 | endian. | ||
35 | |||
36 | A perf_file_section contains a pointer to another section of the perf file. | ||
37 | The header contains three such pointers: for attributes, data and event types. | ||
38 | |||
39 | struct perf_file_section { | ||
40 | uint64_t offset; /* offset from start of file */ | ||
41 | uint64_t size; /* size of the section */ | ||
42 | }; | ||
43 | |||
44 | Flags section: | ||
45 | |||
46 | The header is followed by different optional headers, described by the bits set | ||
47 | in flags. Only headers for which the bit is set are included. Each header | ||
48 | consists of a perf_file_section located after the initial header. | ||
49 | The respective perf_file_section points to the data of the additional | ||
50 | header and defines its size. | ||
51 | |||
52 | Some headers consist of strings, which are defined like this: | ||
53 | |||
54 | struct perf_header_string { | ||
55 | uint32_t len; | ||
56 | char string[len]; /* zero terminated */ | ||
57 | }; | ||
58 | |||
59 | Some headers consist of a sequence of strings, which start with a | ||
60 | |||
61 | struct perf_header_string_list { | ||
62 | uint32_t nr; | ||
63 | struct perf_header_string strings[nr]; /* variable length records */ | ||
64 | }; | ||
65 | |||
66 | The bits are the flags bits in a 256 bit bitmap starting with | ||
67 | flags. These define the valid bits: | ||
68 | |||
69 | HEADER_RESERVED = 0, /* always cleared */ | ||
70 | HEADER_FIRST_FEATURE = 1, | ||
71 | HEADER_TRACING_DATA = 1, | ||
72 | |||
73 | Describe me. | ||
74 | |||
75 | HEADER_BUILD_ID = 2, | ||
76 | |||
77 | The header consists of an sequence of build_id_event. The size of each record | ||
78 | is defined by header.size (see perf_event.h). Each event defines a ELF build id | ||
79 | for a executable file name for a pid. An ELF build id is a unique identifier | ||
80 | assigned by the linker to an executable. | ||
81 | |||
82 | struct build_id_event { | ||
83 | struct perf_event_header header; | ||
84 | pid_t pid; | ||
85 | uint8_t build_id[24]; | ||
86 | char filename[header.size - offsetof(struct build_id_event, filename)]; | ||
87 | }; | ||
88 | |||
89 | HEADER_HOSTNAME = 3, | ||
90 | |||
91 | A perf_header_string with the hostname where the data was collected | ||
92 | (uname -n) | ||
93 | |||
94 | HEADER_OSRELEASE = 4, | ||
95 | |||
96 | A perf_header_string with the os release where the data was collected | ||
97 | (uname -r) | ||
98 | |||
99 | HEADER_VERSION = 5, | ||
100 | |||
101 | A perf_header_string with the perf user tool version where the | ||
102 | data was collected. This is the same as the version of the source tree | ||
103 | the perf tool was built from. | ||
104 | |||
105 | HEADER_ARCH = 6, | ||
106 | |||
107 | A perf_header_string with the CPU architecture (uname -m) | ||
108 | |||
109 | HEADER_NRCPUS = 7, | ||
110 | |||
111 | A structure defining the number of CPUs. | ||
112 | |||
113 | struct nr_cpus { | ||
114 | uint32_t nr_cpus_online; | ||
115 | uint32_t nr_cpus_available; /* CPUs not yet onlined */ | ||
116 | }; | ||
117 | |||
118 | HEADER_CPUDESC = 8, | ||
119 | |||
120 | A perf_header_string with description of the CPU. On x86 this is the model name | ||
121 | in /proc/cpuinfo | ||
122 | |||
123 | HEADER_CPUID = 9, | ||
124 | |||
125 | A perf_header_string with the exact CPU type. On x86 this is | ||
126 | vendor,family,model,stepping. For example: GenuineIntel,6,69,1 | ||
127 | |||
128 | HEADER_TOTAL_MEM = 10, | ||
129 | |||
130 | An uint64_t with the total memory in bytes. | ||
131 | |||
132 | HEADER_CMDLINE = 11, | ||
133 | |||
134 | A perf_header_string with the perf command line used to collect the data. | ||
135 | |||
136 | HEADER_EVENT_DESC = 12, | ||
137 | |||
138 | Another description of the perf_event_attrs, more detailed than header.attrs | ||
139 | including IDs and names. See perf_event.h or the man page for a description | ||
140 | of a struct perf_event_attr. | ||
141 | |||
142 | struct { | ||
143 | uint32_t nr; /* number of events */ | ||
144 | uint32_t attr_size; /* size of each perf_event_attr */ | ||
145 | struct { | ||
146 | struct perf_event_attr attr; /* size of attr_size */ | ||
147 | uint32_t nr_ids; | ||
148 | struct perf_header_string event_string; | ||
149 | uint64_t ids[nr_ids]; | ||
150 | } events[nr]; /* Variable length records */ | ||
151 | }; | ||
152 | |||
153 | HEADER_CPU_TOPOLOGY = 13, | ||
154 | |||
155 | String lists defining the core and CPU threads topology. | ||
156 | |||
157 | struct { | ||
158 | struct perf_header_string_list cores; /* Variable length */ | ||
159 | struct perf_header_string_list threads; /* Variable length */ | ||
160 | }; | ||
161 | |||
162 | Example: | ||
163 | sibling cores : 0-3 | ||
164 | sibling threads : 0-1 | ||
165 | sibling threads : 2-3 | ||
166 | |||
167 | HEADER_NUMA_TOPOLOGY = 14, | ||
168 | |||
169 | A list of NUMA node descriptions | ||
170 | |||
171 | struct { | ||
172 | uint32_t nr; | ||
173 | struct { | ||
174 | uint32_t nodenr; | ||
175 | uint64_t mem_total; | ||
176 | uint64_t mem_free; | ||
177 | struct perf_header_string cpus; | ||
178 | } nodes[nr]; /* Variable length records */ | ||
179 | }; | ||
180 | |||
181 | HEADER_BRANCH_STACK = 15, | ||
182 | |||
183 | Not implemented in perf. | ||
184 | |||
185 | HEADER_PMU_MAPPINGS = 16, | ||
186 | |||
187 | A list of PMU structures, defining the different PMUs supported by perf. | ||
188 | |||
189 | struct { | ||
190 | uint32_t nr; | ||
191 | struct pmu { | ||
192 | uint32_t pmu_type; | ||
193 | struct perf_header_string pmu_name; | ||
194 | } [nr]; /* Variable length records */ | ||
195 | }; | ||
196 | |||
197 | HEADER_GROUP_DESC = 17, | ||
198 | |||
199 | Description of counter groups ({...} in perf syntax) | ||
200 | |||
201 | struct { | ||
202 | uint32_t nr; | ||
203 | struct { | ||
204 | struct perf_header_string string; | ||
205 | uint32_t leader_idx; | ||
206 | uint32_t nr_members; | ||
207 | } [nr]; /* Variable length records */ | ||
208 | }; | ||
209 | |||
210 | HEADER_AUXTRACE = 18, | ||
211 | |||
212 | Define additional auxtrace areas in the perf.data. auxtrace is used to store | ||
213 | undecoded hardware tracing information, such as Intel Processor Trace data. | ||
214 | |||
215 | /** | ||
216 | * struct auxtrace_index_entry - indexes a AUX area tracing event within a | ||
217 | * perf.data file. | ||
218 | * @file_offset: offset within the perf.data file | ||
219 | * @sz: size of the event | ||
220 | */ | ||
221 | struct auxtrace_index_entry { | ||
222 | u64 file_offset; | ||
223 | u64 sz; | ||
224 | }; | ||
225 | |||
226 | #define PERF_AUXTRACE_INDEX_ENTRY_COUNT 256 | ||
227 | |||
228 | /** | ||
229 | * struct auxtrace_index - index of AUX area tracing events within a perf.data | ||
230 | * file. | ||
231 | * @list: linking a number of arrays of entries | ||
232 | * @nr: number of entries | ||
233 | * @entries: array of entries | ||
234 | */ | ||
235 | struct auxtrace_index { | ||
236 | struct list_head list; | ||
237 | size_t nr; | ||
238 | struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT]; | ||
239 | }; | ||
240 | |||
241 | other bits are reserved and should ignored for now | ||
242 | HEADER_FEAT_BITS = 256, | ||
243 | |||
244 | Attributes | ||
245 | |||
246 | This is an array of perf_event_attrs, each attr_size bytes long, which defines | ||
247 | each event collected. See perf_event.h or the man page for a detailed | ||
248 | description. | ||
249 | |||
250 | Data | ||
251 | |||
252 | This section is the bulk of the file. It consist of a stream of perf_events | ||
253 | describing events. This matches the format generated by the kernel. | ||
254 | See perf_event.h or the manpage for a detailed description. | ||
255 | |||
256 | Some notes on parsing: | ||
257 | |||
258 | Ordering | ||
259 | |||
260 | The events are not necessarily in time stamp order, as they can be | ||
261 | collected in parallel on different CPUs. If the events should be | ||
262 | processed in time order they need to be sorted first. It is possible | ||
263 | to only do a partial sort using the FINISHED_ROUND event header (see | ||
264 | below). perf record guarantees that there is no reordering over a | ||
265 | FINISHED_ROUND. | ||
266 | |||
267 | ID vs IDENTIFIER | ||
268 | |||
269 | When the event stream contains multiple events each event is identified | ||
270 | by an ID. This can be either through the PERF_SAMPLE_ID or the | ||
271 | PERF_SAMPLE_IDENTIFIER header. The PERF_SAMPLE_IDENTIFIER header is | ||
272 | at a fixed offset from the event header, which allows reliable | ||
273 | parsing of the header. Relying on ID may be ambigious. | ||
274 | IDENTIFIER is only supported by newer Linux kernels. | ||
275 | |||
276 | Perf record specific events: | ||
277 | |||
278 | In addition to the kernel generated event types perf record adds its | ||
279 | own event types (in addition it also synthesizes some kernel events, | ||
280 | for example MMAP events) | ||
281 | |||
282 | PERF_RECORD_USER_TYPE_START = 64, | ||
283 | PERF_RECORD_HEADER_ATTR = 64, | ||
284 | |||
285 | struct attr_event { | ||
286 | struct perf_event_header header; | ||
287 | struct perf_event_attr attr; | ||
288 | uint64_t id[]; | ||
289 | }; | ||
290 | |||
291 | PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */ | ||
292 | |||
293 | #define MAX_EVENT_NAME 64 | ||
294 | |||
295 | struct perf_trace_event_type { | ||
296 | uint64_t event_id; | ||
297 | char name[MAX_EVENT_NAME]; | ||
298 | }; | ||
299 | |||
300 | struct event_type_event { | ||
301 | struct perf_event_header header; | ||
302 | struct perf_trace_event_type event_type; | ||
303 | }; | ||
304 | |||
305 | |||
306 | PERF_RECORD_HEADER_TRACING_DATA = 66, | ||
307 | |||
308 | Describe me | ||
309 | |||
310 | struct tracing_data_event { | ||
311 | struct perf_event_header header; | ||
312 | uint32_t size; | ||
313 | }; | ||
314 | |||
315 | PERF_RECORD_HEADER_BUILD_ID = 67, | ||
316 | |||
317 | Define a ELF build ID for a referenced executable. | ||
318 | |||
319 | struct build_id_event; /* See above */ | ||
320 | |||
321 | PERF_RECORD_FINISHED_ROUND = 68, | ||
322 | |||
323 | No event reordering over this header. No payload. | ||
324 | |||
325 | PERF_RECORD_ID_INDEX = 69, | ||
326 | |||
327 | Map event ids to CPUs and TIDs. | ||
328 | |||
329 | struct id_index_entry { | ||
330 | uint64_t id; | ||
331 | uint64_t idx; | ||
332 | uint64_t cpu; | ||
333 | uint64_t tid; | ||
334 | }; | ||
335 | |||
336 | struct id_index_event { | ||
337 | struct perf_event_header header; | ||
338 | uint64_t nr; | ||
339 | struct id_index_entry entries[nr]; | ||
340 | }; | ||
341 | |||
342 | PERF_RECORD_AUXTRACE_INFO = 70, | ||
343 | |||
344 | Auxtrace type specific information. Describe me | ||
345 | |||
346 | struct auxtrace_info_event { | ||
347 | struct perf_event_header header; | ||
348 | uint32_t type; | ||
349 | uint32_t reserved__; /* For alignment */ | ||
350 | uint64_t priv[]; | ||
351 | }; | ||
352 | |||
353 | PERF_RECORD_AUXTRACE = 71, | ||
354 | |||
355 | Defines auxtrace data. Followed by the actual data. The contents of | ||
356 | the auxtrace data is dependent on the event and the CPU. For example | ||
357 | for Intel Processor Trace it contains Processor Trace data generated | ||
358 | by the CPU. | ||
359 | |||
360 | struct auxtrace_event { | ||
361 | struct perf_event_header header; | ||
362 | uint64_t size; | ||
363 | uint64_t offset; | ||
364 | uint64_t reference; | ||
365 | uint32_t idx; | ||
366 | uint32_t tid; | ||
367 | uint32_t cpu; | ||
368 | uint32_t reserved__; /* For alignment */ | ||
369 | }; | ||
370 | |||
371 | struct aux_event { | ||
372 | struct perf_event_header header; | ||
373 | uint64_t aux_offset; | ||
374 | uint64_t aux_size; | ||
375 | uint64_t flags; | ||
376 | }; | ||
377 | |||
378 | PERF_RECORD_AUXTRACE_ERROR = 72, | ||
379 | |||
380 | Describes an error in hardware tracing | ||
381 | |||
382 | enum auxtrace_error_type { | ||
383 | PERF_AUXTRACE_ERROR_ITRACE = 1, | ||
384 | PERF_AUXTRACE_ERROR_MAX | ||
385 | }; | ||
386 | |||
387 | #define MAX_AUXTRACE_ERROR_MSG 64 | ||
388 | |||
389 | struct auxtrace_error_event { | ||
390 | struct perf_event_header header; | ||
391 | uint32_t type; | ||
392 | uint32_t code; | ||
393 | uint32_t cpu; | ||
394 | uint32_t pid; | ||
395 | uint32_t tid; | ||
396 | uint32_t reserved__; /* For alignment */ | ||
397 | uint64_t ip; | ||
398 | char msg[MAX_AUXTRACE_ERROR_MSG]; | ||
399 | }; | ||
400 | |||
401 | Event types | ||
402 | |||
403 | Define the event attributes with their IDs. | ||
404 | |||
405 | An array bound by the perf_file_section size. | ||
406 | |||
407 | struct { | ||
408 | struct perf_event_attr attr; /* Size defined by header.attr_size */ | ||
409 | struct perf_file_section ids; | ||
410 | } | ||
411 | |||
412 | ids points to a array of uint64_t defining the ids for event attr attr. | ||
413 | |||
414 | References: | ||
415 | |||
416 | include/uapi/linux/perf_event.h | ||
417 | |||
418 | This is the canonical description of the kernel generated perf_events | ||
419 | and the perf_event_attrs. | ||
420 | |||
421 | perf_events manpage | ||
422 | |||
423 | A manpage describing perf_event and perf_event_attr is here: | ||
424 | http://web.eece.maine.edu/~vweaver/projects/perf_events/programming.html | ||
425 | This tends to be slightly behind the kernel include, but has better | ||
426 | descriptions. An (typically older) version of the man page may be | ||
427 | included with the standard Linux man pages, available with "man | ||
428 | perf_events" | ||
429 | |||
430 | pmu-tools | ||
431 | |||
432 | https://github.com/andikleen/pmu-tools/tree/master/parser | ||
433 | |||
434 | A definition of the perf.data format in python "construct" format is available | ||
435 | in pmu-tools parser. This allows to read perf.data from python and dump it. | ||
436 | |||
437 | quipper | ||
438 | |||
439 | The quipper C++ parser is available at | ||
440 | https://chromium.googlesource.com/chromiumos/platform/chromiumos-wide-profiling/ | ||
441 | Unfortunately this parser tends to be many versions behind and may not be able | ||
442 | to parse data files generated by recent perf. | ||
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 0e95c20ecf6e..07c14e9f6546 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <subcmd/parse-options.h> | 14 | #include <subcmd/parse-options.h> |
15 | #include "symbol.h" | 15 | #include "symbol.h" |
16 | 16 | ||
17 | static bool dont_fork; | ||
18 | |||
17 | struct test __weak arch_tests[] = { | 19 | struct test __weak arch_tests[] = { |
18 | { | 20 | { |
19 | .func = NULL, | 21 | .func = NULL, |
@@ -212,6 +214,10 @@ static struct test generic_tests[] = { | |||
212 | .func = test__backward_ring_buffer, | 214 | .func = test__backward_ring_buffer, |
213 | }, | 215 | }, |
214 | { | 216 | { |
217 | .desc = "Test cpu map print", | ||
218 | .func = test__cpu_map_print, | ||
219 | }, | ||
220 | { | ||
215 | .func = NULL, | 221 | .func = NULL, |
216 | }, | 222 | }, |
217 | }; | 223 | }; |
@@ -247,7 +253,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char | |||
247 | 253 | ||
248 | static int run_test(struct test *test, int subtest) | 254 | static int run_test(struct test *test, int subtest) |
249 | { | 255 | { |
250 | int status, err = -1, child = fork(); | 256 | int status, err = -1, child = dont_fork ? 0 : fork(); |
251 | char sbuf[STRERR_BUFSIZE]; | 257 | char sbuf[STRERR_BUFSIZE]; |
252 | 258 | ||
253 | if (child < 0) { | 259 | if (child < 0) { |
@@ -257,34 +263,41 @@ static int run_test(struct test *test, int subtest) | |||
257 | } | 263 | } |
258 | 264 | ||
259 | if (!child) { | 265 | if (!child) { |
260 | pr_debug("test child forked, pid %d\n", getpid()); | 266 | if (!dont_fork) { |
261 | if (!verbose) { | 267 | pr_debug("test child forked, pid %d\n", getpid()); |
262 | int nullfd = open("/dev/null", O_WRONLY); | 268 | |
263 | if (nullfd >= 0) { | 269 | if (!verbose) { |
264 | close(STDERR_FILENO); | 270 | int nullfd = open("/dev/null", O_WRONLY); |
265 | close(STDOUT_FILENO); | 271 | |
266 | 272 | if (nullfd >= 0) { | |
267 | dup2(nullfd, STDOUT_FILENO); | 273 | close(STDERR_FILENO); |
268 | dup2(STDOUT_FILENO, STDERR_FILENO); | 274 | close(STDOUT_FILENO); |
269 | close(nullfd); | 275 | |
276 | dup2(nullfd, STDOUT_FILENO); | ||
277 | dup2(STDOUT_FILENO, STDERR_FILENO); | ||
278 | close(nullfd); | ||
279 | } | ||
280 | } else { | ||
281 | signal(SIGSEGV, sighandler_dump_stack); | ||
282 | signal(SIGFPE, sighandler_dump_stack); | ||
270 | } | 283 | } |
271 | } else { | ||
272 | signal(SIGSEGV, sighandler_dump_stack); | ||
273 | signal(SIGFPE, sighandler_dump_stack); | ||
274 | } | 284 | } |
275 | 285 | ||
276 | err = test->func(subtest); | 286 | err = test->func(subtest); |
277 | exit(err); | 287 | if (!dont_fork) |
288 | exit(err); | ||
278 | } | 289 | } |
279 | 290 | ||
280 | wait(&status); | 291 | if (!dont_fork) { |
292 | wait(&status); | ||
281 | 293 | ||
282 | if (WIFEXITED(status)) { | 294 | if (WIFEXITED(status)) { |
283 | err = (signed char)WEXITSTATUS(status); | 295 | err = (signed char)WEXITSTATUS(status); |
284 | pr_debug("test child finished with %d\n", err); | 296 | pr_debug("test child finished with %d\n", err); |
285 | } else if (WIFSIGNALED(status)) { | 297 | } else if (WIFSIGNALED(status)) { |
286 | err = -1; | 298 | err = -1; |
287 | pr_debug("test child interrupted\n"); | 299 | pr_debug("test child interrupted\n"); |
300 | } | ||
288 | } | 301 | } |
289 | 302 | ||
290 | return err; | 303 | return err; |
@@ -425,6 +438,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) | |||
425 | OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), | 438 | OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), |
426 | OPT_INCR('v', "verbose", &verbose, | 439 | OPT_INCR('v', "verbose", &verbose, |
427 | "be more verbose (show symbol address, etc)"), | 440 | "be more verbose (show symbol address, etc)"), |
441 | OPT_BOOLEAN('F', "dont-fork", &dont_fork, | ||
442 | "Do not fork for testcase"), | ||
428 | OPT_END() | 443 | OPT_END() |
429 | }; | 444 | }; |
430 | const char * const test_subcommands[] = { "list", NULL }; | 445 | const char * const test_subcommands[] = { "list", NULL }; |
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 4cb6418a8ffc..c9ec5f83e42c 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c | |||
@@ -86,3 +86,27 @@ int test__cpu_map_synthesize(int subtest __maybe_unused) | |||
86 | cpu_map__put(cpus); | 86 | cpu_map__put(cpus); |
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | |||
90 | static int cpu_map_print(const char *str) | ||
91 | { | ||
92 | struct cpu_map *map = cpu_map__new(str); | ||
93 | char buf[100]; | ||
94 | |||
95 | if (!map) | ||
96 | return -1; | ||
97 | |||
98 | cpu_map__snprint(map, buf, sizeof(buf)); | ||
99 | return !strcmp(buf, str); | ||
100 | } | ||
101 | |||
102 | int test__cpu_map_print(int subtest __maybe_unused) | ||
103 | { | ||
104 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1")); | ||
105 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,5")); | ||
106 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3,5,7,9,11,13,15,17,19,21-40")); | ||
107 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("2-5")); | ||
108 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37")); | ||
109 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37")); | ||
110 | TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1-10,12-20,22-30,32-40")); | ||
111 | return 0; | ||
112 | } | ||
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 8cf0d9e189a8..13725e09ba22 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -251,6 +251,9 @@ int test__dso_data_cache(int subtest __maybe_unused) | |||
251 | long nr_end, nr = open_files_cnt(); | 251 | long nr_end, nr = open_files_cnt(); |
252 | int dso_cnt, limit, i, fd; | 252 | int dso_cnt, limit, i, fd; |
253 | 253 | ||
254 | /* Rest the internal dso open counter limit. */ | ||
255 | reset_fd_limit(); | ||
256 | |||
254 | memset(&machine, 0, sizeof(machine)); | 257 | memset(&machine, 0, sizeof(machine)); |
255 | 258 | ||
256 | /* set as system limit */ | 259 | /* set as system limit */ |
@@ -312,6 +315,9 @@ int test__dso_data_reopen(int subtest __maybe_unused) | |||
312 | #define dso_1 (dsos[1]) | 315 | #define dso_1 (dsos[1]) |
313 | #define dso_2 (dsos[2]) | 316 | #define dso_2 (dsos[2]) |
314 | 317 | ||
318 | /* Rest the internal dso open counter limit. */ | ||
319 | reset_fd_limit(); | ||
320 | |||
315 | memset(&machine, 0, sizeof(machine)); | 321 | memset(&machine, 0, sizeof(machine)); |
316 | 322 | ||
317 | /* | 323 | /* |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index c57e72c826d2..52f969570c97 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -87,6 +87,7 @@ int test__synthesize_stat_round(int subtest); | |||
87 | int test__event_update(int subtest); | 87 | int test__event_update(int subtest); |
88 | int test__event_times(int subtest); | 88 | int test__event_times(int subtest); |
89 | int test__backward_ring_buffer(int subtest); | 89 | int test__backward_ring_buffer(int subtest); |
90 | int test__cpu_map_print(int subtest); | ||
90 | 91 | ||
91 | #if defined(__arm__) || defined(__aarch64__) | 92 | #if defined(__arm__) || defined(__aarch64__) |
92 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 93 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c index fccde848fe9c..cee2a2cdc933 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c | |||
@@ -1,13 +1,20 @@ | |||
1 | #include <sys/types.h> | 1 | #include <sys/types.h> |
2 | #include <unistd.h> | 2 | #include <unistd.h> |
3 | #include <sys/prctl.h> | ||
3 | #include "tests.h" | 4 | #include "tests.h" |
4 | #include "thread_map.h" | 5 | #include "thread_map.h" |
5 | #include "debug.h" | 6 | #include "debug.h" |
6 | 7 | ||
8 | #define NAME (const char *) "perf" | ||
9 | #define NAMEUL (unsigned long) NAME | ||
10 | |||
7 | int test__thread_map(int subtest __maybe_unused) | 11 | int test__thread_map(int subtest __maybe_unused) |
8 | { | 12 | { |
9 | struct thread_map *map; | 13 | struct thread_map *map; |
10 | 14 | ||
15 | TEST_ASSERT_VAL("failed to set process name", | ||
16 | !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0)); | ||
17 | |||
11 | /* test map on current pid */ | 18 | /* test map on current pid */ |
12 | map = thread_map__new_by_pid(getpid()); | 19 | map = thread_map__new_by_pid(getpid()); |
13 | TEST_ASSERT_VAL("failed to alloc map", map); | 20 | TEST_ASSERT_VAL("failed to alloc map", map); |
@@ -19,7 +26,7 @@ int test__thread_map(int subtest __maybe_unused) | |||
19 | thread_map__pid(map, 0) == getpid()); | 26 | thread_map__pid(map, 0) == getpid()); |
20 | TEST_ASSERT_VAL("wrong comm", | 27 | TEST_ASSERT_VAL("wrong comm", |
21 | thread_map__comm(map, 0) && | 28 | thread_map__comm(map, 0) && |
22 | !strcmp(thread_map__comm(map, 0), "perf")); | 29 | !strcmp(thread_map__comm(map, 0), NAME)); |
23 | TEST_ASSERT_VAL("wrong refcnt", | 30 | TEST_ASSERT_VAL("wrong refcnt", |
24 | atomic_read(&map->refcnt) == 1); | 31 | atomic_read(&map->refcnt) == 1); |
25 | thread_map__put(map); | 32 | thread_map__put(map); |
@@ -51,7 +58,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, | |||
51 | 58 | ||
52 | TEST_ASSERT_VAL("wrong nr", map->nr == 1); | 59 | TEST_ASSERT_VAL("wrong nr", map->nr == 1); |
53 | TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid()); | 60 | TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid()); |
54 | TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf")); | 61 | TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, NAME)); |
55 | 62 | ||
56 | threads = thread_map__new_event(&event->thread_map); | 63 | threads = thread_map__new_event(&event->thread_map); |
57 | TEST_ASSERT_VAL("failed to alloc map", threads); | 64 | TEST_ASSERT_VAL("failed to alloc map", threads); |
@@ -61,7 +68,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, | |||
61 | thread_map__pid(threads, 0) == getpid()); | 68 | thread_map__pid(threads, 0) == getpid()); |
62 | TEST_ASSERT_VAL("wrong comm", | 69 | TEST_ASSERT_VAL("wrong comm", |
63 | thread_map__comm(threads, 0) && | 70 | thread_map__comm(threads, 0) && |
64 | !strcmp(thread_map__comm(threads, 0), "perf")); | 71 | !strcmp(thread_map__comm(threads, 0), NAME)); |
65 | TEST_ASSERT_VAL("wrong refcnt", | 72 | TEST_ASSERT_VAL("wrong refcnt", |
66 | atomic_read(&threads->refcnt) == 1); | 73 | atomic_read(&threads->refcnt) == 1); |
67 | thread_map__put(threads); | 74 | thread_map__put(threads); |
@@ -72,6 +79,9 @@ int test__thread_map_synthesize(int subtest __maybe_unused) | |||
72 | { | 79 | { |
73 | struct thread_map *threads; | 80 | struct thread_map *threads; |
74 | 81 | ||
82 | TEST_ASSERT_VAL("failed to set process name", | ||
83 | !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0)); | ||
84 | |||
75 | /* test map on current pid */ | 85 | /* test map on current pid */ |
76 | threads = thread_map__new_by_pid(getpid()); | 86 | threads = thread_map__new_by_pid(getpid()); |
77 | TEST_ASSERT_VAL("failed to alloc map", threads); | 87 | TEST_ASSERT_VAL("failed to alloc map", threads); |
diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c index d64f4a9128a1..b08f21eb6f4d 100644 --- a/tools/perf/trace/beauty/eventfd.c +++ b/tools/perf/trace/beauty/eventfd.c | |||
@@ -1,5 +1,3 @@ | |||
1 | #include <sys/eventfd.h> | ||
2 | |||
3 | #ifndef EFD_SEMAPHORE | 1 | #ifndef EFD_SEMAPHORE |
4 | #define EFD_SEMAPHORE 1 | 2 | #define EFD_SEMAPHORE 1 |
5 | #endif | 3 | #endif |
diff --git a/tools/perf/trace/beauty/sched_policy.c b/tools/perf/trace/beauty/sched_policy.c index c205bc608b3c..34775295b9b3 100644 --- a/tools/perf/trace/beauty/sched_policy.c +++ b/tools/perf/trace/beauty/sched_policy.c | |||
@@ -9,6 +9,9 @@ | |||
9 | #ifndef SCHED_DEADLINE | 9 | #ifndef SCHED_DEADLINE |
10 | #define SCHED_DEADLINE 6 | 10 | #define SCHED_DEADLINE 6 |
11 | #endif | 11 | #endif |
12 | #ifndef SCHED_RESET_ON_FORK | ||
13 | #define SCHED_RESET_ON_FORK 0x40000000 | ||
14 | #endif | ||
12 | 15 | ||
13 | static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, | 16 | static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, |
14 | struct syscall_arg *arg) | 17 | struct syscall_arg *arg) |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index c385fecb9d32..e9825fe825fd 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -1522,13 +1522,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
1522 | const char *d_filename; | 1522 | const char *d_filename; |
1523 | const char *evsel_name = perf_evsel__name(evsel); | 1523 | const char *evsel_name = perf_evsel__name(evsel); |
1524 | struct annotation *notes = symbol__annotation(sym); | 1524 | struct annotation *notes = symbol__annotation(sym); |
1525 | struct sym_hist *h = annotation__histogram(notes, evsel->idx); | ||
1525 | struct disasm_line *pos, *queue = NULL; | 1526 | struct disasm_line *pos, *queue = NULL; |
1526 | u64 start = map__rip_2objdump(map, sym->start); | 1527 | u64 start = map__rip_2objdump(map, sym->start); |
1527 | int printed = 2, queue_len = 0; | 1528 | int printed = 2, queue_len = 0; |
1528 | int more = 0; | 1529 | int more = 0; |
1529 | u64 len; | 1530 | u64 len; |
1530 | int width = 8; | 1531 | int width = 8; |
1531 | int namelen, evsel_name_len, graph_dotted_len; | 1532 | int graph_dotted_len; |
1532 | 1533 | ||
1533 | filename = strdup(dso->long_name); | 1534 | filename = strdup(dso->long_name); |
1534 | if (!filename) | 1535 | if (!filename) |
@@ -1540,17 +1541,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
1540 | d_filename = basename(filename); | 1541 | d_filename = basename(filename); |
1541 | 1542 | ||
1542 | len = symbol__size(sym); | 1543 | len = symbol__size(sym); |
1543 | namelen = strlen(d_filename); | ||
1544 | evsel_name_len = strlen(evsel_name); | ||
1545 | 1544 | ||
1546 | if (perf_evsel__is_group_event(evsel)) | 1545 | if (perf_evsel__is_group_event(evsel)) |
1547 | width *= evsel->nr_members; | 1546 | width *= evsel->nr_members; |
1548 | 1547 | ||
1549 | printf(" %-*.*s| Source code & Disassembly of %s for %s\n", | 1548 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", |
1550 | width, width, "Percent", d_filename, evsel_name); | 1549 | width, width, "Percent", d_filename, evsel_name, h->sum); |
1551 | 1550 | ||
1552 | graph_dotted_len = width + namelen + evsel_name_len; | 1551 | printf("%-*.*s----\n", |
1553 | printf("-%-*.*s-----------------------------------------\n", | ||
1554 | graph_dotted_len, graph_dotted_len, graph_dotted_line); | 1552 | graph_dotted_len, graph_dotted_len, graph_dotted_line); |
1555 | 1553 | ||
1556 | if (verbose) | 1554 | if (verbose) |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 02d801670f30..15f83acac1b8 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -236,13 +236,12 @@ struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) | |||
236 | 236 | ||
237 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) | 237 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) |
238 | { | 238 | { |
239 | int i; | 239 | #define BUFSIZE 1024 |
240 | size_t printed = fprintf(fp, "%d cpu%s: ", | 240 | char buf[BUFSIZE]; |
241 | map->nr, map->nr > 1 ? "s" : ""); | ||
242 | for (i = 0; i < map->nr; ++i) | ||
243 | printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]); | ||
244 | 241 | ||
245 | return printed + fprintf(fp, "\n"); | 242 | cpu_map__snprint(map, buf, sizeof(buf)); |
243 | return fprintf(fp, "%s\n", buf); | ||
244 | #undef BUFSIZE | ||
246 | } | 245 | } |
247 | 246 | ||
248 | struct cpu_map *cpu_map__dummy_new(void) | 247 | struct cpu_map *cpu_map__dummy_new(void) |
@@ -599,3 +598,46 @@ bool cpu_map__has(struct cpu_map *cpus, int cpu) | |||
599 | 598 | ||
600 | return false; | 599 | return false; |
601 | } | 600 | } |
601 | |||
602 | size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size) | ||
603 | { | ||
604 | int i, cpu, start = -1; | ||
605 | bool first = true; | ||
606 | size_t ret = 0; | ||
607 | |||
608 | #define COMMA first ? "" : "," | ||
609 | |||
610 | for (i = 0; i < map->nr + 1; i++) { | ||
611 | bool last = i == map->nr; | ||
612 | |||
613 | cpu = last ? INT_MAX : map->map[i]; | ||
614 | |||
615 | if (start == -1) { | ||
616 | start = i; | ||
617 | if (last) { | ||
618 | ret += snprintf(buf + ret, size - ret, | ||
619 | "%s%d", COMMA, | ||
620 | map->map[i]); | ||
621 | } | ||
622 | } else if (((i - start) != (cpu - map->map[start])) || last) { | ||
623 | int end = i - 1; | ||
624 | |||
625 | if (start == end) { | ||
626 | ret += snprintf(buf + ret, size - ret, | ||
627 | "%s%d", COMMA, | ||
628 | map->map[start]); | ||
629 | } else { | ||
630 | ret += snprintf(buf + ret, size - ret, | ||
631 | "%s%d-%d", COMMA, | ||
632 | map->map[start], map->map[end]); | ||
633 | } | ||
634 | first = false; | ||
635 | start = i; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | #undef COMMA | ||
640 | |||
641 | pr_debug("cpumask list: %s\n", buf); | ||
642 | return ret; | ||
643 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 1a0a35073ce1..206dc550354a 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -19,6 +19,7 @@ struct cpu_map *cpu_map__empty_new(int nr); | |||
19 | struct cpu_map *cpu_map__dummy_new(void); | 19 | struct cpu_map *cpu_map__dummy_new(void); |
20 | struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); | 20 | struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); |
21 | struct cpu_map *cpu_map__read(FILE *file); | 21 | struct cpu_map *cpu_map__read(FILE *file); |
22 | size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size); | ||
22 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 23 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
23 | int cpu_map__get_socket_id(int cpu); | 24 | int cpu_map__get_socket_id(int cpu); |
24 | int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); | 25 | int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 5d286f5d7906..e1de6cc4863e 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -442,17 +442,27 @@ static rlim_t get_fd_limit(void) | |||
442 | return limit; | 442 | return limit; |
443 | } | 443 | } |
444 | 444 | ||
445 | static bool may_cache_fd(void) | 445 | static rlim_t fd_limit; |
446 | |||
447 | /* | ||
448 | * Used only by tests/dso-data.c to reset the environment | ||
449 | * for tests. I dont expect we should change this during | ||
450 | * standard runtime. | ||
451 | */ | ||
452 | void reset_fd_limit(void) | ||
446 | { | 453 | { |
447 | static rlim_t limit; | 454 | fd_limit = 0; |
455 | } | ||
448 | 456 | ||
449 | if (!limit) | 457 | static bool may_cache_fd(void) |
450 | limit = get_fd_limit(); | 458 | { |
459 | if (!fd_limit) | ||
460 | fd_limit = get_fd_limit(); | ||
451 | 461 | ||
452 | if (limit == RLIM_INFINITY) | 462 | if (fd_limit == RLIM_INFINITY) |
453 | return true; | 463 | return true; |
454 | 464 | ||
455 | return limit > (rlim_t) dso__data_open_cnt; | 465 | return fd_limit > (rlim_t) dso__data_open_cnt; |
456 | } | 466 | } |
457 | 467 | ||
458 | /* | 468 | /* |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 76d79d070e21..a571f24895ca 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -360,4 +360,6 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine); | |||
360 | 360 | ||
361 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen); | 361 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen); |
362 | 362 | ||
363 | void reset_fd_limit(void); | ||
364 | |||
363 | #endif /* __PERF_DSO */ | 365 | #endif /* __PERF_DSO */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9b141f12329e..e20438b784be 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -1092,7 +1092,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) | |||
1092 | struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); | 1092 | struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); |
1093 | size_t ret; | 1093 | size_t ret; |
1094 | 1094 | ||
1095 | ret = fprintf(fp, " nr: "); | 1095 | ret = fprintf(fp, ": "); |
1096 | 1096 | ||
1097 | if (cpus) | 1097 | if (cpus) |
1098 | ret += cpu_map__fprintf(cpus, fp); | 1098 | ret += cpu_map__fprintf(cpus, fp); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1d8f2bbd38a7..0fea724e735c 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -2422,3 +2422,10 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2422 | err, strerror_r(err, sbuf, sizeof(sbuf)), | 2422 | err, strerror_r(err, sbuf, sizeof(sbuf)), |
2423 | perf_evsel__name(evsel)); | 2423 | perf_evsel__name(evsel)); |
2424 | } | 2424 | } |
2425 | |||
2426 | char *perf_evsel__env_arch(struct perf_evsel *evsel) | ||
2427 | { | ||
2428 | if (evsel && evsel->evlist && evsel->evlist->env) | ||
2429 | return evsel->evlist->env->arch; | ||
2430 | return NULL; | ||
2431 | } | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 828ddd1c8947..86fed7a2932b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -435,4 +435,6 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); | |||
435 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | 435 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, |
436 | attr__fprintf_f attr__fprintf, void *priv); | 436 | attr__fprintf_f attr__fprintf, void *priv); |
437 | 437 | ||
438 | char *perf_evsel__env_arch(struct perf_evsel *evsel); | ||
439 | |||
438 | #endif /* __PERF_EVSEL_H */ | 440 | #endif /* __PERF_EVSEL_H */ |