diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-23 19:49:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-23 19:49:12 -0500 |
commit | 00198dab3b825ab264424a052beea5acb859754f (patch) | |
tree | 1afa5fc96a0447bc8049a9992e5d4d047f5f0b38 /tools | |
parent | 9004fda59577d439564d44d6d1db52d262fe3f99 (diff) | |
parent | 3705b97505bcbf6440f38119c0e7d6058f585b54 (diff) |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Ingo Molnar:
"On the kernel side there's two x86 PMU driver fixes and a uprobes fix,
plus on the tooling side there's a number of fixes and some late
updates"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (36 commits)
perf sched timehist: Fix invalid period calculation
perf sched timehist: Remove hardcoded 'comm_width' check at print_summary
perf sched timehist: Enlarge default 'comm_width'
perf sched timehist: Honour 'comm_width' when aligning the headers
perf/x86: Fix overlap counter scheduling bug
perf/x86/pebs: Fix handling of PEBS buffer overflows
samples/bpf: Move open_raw_sock to separate header
samples/bpf: Remove perf_event_open() declaration
samples/bpf: Be consistent with bpf_load_program bpf_insn parameter
tools lib bpf: Add bpf_prog_{attach,detach}
samples/bpf: Switch over to libbpf
perf diff: Do not overwrite valid build id
perf annotate: Don't throw error for zero length symbols
perf bench futex: Fix lock-pi help string
perf trace: Check if MAP_32BIT is defined (again)
samples/bpf: Make perf_event_read() static
uprobes: Fix uprobes on MIPS, allow for a cache flush after ixol breakpoint creation
samples/bpf: Make samples more libbpf-centric
tools lib bpf: Add flags to bpf_create_map()
tools lib bpf: use __u32 from linux/types.h
...
Diffstat (limited to 'tools')
27 files changed, 865 insertions, 405 deletions
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 9e5fc168c8a3..0eb0e87dbe9f 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -73,6 +73,8 @@ enum bpf_cmd { | |||
73 | BPF_PROG_LOAD, | 73 | BPF_PROG_LOAD, |
74 | BPF_OBJ_PIN, | 74 | BPF_OBJ_PIN, |
75 | BPF_OBJ_GET, | 75 | BPF_OBJ_GET, |
76 | BPF_PROG_ATTACH, | ||
77 | BPF_PROG_DETACH, | ||
76 | }; | 78 | }; |
77 | 79 | ||
78 | enum bpf_map_type { | 80 | enum bpf_map_type { |
@@ -85,6 +87,8 @@ enum bpf_map_type { | |||
85 | BPF_MAP_TYPE_PERCPU_ARRAY, | 87 | BPF_MAP_TYPE_PERCPU_ARRAY, |
86 | BPF_MAP_TYPE_STACK_TRACE, | 88 | BPF_MAP_TYPE_STACK_TRACE, |
87 | BPF_MAP_TYPE_CGROUP_ARRAY, | 89 | BPF_MAP_TYPE_CGROUP_ARRAY, |
90 | BPF_MAP_TYPE_LRU_HASH, | ||
91 | BPF_MAP_TYPE_LRU_PERCPU_HASH, | ||
88 | }; | 92 | }; |
89 | 93 | ||
90 | enum bpf_prog_type { | 94 | enum bpf_prog_type { |
@@ -95,8 +99,23 @@ enum bpf_prog_type { | |||
95 | BPF_PROG_TYPE_SCHED_ACT, | 99 | BPF_PROG_TYPE_SCHED_ACT, |
96 | BPF_PROG_TYPE_TRACEPOINT, | 100 | BPF_PROG_TYPE_TRACEPOINT, |
97 | BPF_PROG_TYPE_XDP, | 101 | BPF_PROG_TYPE_XDP, |
102 | BPF_PROG_TYPE_PERF_EVENT, | ||
103 | BPF_PROG_TYPE_CGROUP_SKB, | ||
104 | BPF_PROG_TYPE_CGROUP_SOCK, | ||
105 | BPF_PROG_TYPE_LWT_IN, | ||
106 | BPF_PROG_TYPE_LWT_OUT, | ||
107 | BPF_PROG_TYPE_LWT_XMIT, | ||
98 | }; | 108 | }; |
99 | 109 | ||
110 | enum bpf_attach_type { | ||
111 | BPF_CGROUP_INET_INGRESS, | ||
112 | BPF_CGROUP_INET_EGRESS, | ||
113 | BPF_CGROUP_INET_SOCK_CREATE, | ||
114 | __MAX_BPF_ATTACH_TYPE | ||
115 | }; | ||
116 | |||
117 | #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE | ||
118 | |||
100 | #define BPF_PSEUDO_MAP_FD 1 | 119 | #define BPF_PSEUDO_MAP_FD 1 |
101 | 120 | ||
102 | /* flags for BPF_MAP_UPDATE_ELEM command */ | 121 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
@@ -105,6 +124,13 @@ enum bpf_prog_type { | |||
105 | #define BPF_EXIST 2 /* update existing element */ | 124 | #define BPF_EXIST 2 /* update existing element */ |
106 | 125 | ||
107 | #define BPF_F_NO_PREALLOC (1U << 0) | 126 | #define BPF_F_NO_PREALLOC (1U << 0) |
127 | /* Instead of having one common LRU list in the | ||
128 | * BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list | ||
129 | * which can scale and perform better. | ||
130 | * Note, the LRU nodes (including free nodes) cannot be moved | ||
131 | * across different LRU lists. | ||
132 | */ | ||
133 | #define BPF_F_NO_COMMON_LRU (1U << 1) | ||
108 | 134 | ||
109 | union bpf_attr { | 135 | union bpf_attr { |
110 | struct { /* anonymous struct used by BPF_MAP_CREATE command */ | 136 | struct { /* anonymous struct used by BPF_MAP_CREATE command */ |
@@ -140,243 +166,327 @@ union bpf_attr { | |||
140 | __aligned_u64 pathname; | 166 | __aligned_u64 pathname; |
141 | __u32 bpf_fd; | 167 | __u32 bpf_fd; |
142 | }; | 168 | }; |
169 | |||
170 | struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ | ||
171 | __u32 target_fd; /* container object to attach to */ | ||
172 | __u32 attach_bpf_fd; /* eBPF program to attach */ | ||
173 | __u32 attach_type; | ||
174 | }; | ||
143 | } __attribute__((aligned(8))); | 175 | } __attribute__((aligned(8))); |
144 | 176 | ||
177 | /* BPF helper function descriptions: | ||
178 | * | ||
179 | * void *bpf_map_lookup_elem(&map, &key) | ||
180 | * Return: Map value or NULL | ||
181 | * | ||
182 | * int bpf_map_update_elem(&map, &key, &value, flags) | ||
183 | * Return: 0 on success or negative error | ||
184 | * | ||
185 | * int bpf_map_delete_elem(&map, &key) | ||
186 | * Return: 0 on success or negative error | ||
187 | * | ||
188 | * int bpf_probe_read(void *dst, int size, void *src) | ||
189 | * Return: 0 on success or negative error | ||
190 | * | ||
191 | * u64 bpf_ktime_get_ns(void) | ||
192 | * Return: current ktime | ||
193 | * | ||
194 | * int bpf_trace_printk(const char *fmt, int fmt_size, ...) | ||
195 | * Return: length of buffer written or negative error | ||
196 | * | ||
197 | * u32 bpf_prandom_u32(void) | ||
198 | * Return: random value | ||
199 | * | ||
200 | * u32 bpf_raw_smp_processor_id(void) | ||
201 | * Return: SMP processor ID | ||
202 | * | ||
203 | * int bpf_skb_store_bytes(skb, offset, from, len, flags) | ||
204 | * store bytes into packet | ||
205 | * @skb: pointer to skb | ||
206 | * @offset: offset within packet from skb->mac_header | ||
207 | * @from: pointer where to copy bytes from | ||
208 | * @len: number of bytes to store into packet | ||
209 | * @flags: bit 0 - if true, recompute skb->csum | ||
210 | * other bits - reserved | ||
211 | * Return: 0 on success or negative error | ||
212 | * | ||
213 | * int bpf_l3_csum_replace(skb, offset, from, to, flags) | ||
214 | * recompute IP checksum | ||
215 | * @skb: pointer to skb | ||
216 | * @offset: offset within packet where IP checksum is located | ||
217 | * @from: old value of header field | ||
218 | * @to: new value of header field | ||
219 | * @flags: bits 0-3 - size of header field | ||
220 | * other bits - reserved | ||
221 | * Return: 0 on success or negative error | ||
222 | * | ||
223 | * int bpf_l4_csum_replace(skb, offset, from, to, flags) | ||
224 | * recompute TCP/UDP checksum | ||
225 | * @skb: pointer to skb | ||
226 | * @offset: offset within packet where TCP/UDP checksum is located | ||
227 | * @from: old value of header field | ||
228 | * @to: new value of header field | ||
229 | * @flags: bits 0-3 - size of header field | ||
230 | * bit 4 - is pseudo header | ||
231 | * other bits - reserved | ||
232 | * Return: 0 on success or negative error | ||
233 | * | ||
234 | * int bpf_tail_call(ctx, prog_array_map, index) | ||
235 | * jump into another BPF program | ||
236 | * @ctx: context pointer passed to next program | ||
237 | * @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY | ||
238 | * @index: index inside array that selects specific program to run | ||
239 | * Return: 0 on success or negative error | ||
240 | * | ||
241 | * int bpf_clone_redirect(skb, ifindex, flags) | ||
242 | * redirect to another netdev | ||
243 | * @skb: pointer to skb | ||
244 | * @ifindex: ifindex of the net device | ||
245 | * @flags: bit 0 - if set, redirect to ingress instead of egress | ||
246 | * other bits - reserved | ||
247 | * Return: 0 on success or negative error | ||
248 | * | ||
249 | * u64 bpf_get_current_pid_tgid(void) | ||
250 | * Return: current->tgid << 32 | current->pid | ||
251 | * | ||
252 | * u64 bpf_get_current_uid_gid(void) | ||
253 | * Return: current_gid << 32 | current_uid | ||
254 | * | ||
255 | * int bpf_get_current_comm(char *buf, int size_of_buf) | ||
256 | * stores current->comm into buf | ||
257 | * Return: 0 on success or negative error | ||
258 | * | ||
259 | * u32 bpf_get_cgroup_classid(skb) | ||
260 | * retrieve a proc's classid | ||
261 | * @skb: pointer to skb | ||
262 | * Return: classid if != 0 | ||
263 | * | ||
264 | * int bpf_skb_vlan_push(skb, vlan_proto, vlan_tci) | ||
265 | * Return: 0 on success or negative error | ||
266 | * | ||
267 | * int bpf_skb_vlan_pop(skb) | ||
268 | * Return: 0 on success or negative error | ||
269 | * | ||
270 | * int bpf_skb_get_tunnel_key(skb, key, size, flags) | ||
271 | * int bpf_skb_set_tunnel_key(skb, key, size, flags) | ||
272 | * retrieve or populate tunnel metadata | ||
273 | * @skb: pointer to skb | ||
274 | * @key: pointer to 'struct bpf_tunnel_key' | ||
275 | * @size: size of 'struct bpf_tunnel_key' | ||
276 | * @flags: room for future extensions | ||
277 | * Return: 0 on success or negative error | ||
278 | * | ||
279 | * u64 bpf_perf_event_read(&map, index) | ||
280 | * Return: Number events read or error code | ||
281 | * | ||
282 | * int bpf_redirect(ifindex, flags) | ||
283 | * redirect to another netdev | ||
284 | * @ifindex: ifindex of the net device | ||
285 | * @flags: bit 0 - if set, redirect to ingress instead of egress | ||
286 | * other bits - reserved | ||
287 | * Return: TC_ACT_REDIRECT | ||
288 | * | ||
289 | * u32 bpf_get_route_realm(skb) | ||
290 | * retrieve a dst's tclassid | ||
291 | * @skb: pointer to skb | ||
292 | * Return: realm if != 0 | ||
293 | * | ||
294 | * int bpf_perf_event_output(ctx, map, index, data, size) | ||
295 | * output perf raw sample | ||
296 | * @ctx: struct pt_regs* | ||
297 | * @map: pointer to perf_event_array map | ||
298 | * @index: index of event in the map | ||
299 | * @data: data on stack to be output as raw data | ||
300 | * @size: size of data | ||
301 | * Return: 0 on success or negative error | ||
302 | * | ||
303 | * int bpf_get_stackid(ctx, map, flags) | ||
304 | * walk user or kernel stack and return id | ||
305 | * @ctx: struct pt_regs* | ||
306 | * @map: pointer to stack_trace map | ||
307 | * @flags: bits 0-7 - numer of stack frames to skip | ||
308 | * bit 8 - collect user stack instead of kernel | ||
309 | * bit 9 - compare stacks by hash only | ||
310 | * bit 10 - if two different stacks hash into the same stackid | ||
311 | * discard old | ||
312 | * other bits - reserved | ||
313 | * Return: >= 0 stackid on success or negative error | ||
314 | * | ||
315 | * s64 bpf_csum_diff(from, from_size, to, to_size, seed) | ||
316 | * calculate csum diff | ||
317 | * @from: raw from buffer | ||
318 | * @from_size: length of from buffer | ||
319 | * @to: raw to buffer | ||
320 | * @to_size: length of to buffer | ||
321 | * @seed: optional seed | ||
322 | * Return: csum result or negative error code | ||
323 | * | ||
324 | * int bpf_skb_get_tunnel_opt(skb, opt, size) | ||
325 | * retrieve tunnel options metadata | ||
326 | * @skb: pointer to skb | ||
327 | * @opt: pointer to raw tunnel option data | ||
328 | * @size: size of @opt | ||
329 | * Return: option size | ||
330 | * | ||
331 | * int bpf_skb_set_tunnel_opt(skb, opt, size) | ||
332 | * populate tunnel options metadata | ||
333 | * @skb: pointer to skb | ||
334 | * @opt: pointer to raw tunnel option data | ||
335 | * @size: size of @opt | ||
336 | * Return: 0 on success or negative error | ||
337 | * | ||
338 | * int bpf_skb_change_proto(skb, proto, flags) | ||
339 | * Change protocol of the skb. Currently supported is v4 -> v6, | ||
340 | * v6 -> v4 transitions. The helper will also resize the skb. eBPF | ||
341 | * program is expected to fill the new headers via skb_store_bytes | ||
342 | * and lX_csum_replace. | ||
343 | * @skb: pointer to skb | ||
344 | * @proto: new skb->protocol type | ||
345 | * @flags: reserved | ||
346 | * Return: 0 on success or negative error | ||
347 | * | ||
348 | * int bpf_skb_change_type(skb, type) | ||
349 | * Change packet type of skb. | ||
350 | * @skb: pointer to skb | ||
351 | * @type: new skb->pkt_type type | ||
352 | * Return: 0 on success or negative error | ||
353 | * | ||
354 | * int bpf_skb_under_cgroup(skb, map, index) | ||
355 | * Check cgroup2 membership of skb | ||
356 | * @skb: pointer to skb | ||
357 | * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type | ||
358 | * @index: index of the cgroup in the bpf_map | ||
359 | * Return: | ||
360 | * == 0 skb failed the cgroup2 descendant test | ||
361 | * == 1 skb succeeded the cgroup2 descendant test | ||
362 | * < 0 error | ||
363 | * | ||
364 | * u32 bpf_get_hash_recalc(skb) | ||
365 | * Retrieve and possibly recalculate skb->hash. | ||
366 | * @skb: pointer to skb | ||
367 | * Return: hash | ||
368 | * | ||
369 | * u64 bpf_get_current_task(void) | ||
370 | * Returns current task_struct | ||
371 | * Return: current | ||
372 | * | ||
373 | * int bpf_probe_write_user(void *dst, void *src, int len) | ||
374 | * safely attempt to write to a location | ||
375 | * @dst: destination address in userspace | ||
376 | * @src: source address on stack | ||
377 | * @len: number of bytes to copy | ||
378 | * Return: 0 on success or negative error | ||
379 | * | ||
380 | * int bpf_current_task_under_cgroup(map, index) | ||
381 | * Check cgroup2 membership of current task | ||
382 | * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type | ||
383 | * @index: index of the cgroup in the bpf_map | ||
384 | * Return: | ||
385 | * == 0 current failed the cgroup2 descendant test | ||
386 | * == 1 current succeeded the cgroup2 descendant test | ||
387 | * < 0 error | ||
388 | * | ||
389 | * int bpf_skb_change_tail(skb, len, flags) | ||
390 | * The helper will resize the skb to the given new size, to be used f.e. | ||
391 | * with control messages. | ||
392 | * @skb: pointer to skb | ||
393 | * @len: new skb length | ||
394 | * @flags: reserved | ||
395 | * Return: 0 on success or negative error | ||
396 | * | ||
397 | * int bpf_skb_pull_data(skb, len) | ||
398 | * The helper will pull in non-linear data in case the skb is non-linear | ||
399 | * and not all of len are part of the linear section. Only needed for | ||
400 | * read/write with direct packet access. | ||
401 | * @skb: pointer to skb | ||
402 | * @len: len to make read/writeable | ||
403 | * Return: 0 on success or negative error | ||
404 | * | ||
405 | * s64 bpf_csum_update(skb, csum) | ||
406 | * Adds csum into skb->csum in case of CHECKSUM_COMPLETE. | ||
407 | * @skb: pointer to skb | ||
408 | * @csum: csum to add | ||
409 | * Return: csum on success or negative error | ||
410 | * | ||
411 | * void bpf_set_hash_invalid(skb) | ||
412 | * Invalidate current skb->hash. | ||
413 | * @skb: pointer to skb | ||
414 | * | ||
415 | * int bpf_get_numa_node_id() | ||
416 | * Return: Id of current NUMA node. | ||
417 | * | ||
418 | * int bpf_skb_change_head() | ||
419 | * Grows headroom of skb and adjusts MAC header offset accordingly. | ||
420 | * Will extends/reallocae as required automatically. | ||
421 | * May change skb data pointer and will thus invalidate any check | ||
422 | * performed for direct packet access. | ||
423 | * @skb: pointer to skb | ||
424 | * @len: length of header to be pushed in front | ||
425 | * @flags: Flags (unused for now) | ||
426 | * Return: 0 on success or negative error | ||
427 | * | ||
428 | * int bpf_xdp_adjust_head(xdp_md, delta) | ||
429 | * Adjust the xdp_md.data by delta | ||
430 | * @xdp_md: pointer to xdp_md | ||
431 | * @delta: An positive/negative integer to be added to xdp_md.data | ||
432 | * Return: 0 on success or negative on error | ||
433 | */ | ||
434 | #define __BPF_FUNC_MAPPER(FN) \ | ||
435 | FN(unspec), \ | ||
436 | FN(map_lookup_elem), \ | ||
437 | FN(map_update_elem), \ | ||
438 | FN(map_delete_elem), \ | ||
439 | FN(probe_read), \ | ||
440 | FN(ktime_get_ns), \ | ||
441 | FN(trace_printk), \ | ||
442 | FN(get_prandom_u32), \ | ||
443 | FN(get_smp_processor_id), \ | ||
444 | FN(skb_store_bytes), \ | ||
445 | FN(l3_csum_replace), \ | ||
446 | FN(l4_csum_replace), \ | ||
447 | FN(tail_call), \ | ||
448 | FN(clone_redirect), \ | ||
449 | FN(get_current_pid_tgid), \ | ||
450 | FN(get_current_uid_gid), \ | ||
451 | FN(get_current_comm), \ | ||
452 | FN(get_cgroup_classid), \ | ||
453 | FN(skb_vlan_push), \ | ||
454 | FN(skb_vlan_pop), \ | ||
455 | FN(skb_get_tunnel_key), \ | ||
456 | FN(skb_set_tunnel_key), \ | ||
457 | FN(perf_event_read), \ | ||
458 | FN(redirect), \ | ||
459 | FN(get_route_realm), \ | ||
460 | FN(perf_event_output), \ | ||
461 | FN(skb_load_bytes), \ | ||
462 | FN(get_stackid), \ | ||
463 | FN(csum_diff), \ | ||
464 | FN(skb_get_tunnel_opt), \ | ||
465 | FN(skb_set_tunnel_opt), \ | ||
466 | FN(skb_change_proto), \ | ||
467 | FN(skb_change_type), \ | ||
468 | FN(skb_under_cgroup), \ | ||
469 | FN(get_hash_recalc), \ | ||
470 | FN(get_current_task), \ | ||
471 | FN(probe_write_user), \ | ||
472 | FN(current_task_under_cgroup), \ | ||
473 | FN(skb_change_tail), \ | ||
474 | FN(skb_pull_data), \ | ||
475 | FN(csum_update), \ | ||
476 | FN(set_hash_invalid), \ | ||
477 | FN(get_numa_node_id), \ | ||
478 | FN(skb_change_head), \ | ||
479 | FN(xdp_adjust_head), | ||
480 | |||
145 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 481 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
146 | * function eBPF program intends to call | 482 | * function eBPF program intends to call |
147 | */ | 483 | */ |
484 | #define __BPF_ENUM_FN(x) BPF_FUNC_ ## x | ||
148 | enum bpf_func_id { | 485 | enum bpf_func_id { |
149 | BPF_FUNC_unspec, | 486 | __BPF_FUNC_MAPPER(__BPF_ENUM_FN) |
150 | BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */ | ||
151 | BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */ | ||
152 | BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */ | ||
153 | BPF_FUNC_probe_read, /* int bpf_probe_read(void *dst, int size, void *src) */ | ||
154 | BPF_FUNC_ktime_get_ns, /* u64 bpf_ktime_get_ns(void) */ | ||
155 | BPF_FUNC_trace_printk, /* int bpf_trace_printk(const char *fmt, int fmt_size, ...) */ | ||
156 | BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */ | ||
157 | BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */ | ||
158 | |||
159 | /** | ||
160 | * skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet | ||
161 | * @skb: pointer to skb | ||
162 | * @offset: offset within packet from skb->mac_header | ||
163 | * @from: pointer where to copy bytes from | ||
164 | * @len: number of bytes to store into packet | ||
165 | * @flags: bit 0 - if true, recompute skb->csum | ||
166 | * other bits - reserved | ||
167 | * Return: 0 on success | ||
168 | */ | ||
169 | BPF_FUNC_skb_store_bytes, | ||
170 | |||
171 | /** | ||
172 | * l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum | ||
173 | * @skb: pointer to skb | ||
174 | * @offset: offset within packet where IP checksum is located | ||
175 | * @from: old value of header field | ||
176 | * @to: new value of header field | ||
177 | * @flags: bits 0-3 - size of header field | ||
178 | * other bits - reserved | ||
179 | * Return: 0 on success | ||
180 | */ | ||
181 | BPF_FUNC_l3_csum_replace, | ||
182 | |||
183 | /** | ||
184 | * l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum | ||
185 | * @skb: pointer to skb | ||
186 | * @offset: offset within packet where TCP/UDP checksum is located | ||
187 | * @from: old value of header field | ||
188 | * @to: new value of header field | ||
189 | * @flags: bits 0-3 - size of header field | ||
190 | * bit 4 - is pseudo header | ||
191 | * other bits - reserved | ||
192 | * Return: 0 on success | ||
193 | */ | ||
194 | BPF_FUNC_l4_csum_replace, | ||
195 | |||
196 | /** | ||
197 | * bpf_tail_call(ctx, prog_array_map, index) - jump into another BPF program | ||
198 | * @ctx: context pointer passed to next program | ||
199 | * @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY | ||
200 | * @index: index inside array that selects specific program to run | ||
201 | * Return: 0 on success | ||
202 | */ | ||
203 | BPF_FUNC_tail_call, | ||
204 | |||
205 | /** | ||
206 | * bpf_clone_redirect(skb, ifindex, flags) - redirect to another netdev | ||
207 | * @skb: pointer to skb | ||
208 | * @ifindex: ifindex of the net device | ||
209 | * @flags: bit 0 - if set, redirect to ingress instead of egress | ||
210 | * other bits - reserved | ||
211 | * Return: 0 on success | ||
212 | */ | ||
213 | BPF_FUNC_clone_redirect, | ||
214 | |||
215 | /** | ||
216 | * u64 bpf_get_current_pid_tgid(void) | ||
217 | * Return: current->tgid << 32 | current->pid | ||
218 | */ | ||
219 | BPF_FUNC_get_current_pid_tgid, | ||
220 | |||
221 | /** | ||
222 | * u64 bpf_get_current_uid_gid(void) | ||
223 | * Return: current_gid << 32 | current_uid | ||
224 | */ | ||
225 | BPF_FUNC_get_current_uid_gid, | ||
226 | |||
227 | /** | ||
228 | * bpf_get_current_comm(char *buf, int size_of_buf) | ||
229 | * stores current->comm into buf | ||
230 | * Return: 0 on success | ||
231 | */ | ||
232 | BPF_FUNC_get_current_comm, | ||
233 | |||
234 | /** | ||
235 | * bpf_get_cgroup_classid(skb) - retrieve a proc's classid | ||
236 | * @skb: pointer to skb | ||
237 | * Return: classid if != 0 | ||
238 | */ | ||
239 | BPF_FUNC_get_cgroup_classid, | ||
240 | BPF_FUNC_skb_vlan_push, /* bpf_skb_vlan_push(skb, vlan_proto, vlan_tci) */ | ||
241 | BPF_FUNC_skb_vlan_pop, /* bpf_skb_vlan_pop(skb) */ | ||
242 | |||
243 | /** | ||
244 | * bpf_skb_[gs]et_tunnel_key(skb, key, size, flags) | ||
245 | * retrieve or populate tunnel metadata | ||
246 | * @skb: pointer to skb | ||
247 | * @key: pointer to 'struct bpf_tunnel_key' | ||
248 | * @size: size of 'struct bpf_tunnel_key' | ||
249 | * @flags: room for future extensions | ||
250 | * Retrun: 0 on success | ||
251 | */ | ||
252 | BPF_FUNC_skb_get_tunnel_key, | ||
253 | BPF_FUNC_skb_set_tunnel_key, | ||
254 | BPF_FUNC_perf_event_read, /* u64 bpf_perf_event_read(&map, index) */ | ||
255 | /** | ||
256 | * bpf_redirect(ifindex, flags) - redirect to another netdev | ||
257 | * @ifindex: ifindex of the net device | ||
258 | * @flags: bit 0 - if set, redirect to ingress instead of egress | ||
259 | * other bits - reserved | ||
260 | * Return: TC_ACT_REDIRECT | ||
261 | */ | ||
262 | BPF_FUNC_redirect, | ||
263 | |||
264 | /** | ||
265 | * bpf_get_route_realm(skb) - retrieve a dst's tclassid | ||
266 | * @skb: pointer to skb | ||
267 | * Return: realm if != 0 | ||
268 | */ | ||
269 | BPF_FUNC_get_route_realm, | ||
270 | |||
271 | /** | ||
272 | * bpf_perf_event_output(ctx, map, index, data, size) - output perf raw sample | ||
273 | * @ctx: struct pt_regs* | ||
274 | * @map: pointer to perf_event_array map | ||
275 | * @index: index of event in the map | ||
276 | * @data: data on stack to be output as raw data | ||
277 | * @size: size of data | ||
278 | * Return: 0 on success | ||
279 | */ | ||
280 | BPF_FUNC_perf_event_output, | ||
281 | BPF_FUNC_skb_load_bytes, | ||
282 | |||
283 | /** | ||
284 | * bpf_get_stackid(ctx, map, flags) - walk user or kernel stack and return id | ||
285 | * @ctx: struct pt_regs* | ||
286 | * @map: pointer to stack_trace map | ||
287 | * @flags: bits 0-7 - numer of stack frames to skip | ||
288 | * bit 8 - collect user stack instead of kernel | ||
289 | * bit 9 - compare stacks by hash only | ||
290 | * bit 10 - if two different stacks hash into the same stackid | ||
291 | * discard old | ||
292 | * other bits - reserved | ||
293 | * Return: >= 0 stackid on success or negative error | ||
294 | */ | ||
295 | BPF_FUNC_get_stackid, | ||
296 | |||
297 | /** | ||
298 | * bpf_csum_diff(from, from_size, to, to_size, seed) - calculate csum diff | ||
299 | * @from: raw from buffer | ||
300 | * @from_size: length of from buffer | ||
301 | * @to: raw to buffer | ||
302 | * @to_size: length of to buffer | ||
303 | * @seed: optional seed | ||
304 | * Return: csum result | ||
305 | */ | ||
306 | BPF_FUNC_csum_diff, | ||
307 | |||
308 | /** | ||
309 | * bpf_skb_[gs]et_tunnel_opt(skb, opt, size) | ||
310 | * retrieve or populate tunnel options metadata | ||
311 | * @skb: pointer to skb | ||
312 | * @opt: pointer to raw tunnel option data | ||
313 | * @size: size of @opt | ||
314 | * Return: 0 on success for set, option size for get | ||
315 | */ | ||
316 | BPF_FUNC_skb_get_tunnel_opt, | ||
317 | BPF_FUNC_skb_set_tunnel_opt, | ||
318 | |||
319 | /** | ||
320 | * bpf_skb_change_proto(skb, proto, flags) | ||
321 | * Change protocol of the skb. Currently supported is | ||
322 | * v4 -> v6, v6 -> v4 transitions. The helper will also | ||
323 | * resize the skb. eBPF program is expected to fill the | ||
324 | * new headers via skb_store_bytes and lX_csum_replace. | ||
325 | * @skb: pointer to skb | ||
326 | * @proto: new skb->protocol type | ||
327 | * @flags: reserved | ||
328 | * Return: 0 on success or negative error | ||
329 | */ | ||
330 | BPF_FUNC_skb_change_proto, | ||
331 | |||
332 | /** | ||
333 | * bpf_skb_change_type(skb, type) | ||
334 | * Change packet type of skb. | ||
335 | * @skb: pointer to skb | ||
336 | * @type: new skb->pkt_type type | ||
337 | * Return: 0 on success or negative error | ||
338 | */ | ||
339 | BPF_FUNC_skb_change_type, | ||
340 | |||
341 | /** | ||
342 | * bpf_skb_under_cgroup(skb, map, index) - Check cgroup2 membership of skb | ||
343 | * @skb: pointer to skb | ||
344 | * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type | ||
345 | * @index: index of the cgroup in the bpf_map | ||
346 | * Return: | ||
347 | * == 0 skb failed the cgroup2 descendant test | ||
348 | * == 1 skb succeeded the cgroup2 descendant test | ||
349 | * < 0 error | ||
350 | */ | ||
351 | BPF_FUNC_skb_under_cgroup, | ||
352 | |||
353 | /** | ||
354 | * bpf_get_hash_recalc(skb) | ||
355 | * Retrieve and possibly recalculate skb->hash. | ||
356 | * @skb: pointer to skb | ||
357 | * Return: hash | ||
358 | */ | ||
359 | BPF_FUNC_get_hash_recalc, | ||
360 | |||
361 | /** | ||
362 | * u64 bpf_get_current_task(void) | ||
363 | * Returns current task_struct | ||
364 | * Return: current | ||
365 | */ | ||
366 | BPF_FUNC_get_current_task, | ||
367 | |||
368 | /** | ||
369 | * bpf_probe_write_user(void *dst, void *src, int len) | ||
370 | * safely attempt to write to a location | ||
371 | * @dst: destination address in userspace | ||
372 | * @src: source address on stack | ||
373 | * @len: number of bytes to copy | ||
374 | * Return: 0 on success or negative error | ||
375 | */ | ||
376 | BPF_FUNC_probe_write_user, | ||
377 | |||
378 | __BPF_FUNC_MAX_ID, | 487 | __BPF_FUNC_MAX_ID, |
379 | }; | 488 | }; |
489 | #undef __BPF_ENUM_FN | ||
380 | 490 | ||
381 | /* All flags used by eBPF helper functions, placed here. */ | 491 | /* All flags used by eBPF helper functions, placed here. */ |
382 | 492 | ||
@@ -450,6 +560,31 @@ struct bpf_tunnel_key { | |||
450 | __u32 tunnel_label; | 560 | __u32 tunnel_label; |
451 | }; | 561 | }; |
452 | 562 | ||
563 | /* Generic BPF return codes which all BPF program types may support. | ||
564 | * The values are binary compatible with their TC_ACT_* counter-part to | ||
565 | * provide backwards compatibility with existing SCHED_CLS and SCHED_ACT | ||
566 | * programs. | ||
567 | * | ||
568 | * XDP is handled seprately, see XDP_*. | ||
569 | */ | ||
570 | enum bpf_ret_code { | ||
571 | BPF_OK = 0, | ||
572 | /* 1 reserved */ | ||
573 | BPF_DROP = 2, | ||
574 | /* 3-6 reserved */ | ||
575 | BPF_REDIRECT = 7, | ||
576 | /* >127 are reserved for prog type specific return codes */ | ||
577 | }; | ||
578 | |||
579 | struct bpf_sock { | ||
580 | __u32 bound_dev_if; | ||
581 | __u32 family; | ||
582 | __u32 type; | ||
583 | __u32 protocol; | ||
584 | }; | ||
585 | |||
586 | #define XDP_PACKET_HEADROOM 256 | ||
587 | |||
453 | /* User return codes for XDP prog type. | 588 | /* User return codes for XDP prog type. |
454 | * A valid XDP program must return one of these defined values. All other | 589 | * A valid XDP program must return one of these defined values. All other |
455 | * return codes are reserved for future use. Unknown return codes will result | 590 | * return codes are reserved for future use. Unknown return codes will result |
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 8143536b462a..3ddb58a36d3c 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c | |||
@@ -54,7 +54,7 @@ static int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, | |||
54 | } | 54 | } |
55 | 55 | ||
56 | int bpf_create_map(enum bpf_map_type map_type, int key_size, | 56 | int bpf_create_map(enum bpf_map_type map_type, int key_size, |
57 | int value_size, int max_entries) | 57 | int value_size, int max_entries, __u32 map_flags) |
58 | { | 58 | { |
59 | union bpf_attr attr; | 59 | union bpf_attr attr; |
60 | 60 | ||
@@ -64,13 +64,14 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, | |||
64 | attr.key_size = key_size; | 64 | attr.key_size = key_size; |
65 | attr.value_size = value_size; | 65 | attr.value_size = value_size; |
66 | attr.max_entries = max_entries; | 66 | attr.max_entries = max_entries; |
67 | attr.map_flags = map_flags; | ||
67 | 68 | ||
68 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); | 69 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); |
69 | } | 70 | } |
70 | 71 | ||
71 | int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, | 72 | int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, |
72 | size_t insns_cnt, char *license, | 73 | size_t insns_cnt, char *license, |
73 | u32 kern_version, char *log_buf, size_t log_buf_sz) | 74 | __u32 kern_version, char *log_buf, size_t log_buf_sz) |
74 | { | 75 | { |
75 | int fd; | 76 | int fd; |
76 | union bpf_attr attr; | 77 | union bpf_attr attr; |
@@ -98,7 +99,7 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, | |||
98 | } | 99 | } |
99 | 100 | ||
100 | int bpf_map_update_elem(int fd, void *key, void *value, | 101 | int bpf_map_update_elem(int fd, void *key, void *value, |
101 | u64 flags) | 102 | __u64 flags) |
102 | { | 103 | { |
103 | union bpf_attr attr; | 104 | union bpf_attr attr; |
104 | 105 | ||
@@ -166,3 +167,26 @@ int bpf_obj_get(const char *pathname) | |||
166 | 167 | ||
167 | return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr)); | 168 | return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr)); |
168 | } | 169 | } |
170 | |||
171 | int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type) | ||
172 | { | ||
173 | union bpf_attr attr; | ||
174 | |||
175 | bzero(&attr, sizeof(attr)); | ||
176 | attr.target_fd = target_fd; | ||
177 | attr.attach_bpf_fd = prog_fd; | ||
178 | attr.attach_type = type; | ||
179 | |||
180 | return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)); | ||
181 | } | ||
182 | |||
183 | int bpf_prog_detach(int target_fd, enum bpf_attach_type type) | ||
184 | { | ||
185 | union bpf_attr attr; | ||
186 | |||
187 | bzero(&attr, sizeof(attr)); | ||
188 | attr.target_fd = target_fd; | ||
189 | attr.attach_type = type; | ||
190 | |||
191 | return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); | ||
192 | } | ||
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 253c3dbb06b4..a2f9853dd882 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h | |||
@@ -24,22 +24,25 @@ | |||
24 | #include <linux/bpf.h> | 24 | #include <linux/bpf.h> |
25 | 25 | ||
26 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | 26 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, |
27 | int max_entries); | 27 | int max_entries, __u32 map_flags); |
28 | 28 | ||
29 | /* Recommend log buffer size */ | 29 | /* Recommend log buffer size */ |
30 | #define BPF_LOG_BUF_SIZE 65536 | 30 | #define BPF_LOG_BUF_SIZE 65536 |
31 | int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, | 31 | int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, |
32 | size_t insns_cnt, char *license, | 32 | size_t insns_cnt, char *license, |
33 | u32 kern_version, char *log_buf, | 33 | __u32 kern_version, char *log_buf, |
34 | size_t log_buf_sz); | 34 | size_t log_buf_sz); |
35 | 35 | ||
36 | int bpf_map_update_elem(int fd, void *key, void *value, | 36 | int bpf_map_update_elem(int fd, void *key, void *value, |
37 | u64 flags); | 37 | __u64 flags); |
38 | 38 | ||
39 | int bpf_map_lookup_elem(int fd, void *key, void *value); | 39 | int bpf_map_lookup_elem(int fd, void *key, void *value); |
40 | int bpf_map_delete_elem(int fd, void *key); | 40 | int bpf_map_delete_elem(int fd, void *key); |
41 | int bpf_map_get_next_key(int fd, void *key, void *next_key); | 41 | int bpf_map_get_next_key(int fd, void *key, void *next_key); |
42 | int bpf_obj_pin(int fd, const char *pathname); | 42 | int bpf_obj_pin(int fd, const char *pathname); |
43 | int bpf_obj_get(const char *pathname); | 43 | int bpf_obj_get(const char *pathname); |
44 | int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type); | ||
45 | int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); | ||
46 | |||
44 | 47 | ||
45 | #endif | 48 | #endif |
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 2e974593f3e8..84e6b35da4bd 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -854,7 +854,8 @@ bpf_object__create_maps(struct bpf_object *obj) | |||
854 | *pfd = bpf_create_map(def->type, | 854 | *pfd = bpf_create_map(def->type, |
855 | def->key_size, | 855 | def->key_size, |
856 | def->value_size, | 856 | def->value_size, |
857 | def->max_entries); | 857 | def->max_entries, |
858 | 0); | ||
858 | if (*pfd < 0) { | 859 | if (*pfd < 0) { |
859 | size_t j; | 860 | size_t j; |
860 | int err = *pfd; | 861 | int err = *pfd; |
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 7775b1eb2bee..76173969ab80 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt | |||
@@ -132,6 +132,10 @@ OPTIONS for 'perf sched timehist' | |||
132 | --migrations:: | 132 | --migrations:: |
133 | Show migration events. | 133 | Show migration events. |
134 | 134 | ||
135 | -I:: | ||
136 | --idle-hist:: | ||
137 | Show idle-related events only. | ||
138 | |||
135 | --time:: | 139 | --time:: |
136 | Only analyze samples within given time window: <start>,<stop>. Times | 140 | Only analyze samples within given time window: <start>,<stop>. Times |
137 | have the format seconds.microseconds. If start is not given (i.e., time | 141 | have the format seconds.microseconds. If start is not given (i.e., time |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index e5af38eede17..8fc24824705e 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -201,6 +201,7 @@ goals := $(filter-out all sub-make, $(MAKECMDGOALS)) | |||
201 | $(goals) all: sub-make | 201 | $(goals) all: sub-make |
202 | 202 | ||
203 | sub-make: fixdep | 203 | sub-make: fixdep |
204 | @./check-headers.sh | ||
204 | $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals) | 205 | $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals) |
205 | 206 | ||
206 | else # force_fixdep | 207 | else # force_fixdep |
@@ -404,99 +405,6 @@ export JEVENTS | |||
404 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | 405 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj |
405 | 406 | ||
406 | $(PERF_IN): prepare FORCE | 407 | $(PERF_IN): prepare FORCE |
407 | @(test -f ../../include/uapi/linux/perf_event.h && ( \ | ||
408 | (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ | ||
409 | || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true | ||
410 | @(test -f ../../include/linux/hash.h && ( \ | ||
411 | (diff -B ../include/linux/hash.h ../../include/linux/hash.h >/dev/null) \ | ||
412 | || echo "Warning: tools/include/linux/hash.h differs from kernel" >&2 )) || true | ||
413 | @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \ | ||
414 | (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \ | ||
415 | || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true | ||
416 | @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \ | ||
417 | (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \ | ||
418 | || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true | ||
419 | @(test -f ../../arch/x86/include/asm/required-features.h && ( \ | ||
420 | (diff -B ../arch/x86/include/asm/required-features.h ../../arch/x86/include/asm/required-features.h >/dev/null) \ | ||
421 | || echo "Warning: tools/arch/x86/include/asm/required-features.h differs from kernel" >&2 )) || true | ||
422 | @(test -f ../../arch/x86/include/asm/cpufeatures.h && ( \ | ||
423 | (diff -B ../arch/x86/include/asm/cpufeatures.h ../../arch/x86/include/asm/cpufeatures.h >/dev/null) \ | ||
424 | || echo "Warning: tools/arch/x86/include/asm/cpufeatures.h differs from kernel" >&2 )) || true | ||
425 | @(test -f ../../arch/x86/lib/memcpy_64.S && ( \ | ||
426 | (diff -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" ../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memcpy_64.S >/dev/null) \ | ||
427 | || echo "Warning: tools/arch/x86/lib/memcpy_64.S differs from kernel" >&2 )) || true | ||
428 | @(test -f ../../arch/x86/lib/memset_64.S && ( \ | ||
429 | (diff -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \ | ||
430 | || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true | ||
431 | @(test -f ../../arch/arm/include/uapi/asm/perf_regs.h && ( \ | ||
432 | (diff -B ../arch/arm/include/uapi/asm/perf_regs.h ../../arch/arm/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
433 | || echo "Warning: tools/arch/arm/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
434 | @(test -f ../../arch/arm64/include/uapi/asm/perf_regs.h && ( \ | ||
435 | (diff -B ../arch/arm64/include/uapi/asm/perf_regs.h ../../arch/arm64/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
436 | || echo "Warning: tools/arch/arm64/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
437 | @(test -f ../../arch/powerpc/include/uapi/asm/perf_regs.h && ( \ | ||
438 | (diff -B ../arch/powerpc/include/uapi/asm/perf_regs.h ../../arch/powerpc/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
439 | || echo "Warning: tools/arch/powerpc/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
440 | @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \ | ||
441 | (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
442 | || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
443 | @(test -f ../../arch/x86/include/uapi/asm/kvm.h && ( \ | ||
444 | (diff -B ../arch/x86/include/uapi/asm/kvm.h ../../arch/x86/include/uapi/asm/kvm.h >/dev/null) \ | ||
445 | || echo "Warning: tools/arch/x86/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
446 | @(test -f ../../arch/x86/include/uapi/asm/kvm_perf.h && ( \ | ||
447 | (diff -B ../arch/x86/include/uapi/asm/kvm_perf.h ../../arch/x86/include/uapi/asm/kvm_perf.h >/dev/null) \ | ||
448 | || echo "Warning: tools/arch/x86/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true | ||
449 | @(test -f ../../arch/x86/include/uapi/asm/svm.h && ( \ | ||
450 | (diff -B ../arch/x86/include/uapi/asm/svm.h ../../arch/x86/include/uapi/asm/svm.h >/dev/null) \ | ||
451 | || echo "Warning: tools/arch/x86/include/uapi/asm/svm.h differs from kernel" >&2 )) || true | ||
452 | @(test -f ../../arch/x86/include/uapi/asm/vmx.h && ( \ | ||
453 | (diff -B ../arch/x86/include/uapi/asm/vmx.h ../../arch/x86/include/uapi/asm/vmx.h >/dev/null) \ | ||
454 | || echo "Warning: tools/arch/x86/include/uapi/asm/vmx.h differs from kernel" >&2 )) || true | ||
455 | @(test -f ../../arch/powerpc/include/uapi/asm/kvm.h && ( \ | ||
456 | (diff -B ../arch/powerpc/include/uapi/asm/kvm.h ../../arch/powerpc/include/uapi/asm/kvm.h >/dev/null) \ | ||
457 | || echo "Warning: tools/arch/powerpc/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
458 | @(test -f ../../arch/s390/include/uapi/asm/kvm.h && ( \ | ||
459 | (diff -B ../arch/s390/include/uapi/asm/kvm.h ../../arch/s390/include/uapi/asm/kvm.h >/dev/null) \ | ||
460 | || echo "Warning: tools/arch/s390/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
461 | @(test -f ../../arch/s390/include/uapi/asm/kvm_perf.h && ( \ | ||
462 | (diff -B ../arch/s390/include/uapi/asm/kvm_perf.h ../../arch/s390/include/uapi/asm/kvm_perf.h >/dev/null) \ | ||
463 | || echo "Warning: tools/arch/s390/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true | ||
464 | @(test -f ../../arch/s390/include/uapi/asm/sie.h && ( \ | ||
465 | (diff -B ../arch/s390/include/uapi/asm/sie.h ../../arch/s390/include/uapi/asm/sie.h >/dev/null) \ | ||
466 | || echo "Warning: tools/arch/s390/include/uapi/asm/sie.h differs from kernel" >&2 )) || true | ||
467 | @(test -f ../../arch/arm/include/uapi/asm/kvm.h && ( \ | ||
468 | (diff -B ../arch/arm/include/uapi/asm/kvm.h ../../arch/arm/include/uapi/asm/kvm.h >/dev/null) \ | ||
469 | || echo "Warning: tools/arch/arm/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
470 | @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \ | ||
471 | (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \ | ||
472 | || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
473 | @(test -f ../../include/asm-generic/bitops/arch_hweight.h && ( \ | ||
474 | (diff -B ../include/asm-generic/bitops/arch_hweight.h ../../include/asm-generic/bitops/arch_hweight.h >/dev/null) \ | ||
475 | || echo "Warning: tools/include/asm-generic/bitops/arch_hweight.h differs from kernel" >&2 )) || true | ||
476 | @(test -f ../../include/asm-generic/bitops/const_hweight.h && ( \ | ||
477 | (diff -B ../include/asm-generic/bitops/const_hweight.h ../../include/asm-generic/bitops/const_hweight.h >/dev/null) \ | ||
478 | || echo "Warning: tools/include/asm-generic/bitops/const_hweight.h differs from kernel" >&2 )) || true | ||
479 | @(test -f ../../include/asm-generic/bitops/__fls.h && ( \ | ||
480 | (diff -B ../include/asm-generic/bitops/__fls.h ../../include/asm-generic/bitops/__fls.h >/dev/null) \ | ||
481 | || echo "Warning: tools/include/asm-generic/bitops/__fls.h differs from kernel" >&2 )) || true | ||
482 | @(test -f ../../include/asm-generic/bitops/fls.h && ( \ | ||
483 | (diff -B ../include/asm-generic/bitops/fls.h ../../include/asm-generic/bitops/fls.h >/dev/null) \ | ||
484 | || echo "Warning: tools/include/asm-generic/bitops/fls.h differs from kernel" >&2 )) || true | ||
485 | @(test -f ../../include/asm-generic/bitops/fls64.h && ( \ | ||
486 | (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \ | ||
487 | || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true | ||
488 | @(test -f ../../include/linux/coresight-pmu.h && ( \ | ||
489 | (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \ | ||
490 | || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true | ||
491 | @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \ | ||
492 | (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \ | ||
493 | || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true | ||
494 | @(test -f ../../include/uapi/asm-generic/mman.h && ( \ | ||
495 | (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \ | ||
496 | || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true | ||
497 | @(test -f ../../include/uapi/linux/mman.h && ( \ | ||
498 | (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \ | ||
499 | || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true | ||
500 | $(Q)$(MAKE) $(build)=perf | 408 | $(Q)$(MAKE) $(build)=perf |
501 | 409 | ||
502 | $(JEVENTS_IN): FORCE | 410 | $(JEVENTS_IN): FORCE |
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index 465012b320ee..6d9d6c40a916 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c | |||
@@ -48,7 +48,7 @@ static const struct option options[] = { | |||
48 | }; | 48 | }; |
49 | 49 | ||
50 | static const char * const bench_futex_lock_pi_usage[] = { | 50 | static const char * const bench_futex_lock_pi_usage[] = { |
51 | "perf bench futex requeue <options>", | 51 | "perf bench futex lock-pi <options>", |
52 | NULL | 52 | NULL |
53 | }; | 53 | }; |
54 | 54 | ||
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 4b419631753d..f8ca7a4ebabc 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
@@ -208,7 +208,7 @@ static void compute_stats(struct c2c_hist_entry *c2c_he, | |||
208 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 208 | static int process_sample_event(struct perf_tool *tool __maybe_unused, |
209 | union perf_event *event, | 209 | union perf_event *event, |
210 | struct perf_sample *sample, | 210 | struct perf_sample *sample, |
211 | struct perf_evsel *evsel __maybe_unused, | 211 | struct perf_evsel *evsel, |
212 | struct machine *machine) | 212 | struct machine *machine) |
213 | { | 213 | { |
214 | struct c2c_hists *c2c_hists = &c2c.hists; | 214 | struct c2c_hists *c2c_hists = &c2c.hists; |
@@ -379,7 +379,7 @@ static int symbol_width(struct hists *hists, struct sort_entry *se) | |||
379 | 379 | ||
380 | static int c2c_width(struct perf_hpp_fmt *fmt, | 380 | static int c2c_width(struct perf_hpp_fmt *fmt, |
381 | struct perf_hpp *hpp __maybe_unused, | 381 | struct perf_hpp *hpp __maybe_unused, |
382 | struct hists *hists __maybe_unused) | 382 | struct hists *hists) |
383 | { | 383 | { |
384 | struct c2c_fmt *c2c_fmt; | 384 | struct c2c_fmt *c2c_fmt; |
385 | struct c2c_dimension *dim; | 385 | struct c2c_dimension *dim; |
@@ -1127,7 +1127,7 @@ MEAN_ENTRY(mean_lcl_entry, lcl_hitm); | |||
1127 | MEAN_ENTRY(mean_load_entry, load); | 1127 | MEAN_ENTRY(mean_load_entry, load); |
1128 | 1128 | ||
1129 | static int | 1129 | static int |
1130 | cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, | 1130 | cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1131 | struct hist_entry *he) | 1131 | struct hist_entry *he) |
1132 | { | 1132 | { |
1133 | struct c2c_hist_entry *c2c_he; | 1133 | struct c2c_hist_entry *c2c_he; |
@@ -1141,7 +1141,7 @@ cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, | |||
1141 | } | 1141 | } |
1142 | 1142 | ||
1143 | static int | 1143 | static int |
1144 | cl_idx_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, | 1144 | cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1145 | struct hist_entry *he) | 1145 | struct hist_entry *he) |
1146 | { | 1146 | { |
1147 | struct c2c_hist_entry *c2c_he; | 1147 | struct c2c_hist_entry *c2c_he; |
@@ -1155,7 +1155,7 @@ cl_idx_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, | |||
1155 | } | 1155 | } |
1156 | 1156 | ||
1157 | static int | 1157 | static int |
1158 | cl_idx_empty_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, | 1158 | cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1159 | struct hist_entry *he) | 1159 | struct hist_entry *he) |
1160 | { | 1160 | { |
1161 | int width = c2c_width(fmt, hpp, he->hists); | 1161 | int width = c2c_width(fmt, hpp, he->hists); |
@@ -1779,7 +1779,6 @@ static int c2c_hists__init(struct c2c_hists *hists, | |||
1779 | return hpp_list__parse(&hists->list, NULL, sort); | 1779 | return hpp_list__parse(&hists->list, NULL, sort); |
1780 | } | 1780 | } |
1781 | 1781 | ||
1782 | __maybe_unused | ||
1783 | static int c2c_hists__reinit(struct c2c_hists *c2c_hists, | 1782 | static int c2c_hists__reinit(struct c2c_hists *c2c_hists, |
1784 | const char *output, | 1783 | const char *output, |
1785 | const char *sort) | 1784 | const char *sort) |
@@ -2658,7 +2657,7 @@ out: | |||
2658 | return err; | 2657 | return err; |
2659 | } | 2658 | } |
2660 | 2659 | ||
2661 | static int parse_record_events(const struct option *opt __maybe_unused, | 2660 | static int parse_record_events(const struct option *opt, |
2662 | const char *str, int unset __maybe_unused) | 2661 | const char *str, int unset __maybe_unused) |
2663 | { | 2662 | { |
2664 | bool *event_set = (bool *) opt->value; | 2663 | bool *event_set = (bool *) opt->value; |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index d1ce29be560e..cd7bc4d104e2 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -70,8 +70,8 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) | |||
70 | OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"), | 70 | OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"), |
71 | OPT_INCR('v', "verbose", &verbose, | 71 | OPT_INCR('v', "verbose", &verbose, |
72 | "be more verbose (show counter open errors, etc)"), | 72 | "be more verbose (show counter open errors, etc)"), |
73 | OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), | 73 | OPT_BOOLEAN('U', "all-user", &all_user, "collect only user level data"), |
74 | OPT_BOOLEAN('K', "--all-kernel", &all_kernel, "collect only kernel level data"), | 74 | OPT_BOOLEAN('K', "all-kernel", &all_kernel, "collect only kernel level data"), |
75 | OPT_END() | 75 | OPT_END() |
76 | }; | 76 | }; |
77 | 77 | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index fa26865364b6..74d6a035133a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -1687,6 +1687,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1687 | goto out; | 1687 | goto out; |
1688 | } | 1688 | } |
1689 | 1689 | ||
1690 | /* Enable ignoring missing threads when -u option is defined. */ | ||
1691 | rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX; | ||
1692 | |||
1690 | err = -ENOMEM; | 1693 | err = -ENOMEM; |
1691 | if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) | 1694 | if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) |
1692 | usage_with_options(record_usage, record_options); | 1695 | usage_with_options(record_usage, record_options); |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index d2afbe4a240d..06cc759a4597 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -648,7 +648,7 @@ report_parse_ignore_callees_opt(const struct option *opt __maybe_unused, | |||
648 | } | 648 | } |
649 | 649 | ||
650 | static int | 650 | static int |
651 | parse_branch_mode(const struct option *opt __maybe_unused, | 651 | parse_branch_mode(const struct option *opt, |
652 | const char *str __maybe_unused, int unset) | 652 | const char *str __maybe_unused, int unset) |
653 | { | 653 | { |
654 | int *branch_mode = opt->value; | 654 | int *branch_mode = opt->value; |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 1a3f1be93372..d53e706a6f17 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -200,6 +200,7 @@ struct perf_sched { | |||
200 | /* options for timehist command */ | 200 | /* options for timehist command */ |
201 | bool summary; | 201 | bool summary; |
202 | bool summary_only; | 202 | bool summary_only; |
203 | bool idle_hist; | ||
203 | bool show_callchain; | 204 | bool show_callchain; |
204 | unsigned int max_stack; | 205 | unsigned int max_stack; |
205 | bool show_cpu_visual; | 206 | bool show_cpu_visual; |
@@ -230,6 +231,15 @@ struct evsel_runtime { | |||
230 | u32 ncpu; /* highest cpu slot allocated */ | 231 | u32 ncpu; /* highest cpu slot allocated */ |
231 | }; | 232 | }; |
232 | 233 | ||
234 | /* per cpu idle time data */ | ||
235 | struct idle_thread_runtime { | ||
236 | struct thread_runtime tr; | ||
237 | struct thread *last_thread; | ||
238 | struct rb_root sorted_root; | ||
239 | struct callchain_root callchain; | ||
240 | struct callchain_cursor cursor; | ||
241 | }; | ||
242 | |||
233 | /* track idle times per cpu */ | 243 | /* track idle times per cpu */ |
234 | static struct thread **idle_threads; | 244 | static struct thread **idle_threads; |
235 | static int idle_max_cpu; | 245 | static int idle_max_cpu; |
@@ -1765,7 +1775,7 @@ static u64 perf_evsel__get_time(struct perf_evsel *evsel, u32 cpu) | |||
1765 | return r->last_time[cpu]; | 1775 | return r->last_time[cpu]; |
1766 | } | 1776 | } |
1767 | 1777 | ||
1768 | static int comm_width = 20; | 1778 | static int comm_width = 30; |
1769 | 1779 | ||
1770 | static char *timehist_get_commstr(struct thread *thread) | 1780 | static char *timehist_get_commstr(struct thread *thread) |
1771 | { | 1781 | { |
@@ -1807,7 +1817,7 @@ static void timehist_header(struct perf_sched *sched) | |||
1807 | printf(" "); | 1817 | printf(" "); |
1808 | } | 1818 | } |
1809 | 1819 | ||
1810 | printf(" %-20s %9s %9s %9s", | 1820 | printf(" %-*s %9s %9s %9s", comm_width, |
1811 | "task name", "wait time", "sch delay", "run time"); | 1821 | "task name", "wait time", "sch delay", "run time"); |
1812 | 1822 | ||
1813 | printf("\n"); | 1823 | printf("\n"); |
@@ -1820,7 +1830,8 @@ static void timehist_header(struct perf_sched *sched) | |||
1820 | if (sched->show_cpu_visual) | 1830 | if (sched->show_cpu_visual) |
1821 | printf(" %*s ", ncpus, ""); | 1831 | printf(" %*s ", ncpus, ""); |
1822 | 1832 | ||
1823 | printf(" %-20s %9s %9s %9s\n", "[tid/pid]", "(msec)", "(msec)", "(msec)"); | 1833 | printf(" %-*s %9s %9s %9s\n", comm_width, |
1834 | "[tid/pid]", "(msec)", "(msec)", "(msec)"); | ||
1824 | 1835 | ||
1825 | /* | 1836 | /* |
1826 | * separator | 1837 | * separator |
@@ -1830,7 +1841,7 @@ static void timehist_header(struct perf_sched *sched) | |||
1830 | if (sched->show_cpu_visual) | 1841 | if (sched->show_cpu_visual) |
1831 | printf(" %.*s ", ncpus, graph_dotted_line); | 1842 | printf(" %.*s ", ncpus, graph_dotted_line); |
1832 | 1843 | ||
1833 | printf(" %.20s %.9s %.9s %.9s", | 1844 | printf(" %.*s %.9s %.9s %.9s", comm_width, |
1834 | graph_dotted_line, graph_dotted_line, graph_dotted_line, | 1845 | graph_dotted_line, graph_dotted_line, graph_dotted_line, |
1835 | graph_dotted_line); | 1846 | graph_dotted_line); |
1836 | 1847 | ||
@@ -1939,39 +1950,40 @@ static void timehist_update_runtime_stats(struct thread_runtime *r, | |||
1939 | r->total_run_time += r->dt_run; | 1950 | r->total_run_time += r->dt_run; |
1940 | } | 1951 | } |
1941 | 1952 | ||
1942 | static bool is_idle_sample(struct perf_sched *sched, | 1953 | static bool is_idle_sample(struct perf_sample *sample, |
1943 | struct perf_sample *sample, | 1954 | struct perf_evsel *evsel) |
1944 | struct perf_evsel *evsel, | ||
1945 | struct machine *machine) | ||
1946 | { | 1955 | { |
1947 | struct thread *thread; | ||
1948 | struct callchain_cursor *cursor = &callchain_cursor; | ||
1949 | |||
1950 | /* pid 0 == swapper == idle task */ | 1956 | /* pid 0 == swapper == idle task */ |
1951 | if (sample->pid == 0) | 1957 | if (strcmp(perf_evsel__name(evsel), "sched:sched_switch") == 0) |
1952 | return true; | 1958 | return perf_evsel__intval(evsel, sample, "prev_pid") == 0; |
1953 | 1959 | ||
1954 | if (strcmp(perf_evsel__name(evsel), "sched:sched_switch") == 0) { | 1960 | return sample->pid == 0; |
1955 | if (perf_evsel__intval(evsel, sample, "prev_pid") == 0) | 1961 | } |
1956 | return true; | 1962 | |
1957 | } | 1963 | static void save_task_callchain(struct perf_sched *sched, |
1964 | struct perf_sample *sample, | ||
1965 | struct perf_evsel *evsel, | ||
1966 | struct machine *machine) | ||
1967 | { | ||
1968 | struct callchain_cursor *cursor = &callchain_cursor; | ||
1969 | struct thread *thread; | ||
1958 | 1970 | ||
1959 | /* want main thread for process - has maps */ | 1971 | /* want main thread for process - has maps */ |
1960 | thread = machine__findnew_thread(machine, sample->pid, sample->pid); | 1972 | thread = machine__findnew_thread(machine, sample->pid, sample->pid); |
1961 | if (thread == NULL) { | 1973 | if (thread == NULL) { |
1962 | pr_debug("Failed to get thread for pid %d.\n", sample->pid); | 1974 | pr_debug("Failed to get thread for pid %d.\n", sample->pid); |
1963 | return false; | 1975 | return; |
1964 | } | 1976 | } |
1965 | 1977 | ||
1966 | if (!symbol_conf.use_callchain || sample->callchain == NULL) | 1978 | if (!symbol_conf.use_callchain || sample->callchain == NULL) |
1967 | return false; | 1979 | return; |
1968 | 1980 | ||
1969 | if (thread__resolve_callchain(thread, cursor, evsel, sample, | 1981 | if (thread__resolve_callchain(thread, cursor, evsel, sample, |
1970 | NULL, NULL, sched->max_stack + 2) != 0) { | 1982 | NULL, NULL, sched->max_stack + 2) != 0) { |
1971 | if (verbose) | 1983 | if (verbose) |
1972 | error("Failed to resolve callchain. Skipping\n"); | 1984 | error("Failed to resolve callchain. Skipping\n"); |
1973 | 1985 | ||
1974 | return false; | 1986 | return; |
1975 | } | 1987 | } |
1976 | 1988 | ||
1977 | callchain_cursor_commit(cursor); | 1989 | callchain_cursor_commit(cursor); |
@@ -1994,8 +2006,24 @@ static bool is_idle_sample(struct perf_sched *sched, | |||
1994 | 2006 | ||
1995 | callchain_cursor_advance(cursor); | 2007 | callchain_cursor_advance(cursor); |
1996 | } | 2008 | } |
2009 | } | ||
2010 | |||
2011 | static int init_idle_thread(struct thread *thread) | ||
2012 | { | ||
2013 | struct idle_thread_runtime *itr; | ||
2014 | |||
2015 | thread__set_comm(thread, idle_comm, 0); | ||
2016 | |||
2017 | itr = zalloc(sizeof(*itr)); | ||
2018 | if (itr == NULL) | ||
2019 | return -ENOMEM; | ||
1997 | 2020 | ||
1998 | return false; | 2021 | init_stats(&itr->tr.run_stats); |
2022 | callchain_init(&itr->callchain); | ||
2023 | callchain_cursor_reset(&itr->cursor); | ||
2024 | thread__set_priv(thread, itr); | ||
2025 | |||
2026 | return 0; | ||
1999 | } | 2027 | } |
2000 | 2028 | ||
2001 | /* | 2029 | /* |
@@ -2004,7 +2032,7 @@ static bool is_idle_sample(struct perf_sched *sched, | |||
2004 | */ | 2032 | */ |
2005 | static int init_idle_threads(int ncpu) | 2033 | static int init_idle_threads(int ncpu) |
2006 | { | 2034 | { |
2007 | int i; | 2035 | int i, ret; |
2008 | 2036 | ||
2009 | idle_threads = zalloc(ncpu * sizeof(struct thread *)); | 2037 | idle_threads = zalloc(ncpu * sizeof(struct thread *)); |
2010 | if (!idle_threads) | 2038 | if (!idle_threads) |
@@ -2018,7 +2046,9 @@ static int init_idle_threads(int ncpu) | |||
2018 | if (idle_threads[i] == NULL) | 2046 | if (idle_threads[i] == NULL) |
2019 | return -ENOMEM; | 2047 | return -ENOMEM; |
2020 | 2048 | ||
2021 | thread__set_comm(idle_threads[i], idle_comm, 0); | 2049 | ret = init_idle_thread(idle_threads[i]); |
2050 | if (ret < 0) | ||
2051 | return ret; | ||
2022 | } | 2052 | } |
2023 | 2053 | ||
2024 | return 0; | 2054 | return 0; |
@@ -2065,14 +2095,23 @@ static struct thread *get_idle_thread(int cpu) | |||
2065 | idle_threads[cpu] = thread__new(0, 0); | 2095 | idle_threads[cpu] = thread__new(0, 0); |
2066 | 2096 | ||
2067 | if (idle_threads[cpu]) { | 2097 | if (idle_threads[cpu]) { |
2068 | idle_threads[cpu]->tid = 0; | 2098 | if (init_idle_thread(idle_threads[cpu]) < 0) |
2069 | thread__set_comm(idle_threads[cpu], idle_comm, 0); | 2099 | return NULL; |
2070 | } | 2100 | } |
2071 | } | 2101 | } |
2072 | 2102 | ||
2073 | return idle_threads[cpu]; | 2103 | return idle_threads[cpu]; |
2074 | } | 2104 | } |
2075 | 2105 | ||
2106 | static void save_idle_callchain(struct idle_thread_runtime *itr, | ||
2107 | struct perf_sample *sample) | ||
2108 | { | ||
2109 | if (!symbol_conf.use_callchain || sample->callchain == NULL) | ||
2110 | return; | ||
2111 | |||
2112 | callchain_cursor__copy(&itr->cursor, &callchain_cursor); | ||
2113 | } | ||
2114 | |||
2076 | /* | 2115 | /* |
2077 | * handle runtime stats saved per thread | 2116 | * handle runtime stats saved per thread |
2078 | */ | 2117 | */ |
@@ -2111,7 +2150,7 @@ static struct thread *timehist_get_thread(struct perf_sched *sched, | |||
2111 | { | 2150 | { |
2112 | struct thread *thread; | 2151 | struct thread *thread; |
2113 | 2152 | ||
2114 | if (is_idle_sample(sched, sample, evsel, machine)) { | 2153 | if (is_idle_sample(sample, evsel)) { |
2115 | thread = get_idle_thread(sample->cpu); | 2154 | thread = get_idle_thread(sample->cpu); |
2116 | if (thread == NULL) | 2155 | if (thread == NULL) |
2117 | pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); | 2156 | pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); |
@@ -2124,13 +2163,37 @@ static struct thread *timehist_get_thread(struct perf_sched *sched, | |||
2124 | pr_debug("Failed to get thread for tid %d. skipping sample.\n", | 2163 | pr_debug("Failed to get thread for tid %d. skipping sample.\n", |
2125 | sample->tid); | 2164 | sample->tid); |
2126 | } | 2165 | } |
2166 | |||
2167 | save_task_callchain(sched, sample, evsel, machine); | ||
2168 | if (sched->idle_hist) { | ||
2169 | struct thread *idle; | ||
2170 | struct idle_thread_runtime *itr; | ||
2171 | |||
2172 | idle = get_idle_thread(sample->cpu); | ||
2173 | if (idle == NULL) { | ||
2174 | pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); | ||
2175 | return NULL; | ||
2176 | } | ||
2177 | |||
2178 | itr = thread__priv(idle); | ||
2179 | if (itr == NULL) | ||
2180 | return NULL; | ||
2181 | |||
2182 | itr->last_thread = thread; | ||
2183 | |||
2184 | /* copy task callchain when entering to idle */ | ||
2185 | if (perf_evsel__intval(evsel, sample, "next_pid") == 0) | ||
2186 | save_idle_callchain(itr, sample); | ||
2187 | } | ||
2127 | } | 2188 | } |
2128 | 2189 | ||
2129 | return thread; | 2190 | return thread; |
2130 | } | 2191 | } |
2131 | 2192 | ||
2132 | static bool timehist_skip_sample(struct perf_sched *sched, | 2193 | static bool timehist_skip_sample(struct perf_sched *sched, |
2133 | struct thread *thread) | 2194 | struct thread *thread, |
2195 | struct perf_evsel *evsel, | ||
2196 | struct perf_sample *sample) | ||
2134 | { | 2197 | { |
2135 | bool rc = false; | 2198 | bool rc = false; |
2136 | 2199 | ||
@@ -2139,10 +2202,19 @@ static bool timehist_skip_sample(struct perf_sched *sched, | |||
2139 | sched->skipped_samples++; | 2202 | sched->skipped_samples++; |
2140 | } | 2203 | } |
2141 | 2204 | ||
2205 | if (sched->idle_hist) { | ||
2206 | if (strcmp(perf_evsel__name(evsel), "sched:sched_switch")) | ||
2207 | rc = true; | ||
2208 | else if (perf_evsel__intval(evsel, sample, "prev_pid") != 0 && | ||
2209 | perf_evsel__intval(evsel, sample, "next_pid") != 0) | ||
2210 | rc = true; | ||
2211 | } | ||
2212 | |||
2142 | return rc; | 2213 | return rc; |
2143 | } | 2214 | } |
2144 | 2215 | ||
2145 | static void timehist_print_wakeup_event(struct perf_sched *sched, | 2216 | static void timehist_print_wakeup_event(struct perf_sched *sched, |
2217 | struct perf_evsel *evsel, | ||
2146 | struct perf_sample *sample, | 2218 | struct perf_sample *sample, |
2147 | struct machine *machine, | 2219 | struct machine *machine, |
2148 | struct thread *awakened) | 2220 | struct thread *awakened) |
@@ -2155,8 +2227,8 @@ static void timehist_print_wakeup_event(struct perf_sched *sched, | |||
2155 | return; | 2227 | return; |
2156 | 2228 | ||
2157 | /* show wakeup unless both awakee and awaker are filtered */ | 2229 | /* show wakeup unless both awakee and awaker are filtered */ |
2158 | if (timehist_skip_sample(sched, thread) && | 2230 | if (timehist_skip_sample(sched, thread, evsel, sample) && |
2159 | timehist_skip_sample(sched, awakened)) { | 2231 | timehist_skip_sample(sched, awakened, evsel, sample)) { |
2160 | return; | 2232 | return; |
2161 | } | 2233 | } |
2162 | 2234 | ||
@@ -2201,7 +2273,7 @@ static int timehist_sched_wakeup_event(struct perf_tool *tool, | |||
2201 | /* show wakeups if requested */ | 2273 | /* show wakeups if requested */ |
2202 | if (sched->show_wakeups && | 2274 | if (sched->show_wakeups && |
2203 | !perf_time__skip_sample(&sched->ptime, sample->time)) | 2275 | !perf_time__skip_sample(&sched->ptime, sample->time)) |
2204 | timehist_print_wakeup_event(sched, sample, machine, thread); | 2276 | timehist_print_wakeup_event(sched, evsel, sample, machine, thread); |
2205 | 2277 | ||
2206 | return 0; | 2278 | return 0; |
2207 | } | 2279 | } |
@@ -2228,8 +2300,8 @@ static void timehist_print_migration_event(struct perf_sched *sched, | |||
2228 | if (thread == NULL) | 2300 | if (thread == NULL) |
2229 | return; | 2301 | return; |
2230 | 2302 | ||
2231 | if (timehist_skip_sample(sched, thread) && | 2303 | if (timehist_skip_sample(sched, thread, evsel, sample) && |
2232 | timehist_skip_sample(sched, migrated)) { | 2304 | timehist_skip_sample(sched, migrated, evsel, sample)) { |
2233 | return; | 2305 | return; |
2234 | } | 2306 | } |
2235 | 2307 | ||
@@ -2314,7 +2386,7 @@ static int timehist_sched_change_event(struct perf_tool *tool, | |||
2314 | goto out; | 2386 | goto out; |
2315 | } | 2387 | } |
2316 | 2388 | ||
2317 | if (timehist_skip_sample(sched, thread)) | 2389 | if (timehist_skip_sample(sched, thread, evsel, sample)) |
2318 | goto out; | 2390 | goto out; |
2319 | 2391 | ||
2320 | tr = thread__get_runtime(thread); | 2392 | tr = thread__get_runtime(thread); |
@@ -2333,7 +2405,7 @@ static int timehist_sched_change_event(struct perf_tool *tool, | |||
2333 | if (ptime->start && ptime->start > t) | 2405 | if (ptime->start && ptime->start > t) |
2334 | goto out; | 2406 | goto out; |
2335 | 2407 | ||
2336 | if (ptime->start > tprev) | 2408 | if (tprev && ptime->start > tprev) |
2337 | tprev = ptime->start; | 2409 | tprev = ptime->start; |
2338 | 2410 | ||
2339 | /* | 2411 | /* |
@@ -2350,7 +2422,39 @@ static int timehist_sched_change_event(struct perf_tool *tool, | |||
2350 | t = ptime->end; | 2422 | t = ptime->end; |
2351 | } | 2423 | } |
2352 | 2424 | ||
2353 | timehist_update_runtime_stats(tr, t, tprev); | 2425 | if (!sched->idle_hist || thread->tid == 0) { |
2426 | timehist_update_runtime_stats(tr, t, tprev); | ||
2427 | |||
2428 | if (sched->idle_hist) { | ||
2429 | struct idle_thread_runtime *itr = (void *)tr; | ||
2430 | struct thread_runtime *last_tr; | ||
2431 | |||
2432 | BUG_ON(thread->tid != 0); | ||
2433 | |||
2434 | if (itr->last_thread == NULL) | ||
2435 | goto out; | ||
2436 | |||
2437 | /* add current idle time as last thread's runtime */ | ||
2438 | last_tr = thread__get_runtime(itr->last_thread); | ||
2439 | if (last_tr == NULL) | ||
2440 | goto out; | ||
2441 | |||
2442 | timehist_update_runtime_stats(last_tr, t, tprev); | ||
2443 | /* | ||
2444 | * remove delta time of last thread as it's not updated | ||
2445 | * and otherwise it will show an invalid value next | ||
2446 | * time. we only care total run time and run stat. | ||
2447 | */ | ||
2448 | last_tr->dt_run = 0; | ||
2449 | last_tr->dt_wait = 0; | ||
2450 | last_tr->dt_delay = 0; | ||
2451 | |||
2452 | if (itr->cursor.nr) | ||
2453 | callchain_append(&itr->callchain, &itr->cursor, t - tprev); | ||
2454 | |||
2455 | itr->last_thread = NULL; | ||
2456 | } | ||
2457 | } | ||
2354 | 2458 | ||
2355 | if (!sched->summary_only) | 2459 | if (!sched->summary_only) |
2356 | timehist_print_sample(sched, sample, &al, thread, t); | 2460 | timehist_print_sample(sched, sample, &al, thread, t); |
@@ -2457,6 +2561,60 @@ static int show_deadthread_runtime(struct thread *t, void *priv) | |||
2457 | return __show_thread_runtime(t, priv); | 2561 | return __show_thread_runtime(t, priv); |
2458 | } | 2562 | } |
2459 | 2563 | ||
2564 | static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node) | ||
2565 | { | ||
2566 | const char *sep = " <- "; | ||
2567 | struct callchain_list *chain; | ||
2568 | size_t ret = 0; | ||
2569 | char bf[1024]; | ||
2570 | bool first; | ||
2571 | |||
2572 | if (node == NULL) | ||
2573 | return 0; | ||
2574 | |||
2575 | ret = callchain__fprintf_folded(fp, node->parent); | ||
2576 | first = (ret == 0); | ||
2577 | |||
2578 | list_for_each_entry(chain, &node->val, list) { | ||
2579 | if (chain->ip >= PERF_CONTEXT_MAX) | ||
2580 | continue; | ||
2581 | if (chain->ms.sym && chain->ms.sym->ignore) | ||
2582 | continue; | ||
2583 | ret += fprintf(fp, "%s%s", first ? "" : sep, | ||
2584 | callchain_list__sym_name(chain, bf, sizeof(bf), | ||
2585 | false)); | ||
2586 | first = false; | ||
2587 | } | ||
2588 | |||
2589 | return ret; | ||
2590 | } | ||
2591 | |||
2592 | static size_t timehist_print_idlehist_callchain(struct rb_root *root) | ||
2593 | { | ||
2594 | size_t ret = 0; | ||
2595 | FILE *fp = stdout; | ||
2596 | struct callchain_node *chain; | ||
2597 | struct rb_node *rb_node = rb_first(root); | ||
2598 | |||
2599 | printf(" %16s %8s %s\n", "Idle time (msec)", "Count", "Callchains"); | ||
2600 | printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line, | ||
2601 | graph_dotted_line); | ||
2602 | |||
2603 | while (rb_node) { | ||
2604 | chain = rb_entry(rb_node, struct callchain_node, rb_node); | ||
2605 | rb_node = rb_next(rb_node); | ||
2606 | |||
2607 | ret += fprintf(fp, " "); | ||
2608 | print_sched_time(chain->hit, 12); | ||
2609 | ret += 16; /* print_sched_time returns 2nd arg + 4 */ | ||
2610 | ret += fprintf(fp, " %8d ", chain->count); | ||
2611 | ret += callchain__fprintf_folded(fp, chain); | ||
2612 | ret += fprintf(fp, "\n"); | ||
2613 | } | ||
2614 | |||
2615 | return ret; | ||
2616 | } | ||
2617 | |||
2460 | static void timehist_print_summary(struct perf_sched *sched, | 2618 | static void timehist_print_summary(struct perf_sched *sched, |
2461 | struct perf_session *session) | 2619 | struct perf_session *session) |
2462 | { | 2620 | { |
@@ -2469,12 +2627,15 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
2469 | 2627 | ||
2470 | memset(&totals, 0, sizeof(totals)); | 2628 | memset(&totals, 0, sizeof(totals)); |
2471 | 2629 | ||
2472 | if (comm_width < 30) | 2630 | if (sched->idle_hist) { |
2473 | comm_width = 30; | 2631 | printf("\nIdle-time summary\n"); |
2474 | 2632 | printf("%*s parent sched-out ", comm_width, "comm"); | |
2475 | printf("\nRuntime summary\n"); | 2633 | printf(" idle-time min-idle avg-idle max-idle stddev migrations\n"); |
2476 | printf("%*s parent sched-in ", comm_width, "comm"); | 2634 | } else { |
2477 | printf(" run-time min-run avg-run max-run stddev migrations\n"); | 2635 | printf("\nRuntime summary\n"); |
2636 | printf("%*s parent sched-in ", comm_width, "comm"); | ||
2637 | printf(" run-time min-run avg-run max-run stddev migrations\n"); | ||
2638 | } | ||
2478 | printf("%*s (count) ", comm_width, ""); | 2639 | printf("%*s (count) ", comm_width, ""); |
2479 | printf(" (msec) (msec) (msec) (msec) %%\n"); | 2640 | printf(" (msec) (msec) (msec) (msec) %%\n"); |
2480 | printf("%.117s\n", graph_dotted_line); | 2641 | printf("%.117s\n", graph_dotted_line); |
@@ -2490,7 +2651,7 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
2490 | printf("<no terminated tasks>\n"); | 2651 | printf("<no terminated tasks>\n"); |
2491 | 2652 | ||
2492 | /* CPU idle stats not tracked when samples were skipped */ | 2653 | /* CPU idle stats not tracked when samples were skipped */ |
2493 | if (sched->skipped_samples) | 2654 | if (sched->skipped_samples && !sched->idle_hist) |
2494 | return; | 2655 | return; |
2495 | 2656 | ||
2496 | printf("\nIdle stats:\n"); | 2657 | printf("\nIdle stats:\n"); |
@@ -2509,6 +2670,35 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
2509 | printf(" CPU %2d idle entire time window\n", i); | 2670 | printf(" CPU %2d idle entire time window\n", i); |
2510 | } | 2671 | } |
2511 | 2672 | ||
2673 | if (sched->idle_hist && symbol_conf.use_callchain) { | ||
2674 | callchain_param.mode = CHAIN_FOLDED; | ||
2675 | callchain_param.value = CCVAL_PERIOD; | ||
2676 | |||
2677 | callchain_register_param(&callchain_param); | ||
2678 | |||
2679 | printf("\nIdle stats by callchain:\n"); | ||
2680 | for (i = 0; i < idle_max_cpu; ++i) { | ||
2681 | struct idle_thread_runtime *itr; | ||
2682 | |||
2683 | t = idle_threads[i]; | ||
2684 | if (!t) | ||
2685 | continue; | ||
2686 | |||
2687 | itr = thread__priv(t); | ||
2688 | if (itr == NULL) | ||
2689 | continue; | ||
2690 | |||
2691 | callchain_param.sort(&itr->sorted_root, &itr->callchain, | ||
2692 | 0, &callchain_param); | ||
2693 | |||
2694 | printf(" CPU %2d:", i); | ||
2695 | print_sched_time(itr->tr.total_run_time, 6); | ||
2696 | printf(" msec\n"); | ||
2697 | timehist_print_idlehist_callchain(&itr->sorted_root); | ||
2698 | printf("\n"); | ||
2699 | } | ||
2700 | } | ||
2701 | |||
2512 | printf("\n" | 2702 | printf("\n" |
2513 | " Total number of unique tasks: %" PRIu64 "\n" | 2703 | " Total number of unique tasks: %" PRIu64 "\n" |
2514 | "Total number of context switches: %" PRIu64 "\n" | 2704 | "Total number of context switches: %" PRIu64 "\n" |
@@ -3036,6 +3226,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3036 | OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), | 3226 | OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), |
3037 | OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), | 3227 | OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), |
3038 | OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), | 3228 | OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), |
3229 | OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"), | ||
3039 | OPT_STRING(0, "time", &sched.time_str, "str", | 3230 | OPT_STRING(0, "time", &sched.time_str, "str", |
3040 | "Time span for analysis (start,stop)"), | 3231 | "Time span for analysis (start,stop)"), |
3041 | OPT_PARENT(sched_options) | 3232 | OPT_PARENT(sched_options) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 688dea7cb08f..a02f2e965628 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -2195,7 +2195,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, | |||
2195 | } | 2195 | } |
2196 | 2196 | ||
2197 | static | 2197 | static |
2198 | int process_stat_config_event(struct perf_tool *tool __maybe_unused, | 2198 | int process_stat_config_event(struct perf_tool *tool, |
2199 | union perf_event *event, | 2199 | union perf_event *event, |
2200 | struct perf_session *session __maybe_unused) | 2200 | struct perf_session *session __maybe_unused) |
2201 | { | 2201 | { |
@@ -2238,7 +2238,7 @@ static int set_maps(struct perf_stat *st) | |||
2238 | } | 2238 | } |
2239 | 2239 | ||
2240 | static | 2240 | static |
2241 | int process_thread_map_event(struct perf_tool *tool __maybe_unused, | 2241 | int process_thread_map_event(struct perf_tool *tool, |
2242 | union perf_event *event, | 2242 | union perf_event *event, |
2243 | struct perf_session *session __maybe_unused) | 2243 | struct perf_session *session __maybe_unused) |
2244 | { | 2244 | { |
@@ -2257,7 +2257,7 @@ int process_thread_map_event(struct perf_tool *tool __maybe_unused, | |||
2257 | } | 2257 | } |
2258 | 2258 | ||
2259 | static | 2259 | static |
2260 | int process_cpu_map_event(struct perf_tool *tool __maybe_unused, | 2260 | int process_cpu_map_event(struct perf_tool *tool, |
2261 | union perf_event *event, | 2261 | union perf_event *event, |
2262 | struct perf_session *session __maybe_unused) | 2262 | struct perf_session *session __maybe_unused) |
2263 | { | 2263 | { |
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh new file mode 100755 index 000000000000..c747bfd7f14d --- /dev/null +++ b/tools/perf/check-headers.sh | |||
@@ -0,0 +1,59 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | HEADERS=' | ||
4 | include/uapi/linux/perf_event.h | ||
5 | include/linux/hash.h | ||
6 | include/uapi/linux/hw_breakpoint.h | ||
7 | arch/x86/include/asm/disabled-features.h | ||
8 | arch/x86/include/asm/required-features.h | ||
9 | arch/x86/include/asm/cpufeatures.h | ||
10 | arch/arm/include/uapi/asm/perf_regs.h | ||
11 | arch/arm64/include/uapi/asm/perf_regs.h | ||
12 | arch/powerpc/include/uapi/asm/perf_regs.h | ||
13 | arch/x86/include/uapi/asm/perf_regs.h | ||
14 | arch/x86/include/uapi/asm/kvm.h | ||
15 | arch/x86/include/uapi/asm/kvm_perf.h | ||
16 | arch/x86/include/uapi/asm/svm.h | ||
17 | arch/x86/include/uapi/asm/vmx.h | ||
18 | arch/powerpc/include/uapi/asm/kvm.h | ||
19 | arch/s390/include/uapi/asm/kvm.h | ||
20 | arch/s390/include/uapi/asm/kvm_perf.h | ||
21 | arch/s390/include/uapi/asm/sie.h | ||
22 | arch/arm/include/uapi/asm/kvm.h | ||
23 | arch/arm64/include/uapi/asm/kvm.h | ||
24 | include/asm-generic/bitops/arch_hweight.h | ||
25 | include/asm-generic/bitops/const_hweight.h | ||
26 | include/asm-generic/bitops/__fls.h | ||
27 | include/asm-generic/bitops/fls.h | ||
28 | include/asm-generic/bitops/fls64.h | ||
29 | include/linux/coresight-pmu.h | ||
30 | include/uapi/asm-generic/mman-common.h | ||
31 | ' | ||
32 | |||
33 | check () { | ||
34 | file=$1 | ||
35 | opts= | ||
36 | |||
37 | shift | ||
38 | while [ -n "$*" ]; do | ||
39 | opts="$opts \"$1\"" | ||
40 | shift | ||
41 | done | ||
42 | |||
43 | cmd="diff $opts ../$file ../../$file > /dev/null" | ||
44 | |||
45 | test -f ../../$file && | ||
46 | eval $cmd || echo "Warning: $file differs from kernel" >&2 | ||
47 | } | ||
48 | |||
49 | |||
50 | # simple diff check | ||
51 | for i in $HEADERS; do | ||
52 | check $i -B | ||
53 | done | ||
54 | |||
55 | # diff with extra ignore lines | ||
56 | check arch/x86/lib/memcpy_64.S -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" | ||
57 | check arch/x86/lib/memset_64.S -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" | ||
58 | check include/uapi/asm-generic/mman.h -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>" | ||
59 | check include/uapi/linux/mman.h -B -I "^#include <\(uapi/\)*asm/mman.h>" | ||
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 9a0236a4cf95..1c27d947c2fe 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -55,6 +55,7 @@ struct record_opts { | |||
55 | bool all_user; | 55 | bool all_user; |
56 | bool tail_synthesize; | 56 | bool tail_synthesize; |
57 | bool overwrite; | 57 | bool overwrite; |
58 | bool ignore_missing_thread; | ||
58 | unsigned int freq; | 59 | unsigned int freq; |
59 | unsigned int mmap_pages; | 60 | unsigned int mmap_pages; |
60 | unsigned int auxtrace_mmap_pages; | 61 | unsigned int auxtrace_mmap_pages; |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 23605202d4a1..a77dcc0d24e3 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -186,6 +186,10 @@ static struct test generic_tests[] = { | |||
186 | .func = test__thread_map_synthesize, | 186 | .func = test__thread_map_synthesize, |
187 | }, | 187 | }, |
188 | { | 188 | { |
189 | .desc = "Remove thread map", | ||
190 | .func = test__thread_map_remove, | ||
191 | }, | ||
192 | { | ||
189 | .desc = "Synthesize cpu map", | 193 | .desc = "Synthesize cpu map", |
190 | .func = test__cpu_map_synthesize, | 194 | .func = test__cpu_map_synthesize, |
191 | }, | 195 | }, |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 0d7b251305af..a512f0c8ff5b 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -80,6 +80,7 @@ const char *test__bpf_subtest_get_desc(int subtest); | |||
80 | int test__bpf_subtest_get_nr(void); | 80 | int test__bpf_subtest_get_nr(void); |
81 | int test_session_topology(int subtest); | 81 | int test_session_topology(int subtest); |
82 | int test__thread_map_synthesize(int subtest); | 82 | int test__thread_map_synthesize(int subtest); |
83 | int test__thread_map_remove(int subtest); | ||
83 | int test__cpu_map_synthesize(int subtest); | 84 | int test__cpu_map_synthesize(int subtest); |
84 | int test__synthesize_stat_config(int subtest); | 85 | int test__synthesize_stat_config(int subtest); |
85 | int test__synthesize_stat(int subtest); | 86 | int test__synthesize_stat(int subtest); |
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c index cee2a2cdc933..a4a4b4625ac3 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <stdlib.h> | ||
1 | #include <sys/types.h> | 2 | #include <sys/types.h> |
2 | #include <unistd.h> | 3 | #include <unistd.h> |
3 | #include <sys/prctl.h> | 4 | #include <sys/prctl.h> |
@@ -93,3 +94,46 @@ int test__thread_map_synthesize(int subtest __maybe_unused) | |||
93 | 94 | ||
94 | return 0; | 95 | return 0; |
95 | } | 96 | } |
97 | |||
98 | int test__thread_map_remove(int subtest __maybe_unused) | ||
99 | { | ||
100 | struct thread_map *threads; | ||
101 | char *str; | ||
102 | int i; | ||
103 | |||
104 | TEST_ASSERT_VAL("failed to allocate map string", | ||
105 | asprintf(&str, "%d,%d", getpid(), getppid()) >= 0); | ||
106 | |||
107 | threads = thread_map__new_str(str, NULL, 0); | ||
108 | |||
109 | TEST_ASSERT_VAL("failed to allocate thread_map", | ||
110 | threads); | ||
111 | |||
112 | if (verbose) | ||
113 | thread_map__fprintf(threads, stderr); | ||
114 | |||
115 | TEST_ASSERT_VAL("failed to remove thread", | ||
116 | !thread_map__remove(threads, 0)); | ||
117 | |||
118 | TEST_ASSERT_VAL("thread_map count != 1", threads->nr == 1); | ||
119 | |||
120 | if (verbose) | ||
121 | thread_map__fprintf(threads, stderr); | ||
122 | |||
123 | TEST_ASSERT_VAL("failed to remove thread", | ||
124 | !thread_map__remove(threads, 0)); | ||
125 | |||
126 | TEST_ASSERT_VAL("thread_map count != 0", threads->nr == 0); | ||
127 | |||
128 | if (verbose) | ||
129 | thread_map__fprintf(threads, stderr); | ||
130 | |||
131 | TEST_ASSERT_VAL("failed to not remove thread", | ||
132 | thread_map__remove(threads, 0)); | ||
133 | |||
134 | for (i = 0; i < threads->nr; i++) | ||
135 | free(threads->map[i].comm); | ||
136 | |||
137 | free(threads); | ||
138 | return 0; | ||
139 | } | ||
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c index fd710ab33684..af1cfde6b97b 100644 --- a/tools/perf/trace/beauty/mmap.c +++ b/tools/perf/trace/beauty/mmap.c | |||
@@ -42,7 +42,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | |||
42 | 42 | ||
43 | P_MMAP_FLAG(SHARED); | 43 | P_MMAP_FLAG(SHARED); |
44 | P_MMAP_FLAG(PRIVATE); | 44 | P_MMAP_FLAG(PRIVATE); |
45 | #ifdef MAP_32BIT | ||
45 | P_MMAP_FLAG(32BIT); | 46 | P_MMAP_FLAG(32BIT); |
47 | #endif | ||
46 | P_MMAP_FLAG(ANONYMOUS); | 48 | P_MMAP_FLAG(ANONYMOUS); |
47 | P_MMAP_FLAG(DENYWRITE); | 49 | P_MMAP_FLAG(DENYWRITE); |
48 | P_MMAP_FLAG(EXECUTABLE); | 50 | P_MMAP_FLAG(EXECUTABLE); |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ec7a30fad149..ba36aac340bc 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -215,7 +215,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
215 | ui_browser__set_color(browser, color); | 215 | ui_browser__set_color(browser, color); |
216 | if (dl->ins.ops && dl->ins.ops->scnprintf) { | 216 | if (dl->ins.ops && dl->ins.ops->scnprintf) { |
217 | if (ins__is_jump(&dl->ins)) { | 217 | if (ins__is_jump(&dl->ins)) { |
218 | bool fwd = dl->ops.target.offset > (u64)dl->offset; | 218 | bool fwd = dl->ops.target.offset > dl->offset; |
219 | 219 | ||
220 | ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : | 220 | ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : |
221 | SLSMG_UARROW_CHAR); | 221 | SLSMG_UARROW_CHAR); |
@@ -245,7 +245,8 @@ static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sy | |||
245 | { | 245 | { |
246 | if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) | 246 | if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) |
247 | || !disasm_line__has_offset(dl) | 247 | || !disasm_line__has_offset(dl) |
248 | || dl->ops.target.offset >= symbol__size(sym)) | 248 | || dl->ops.target.offset < 0 |
249 | || dl->ops.target.offset >= (s64)symbol__size(sym)) | ||
249 | return false; | 250 | return false; |
250 | 251 | ||
251 | return true; | 252 | return true; |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ea7e0de4b9c1..06cc04e5806a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -223,13 +223,19 @@ bool ins__is_call(const struct ins *ins) | |||
223 | static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) | 223 | static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) |
224 | { | 224 | { |
225 | const char *s = strchr(ops->raw, '+'); | 225 | const char *s = strchr(ops->raw, '+'); |
226 | const char *c = strchr(ops->raw, ','); | ||
226 | 227 | ||
227 | ops->target.addr = strtoull(ops->raw, NULL, 16); | 228 | if (c++ != NULL) |
229 | ops->target.addr = strtoull(c, NULL, 16); | ||
230 | else | ||
231 | ops->target.addr = strtoull(ops->raw, NULL, 16); | ||
228 | 232 | ||
229 | if (s++ != NULL) | 233 | if (s++ != NULL) { |
230 | ops->target.offset = strtoull(s, NULL, 16); | 234 | ops->target.offset = strtoull(s, NULL, 16); |
231 | else | 235 | ops->target.offset_avail = true; |
232 | ops->target.offset = UINT64_MAX; | 236 | } else { |
237 | ops->target.offset_avail = false; | ||
238 | } | ||
233 | 239 | ||
234 | return 0; | 240 | return 0; |
235 | } | 241 | } |
@@ -237,7 +243,7 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op | |||
237 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | 243 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, |
238 | struct ins_operands *ops) | 244 | struct ins_operands *ops) |
239 | { | 245 | { |
240 | if (!ops->target.addr) | 246 | if (!ops->target.addr || ops->target.offset < 0) |
241 | return ins__raw_scnprintf(ins, bf, size, ops); | 247 | return ins__raw_scnprintf(ins, bf, size, ops); |
242 | 248 | ||
243 | return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); | 249 | return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); |
@@ -641,7 +647,8 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
641 | 647 | ||
642 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); | 648 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); |
643 | 649 | ||
644 | if (addr < sym->start || addr >= sym->end) { | 650 | if ((addr < sym->start || addr >= sym->end) && |
651 | (addr != sym->end || sym->start != sym->end)) { | ||
645 | pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", | 652 | pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", |
646 | __func__, __LINE__, sym->name, sym->start, addr, sym->end); | 653 | __func__, __LINE__, sym->name, sym->start, addr, sym->end); |
647 | return -ERANGE; | 654 | return -ERANGE; |
@@ -1205,9 +1212,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
1205 | if (dl == NULL) | 1212 | if (dl == NULL) |
1206 | return -1; | 1213 | return -1; |
1207 | 1214 | ||
1208 | if (dl->ops.target.offset == UINT64_MAX) | 1215 | if (!disasm_line__has_offset(dl)) { |
1209 | dl->ops.target.offset = dl->ops.target.addr - | 1216 | dl->ops.target.offset = dl->ops.target.addr - |
1210 | map__rip_2objdump(map, sym->start); | 1217 | map__rip_2objdump(map, sym->start); |
1218 | dl->ops.target.offset_avail = true; | ||
1219 | } | ||
1211 | 1220 | ||
1212 | /* kcore has no symbols, so add the call target name */ | 1221 | /* kcore has no symbols, so add the call target name */ |
1213 | if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) { | 1222 | if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) { |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 87e4cadc5d27..09776b5af991 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -24,7 +24,8 @@ struct ins_operands { | |||
24 | char *raw; | 24 | char *raw; |
25 | char *name; | 25 | char *name; |
26 | u64 addr; | 26 | u64 addr; |
27 | u64 offset; | 27 | s64 offset; |
28 | bool offset_avail; | ||
28 | } target; | 29 | } target; |
29 | union { | 30 | union { |
30 | struct { | 31 | struct { |
@@ -68,7 +69,7 @@ struct disasm_line { | |||
68 | 69 | ||
69 | static inline bool disasm_line__has_offset(const struct disasm_line *dl) | 70 | static inline bool disasm_line__has_offset(const struct disasm_line *dl) |
70 | { | 71 | { |
71 | return dl->ops.target.offset != UINT64_MAX; | 72 | return dl->ops.target.offset_avail; |
72 | } | 73 | } |
73 | 74 | ||
74 | void disasm_line__free(struct disasm_line *dl); | 75 | void disasm_line__free(struct disasm_line *dl); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b2365a63db45..04e536ae4d88 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -990,6 +990,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, | |||
990 | * it overloads any global configuration. | 990 | * it overloads any global configuration. |
991 | */ | 991 | */ |
992 | apply_config_terms(evsel, opts); | 992 | apply_config_terms(evsel, opts); |
993 | |||
994 | evsel->ignore_missing_thread = opts->ignore_missing_thread; | ||
993 | } | 995 | } |
994 | 996 | ||
995 | static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 997 | static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -1419,6 +1421,33 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, | |||
1419 | return fprintf(fp, " %-32s %s\n", name, val); | 1421 | return fprintf(fp, " %-32s %s\n", name, val); |
1420 | } | 1422 | } |
1421 | 1423 | ||
1424 | static bool ignore_missing_thread(struct perf_evsel *evsel, | ||
1425 | struct thread_map *threads, | ||
1426 | int thread, int err) | ||
1427 | { | ||
1428 | if (!evsel->ignore_missing_thread) | ||
1429 | return false; | ||
1430 | |||
1431 | /* The system wide setup does not work with threads. */ | ||
1432 | if (evsel->system_wide) | ||
1433 | return false; | ||
1434 | |||
1435 | /* The -ESRCH is perf event syscall errno for pid's not found. */ | ||
1436 | if (err != -ESRCH) | ||
1437 | return false; | ||
1438 | |||
1439 | /* If there's only one thread, let it fail. */ | ||
1440 | if (threads->nr == 1) | ||
1441 | return false; | ||
1442 | |||
1443 | if (thread_map__remove(threads, thread)) | ||
1444 | return false; | ||
1445 | |||
1446 | pr_warning("WARNING: Ignored open failure for pid %d\n", | ||
1447 | thread_map__pid(threads, thread)); | ||
1448 | return true; | ||
1449 | } | ||
1450 | |||
1422 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 1451 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
1423 | struct thread_map *threads) | 1452 | struct thread_map *threads) |
1424 | { | 1453 | { |
@@ -1474,7 +1503,7 @@ retry_sample_id: | |||
1474 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 1503 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
1475 | 1504 | ||
1476 | for (thread = 0; thread < nthreads; thread++) { | 1505 | for (thread = 0; thread < nthreads; thread++) { |
1477 | int group_fd; | 1506 | int fd, group_fd; |
1478 | 1507 | ||
1479 | if (!evsel->cgrp && !evsel->system_wide) | 1508 | if (!evsel->cgrp && !evsel->system_wide) |
1480 | pid = thread_map__pid(threads, thread); | 1509 | pid = thread_map__pid(threads, thread); |
@@ -1484,21 +1513,37 @@ retry_open: | |||
1484 | pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", | 1513 | pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", |
1485 | pid, cpus->map[cpu], group_fd, flags); | 1514 | pid, cpus->map[cpu], group_fd, flags); |
1486 | 1515 | ||
1487 | FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, | 1516 | fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu], |
1488 | pid, | 1517 | group_fd, flags); |
1489 | cpus->map[cpu], | 1518 | |
1490 | group_fd, flags); | 1519 | FD(evsel, cpu, thread) = fd; |
1491 | if (FD(evsel, cpu, thread) < 0) { | 1520 | |
1521 | if (fd < 0) { | ||
1492 | err = -errno; | 1522 | err = -errno; |
1523 | |||
1524 | if (ignore_missing_thread(evsel, threads, thread, err)) { | ||
1525 | /* | ||
1526 | * We just removed 1 thread, so take a step | ||
1527 | * back on thread index and lower the upper | ||
1528 | * nthreads limit. | ||
1529 | */ | ||
1530 | nthreads--; | ||
1531 | thread--; | ||
1532 | |||
1533 | /* ... and pretend like nothing have happened. */ | ||
1534 | err = 0; | ||
1535 | continue; | ||
1536 | } | ||
1537 | |||
1493 | pr_debug2("\nsys_perf_event_open failed, error %d\n", | 1538 | pr_debug2("\nsys_perf_event_open failed, error %d\n", |
1494 | err); | 1539 | err); |
1495 | goto try_fallback; | 1540 | goto try_fallback; |
1496 | } | 1541 | } |
1497 | 1542 | ||
1498 | pr_debug2(" = %d\n", FD(evsel, cpu, thread)); | 1543 | pr_debug2(" = %d\n", fd); |
1499 | 1544 | ||
1500 | if (evsel->bpf_fd >= 0) { | 1545 | if (evsel->bpf_fd >= 0) { |
1501 | int evt_fd = FD(evsel, cpu, thread); | 1546 | int evt_fd = fd; |
1502 | int bpf_fd = evsel->bpf_fd; | 1547 | int bpf_fd = evsel->bpf_fd; |
1503 | 1548 | ||
1504 | err = ioctl(evt_fd, | 1549 | err = ioctl(evt_fd, |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6abb89cd27f9..06ef6f29efa1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -120,6 +120,7 @@ struct perf_evsel { | |||
120 | bool tracking; | 120 | bool tracking; |
121 | bool per_pkg; | 121 | bool per_pkg; |
122 | bool precise_max; | 122 | bool precise_max; |
123 | bool ignore_missing_thread; | ||
123 | /* parse modifier helper */ | 124 | /* parse modifier helper */ |
124 | int exclude_GH; | 125 | int exclude_GH; |
125 | int nr_members; | 126 | int nr_members; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index df2482b2ba45..dc93940de351 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1459,7 +1459,8 @@ int dso__load(struct dso *dso, struct map *map) | |||
1459 | * Read the build id if possible. This is required for | 1459 | * Read the build id if possible. This is required for |
1460 | * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work | 1460 | * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work |
1461 | */ | 1461 | */ |
1462 | if (is_regular_file(dso->long_name) && | 1462 | if (!dso->has_build_id && |
1463 | is_regular_file(dso->long_name) && | ||
1463 | filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) | 1464 | filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) |
1464 | dso__set_build_id(dso, build_id); | 1465 | dso__set_build_id(dso, build_id); |
1465 | 1466 | ||
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 40585f5b7027..f9eab200fd75 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -448,3 +448,25 @@ bool thread_map__has(struct thread_map *threads, pid_t pid) | |||
448 | 448 | ||
449 | return false; | 449 | return false; |
450 | } | 450 | } |
451 | |||
452 | int thread_map__remove(struct thread_map *threads, int idx) | ||
453 | { | ||
454 | int i; | ||
455 | |||
456 | if (threads->nr < 1) | ||
457 | return -EINVAL; | ||
458 | |||
459 | if (idx >= threads->nr) | ||
460 | return -EINVAL; | ||
461 | |||
462 | /* | ||
463 | * Free the 'idx' item and shift the rest up. | ||
464 | */ | ||
465 | free(threads->map[idx].comm); | ||
466 | |||
467 | for (i = idx; i < threads->nr - 1; i++) | ||
468 | threads->map[i] = threads->map[i + 1]; | ||
469 | |||
470 | threads->nr--; | ||
471 | return 0; | ||
472 | } | ||
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index bd3b971588da..ea0ef08c6303 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
@@ -58,4 +58,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread) | |||
58 | 58 | ||
59 | void thread_map__read_comms(struct thread_map *threads); | 59 | void thread_map__read_comms(struct thread_map *threads); |
60 | bool thread_map__has(struct thread_map *threads, pid_t pid); | 60 | bool thread_map__has(struct thread_map *threads, pid_t pid); |
61 | int thread_map__remove(struct thread_map *threads, int idx); | ||
61 | #endif /* __PERF_THREAD_MAP_H */ | 62 | #endif /* __PERF_THREAD_MAP_H */ |