4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <perf/cpumap.h>
10 #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
11 #include <linux/perf_event.h>
12 #include <linux/zalloc.h>
23 #include "thread_map.h"
24 #include "time-utils.h"
25 #include <linux/ctype.h>
27 #include "util/namespaces.h"
29 #include "symbol/kallsyms.h"
33 #include "bpf-event.h"
37 static const char *perf_event__names
[] = {
39 [PERF_RECORD_MMAP
] = "MMAP",
40 [PERF_RECORD_MMAP2
] = "MMAP2",
41 [PERF_RECORD_LOST
] = "LOST",
42 [PERF_RECORD_COMM
] = "COMM",
43 [PERF_RECORD_EXIT
] = "EXIT",
44 [PERF_RECORD_THROTTLE
] = "THROTTLE",
45 [PERF_RECORD_UNTHROTTLE
] = "UNTHROTTLE",
46 [PERF_RECORD_FORK
] = "FORK",
47 [PERF_RECORD_READ
] = "READ",
48 [PERF_RECORD_SAMPLE
] = "SAMPLE",
49 [PERF_RECORD_AUX
] = "AUX",
50 [PERF_RECORD_ITRACE_START
] = "ITRACE_START",
51 [PERF_RECORD_LOST_SAMPLES
] = "LOST_SAMPLES",
52 [PERF_RECORD_SWITCH
] = "SWITCH",
53 [PERF_RECORD_SWITCH_CPU_WIDE
] = "SWITCH_CPU_WIDE",
54 [PERF_RECORD_NAMESPACES
] = "NAMESPACES",
55 [PERF_RECORD_KSYMBOL
] = "KSYMBOL",
56 [PERF_RECORD_BPF_EVENT
] = "BPF_EVENT",
57 [PERF_RECORD_HEADER_ATTR
] = "ATTR",
58 [PERF_RECORD_HEADER_EVENT_TYPE
] = "EVENT_TYPE",
59 [PERF_RECORD_HEADER_TRACING_DATA
] = "TRACING_DATA",
60 [PERF_RECORD_HEADER_BUILD_ID
] = "BUILD_ID",
61 [PERF_RECORD_FINISHED_ROUND
] = "FINISHED_ROUND",
62 [PERF_RECORD_ID_INDEX
] = "ID_INDEX",
63 [PERF_RECORD_AUXTRACE_INFO
] = "AUXTRACE_INFO",
64 [PERF_RECORD_AUXTRACE
] = "AUXTRACE",
65 [PERF_RECORD_AUXTRACE_ERROR
] = "AUXTRACE_ERROR",
66 [PERF_RECORD_THREAD_MAP
] = "THREAD_MAP",
67 [PERF_RECORD_CPU_MAP
] = "CPU_MAP",
68 [PERF_RECORD_STAT_CONFIG
] = "STAT_CONFIG",
69 [PERF_RECORD_STAT
] = "STAT",
70 [PERF_RECORD_STAT_ROUND
] = "STAT_ROUND",
71 [PERF_RECORD_EVENT_UPDATE
] = "EVENT_UPDATE",
72 [PERF_RECORD_TIME_CONV
] = "TIME_CONV",
73 [PERF_RECORD_HEADER_FEATURE
] = "FEATURE",
74 [PERF_RECORD_COMPRESSED
] = "COMPRESSED",
77 const char *perf_event__name(unsigned int id
)
79 if (id
>= ARRAY_SIZE(perf_event__names
))
81 if (!perf_event__names
[id
])
83 return perf_event__names
[id
];
86 struct process_symbol_args
{
91 static int find_symbol_cb(void *arg
, const char *name
, char type
,
94 struct process_symbol_args
*args
= arg
;
97 * Must be a function or at least an alias, as in PARISC64, where "_text" is
98 * an 'A' to the same address as "_stext".
100 if (!(kallsyms__is_function(type
) ||
101 type
== 'A') || strcmp(name
, args
->name
))
108 int kallsyms__get_function_start(const char *kallsyms_filename
,
109 const char *symbol_name
, u64
*addr
)
111 struct process_symbol_args args
= { .name
= symbol_name
, };
113 if (kallsyms__parse(kallsyms_filename
, &args
, find_symbol_cb
) <= 0)
120 void perf_event__read_stat_config(struct perf_stat_config
*config
,
121 struct perf_record_stat_config
*event
)
125 for (i
= 0; i
< event
->nr
; i
++) {
127 switch (event
->data
[i
].tag
) {
128 #define CASE(__term, __val) \
129 case PERF_STAT_CONFIG_TERM__##__term: \
130 config->__val = event->data[i].val; \
133 CASE(AGGR_MODE
, aggr_mode
)
135 CASE(INTERVAL
, interval
)
138 pr_warning("unknown stat config term %" PRI_lu64
"\n",
144 size_t perf_event__fprintf_comm(union perf_event
*event
, FILE *fp
)
148 if (event
->header
.misc
& PERF_RECORD_MISC_COMM_EXEC
)
153 return fprintf(fp
, "%s: %s:%d/%d\n", s
, event
->comm
.comm
, event
->comm
.pid
, event
->comm
.tid
);
156 size_t perf_event__fprintf_namespaces(union perf_event
*event
, FILE *fp
)
159 struct perf_ns_link_info
*ns_link_info
;
160 u32 nr_namespaces
, idx
;
162 ns_link_info
= event
->namespaces
.link_info
;
163 nr_namespaces
= event
->namespaces
.nr_namespaces
;
165 ret
+= fprintf(fp
, " %d/%d - nr_namespaces: %u\n\t\t[",
166 event
->namespaces
.pid
,
167 event
->namespaces
.tid
,
170 for (idx
= 0; idx
< nr_namespaces
; idx
++) {
171 if (idx
&& (idx
% 4 == 0))
172 ret
+= fprintf(fp
, "\n\t\t ");
174 ret
+= fprintf(fp
, "%u/%s: %" PRIu64
"/%#" PRIx64
"%s", idx
,
175 perf_ns__name(idx
), (u64
)ns_link_info
[idx
].dev
,
176 (u64
)ns_link_info
[idx
].ino
,
177 ((idx
+ 1) != nr_namespaces
) ? ", " : "]\n");
183 int perf_event__process_comm(struct perf_tool
*tool __maybe_unused
,
184 union perf_event
*event
,
185 struct perf_sample
*sample
,
186 struct machine
*machine
)
188 return machine__process_comm_event(machine
, event
, sample
);
191 int perf_event__process_namespaces(struct perf_tool
*tool __maybe_unused
,
192 union perf_event
*event
,
193 struct perf_sample
*sample
,
194 struct machine
*machine
)
196 return machine__process_namespaces_event(machine
, event
, sample
);
199 int perf_event__process_lost(struct perf_tool
*tool __maybe_unused
,
200 union perf_event
*event
,
201 struct perf_sample
*sample
,
202 struct machine
*machine
)
204 return machine__process_lost_event(machine
, event
, sample
);
207 int perf_event__process_aux(struct perf_tool
*tool __maybe_unused
,
208 union perf_event
*event
,
209 struct perf_sample
*sample __maybe_unused
,
210 struct machine
*machine
)
212 return machine__process_aux_event(machine
, event
);
215 int perf_event__process_itrace_start(struct perf_tool
*tool __maybe_unused
,
216 union perf_event
*event
,
217 struct perf_sample
*sample __maybe_unused
,
218 struct machine
*machine
)
220 return machine__process_itrace_start_event(machine
, event
);
223 int perf_event__process_lost_samples(struct perf_tool
*tool __maybe_unused
,
224 union perf_event
*event
,
225 struct perf_sample
*sample
,
226 struct machine
*machine
)
228 return machine__process_lost_samples_event(machine
, event
, sample
);
231 int perf_event__process_switch(struct perf_tool
*tool __maybe_unused
,
232 union perf_event
*event
,
233 struct perf_sample
*sample __maybe_unused
,
234 struct machine
*machine
)
236 return machine__process_switch_event(machine
, event
);
239 int perf_event__process_ksymbol(struct perf_tool
*tool __maybe_unused
,
240 union perf_event
*event
,
241 struct perf_sample
*sample __maybe_unused
,
242 struct machine
*machine
)
244 return machine__process_ksymbol(machine
, event
, sample
);
247 int perf_event__process_bpf(struct perf_tool
*tool __maybe_unused
,
248 union perf_event
*event
,
249 struct perf_sample
*sample
,
250 struct machine
*machine
)
252 return machine__process_bpf(machine
, event
, sample
);
255 size_t perf_event__fprintf_mmap(union perf_event
*event
, FILE *fp
)
257 return fprintf(fp
, " %d/%d: [%#" PRI_lx64
"(%#" PRI_lx64
") @ %#" PRI_lx64
"]: %c %s\n",
258 event
->mmap
.pid
, event
->mmap
.tid
, event
->mmap
.start
,
259 event
->mmap
.len
, event
->mmap
.pgoff
,
260 (event
->header
.misc
& PERF_RECORD_MISC_MMAP_DATA
) ? 'r' : 'x',
261 event
->mmap
.filename
);
264 size_t perf_event__fprintf_mmap2(union perf_event
*event
, FILE *fp
)
266 return fprintf(fp
, " %d/%d: [%#" PRI_lx64
"(%#" PRI_lx64
") @ %#" PRI_lx64
267 " %02x:%02x %"PRI_lu64
" %"PRI_lu64
"]: %c%c%c%c %s\n",
268 event
->mmap2
.pid
, event
->mmap2
.tid
, event
->mmap2
.start
,
269 event
->mmap2
.len
, event
->mmap2
.pgoff
, event
->mmap2
.maj
,
270 event
->mmap2
.min
, event
->mmap2
.ino
,
271 event
->mmap2
.ino_generation
,
272 (event
->mmap2
.prot
& PROT_READ
) ? 'r' : '-',
273 (event
->mmap2
.prot
& PROT_WRITE
) ? 'w' : '-',
274 (event
->mmap2
.prot
& PROT_EXEC
) ? 'x' : '-',
275 (event
->mmap2
.flags
& MAP_SHARED
) ? 's' : 'p',
276 event
->mmap2
.filename
);
279 size_t perf_event__fprintf_thread_map(union perf_event
*event
, FILE *fp
)
281 struct perf_thread_map
*threads
= thread_map__new_event(&event
->thread_map
);
284 ret
= fprintf(fp
, " nr: ");
287 ret
+= thread_map__fprintf(threads
, fp
);
289 ret
+= fprintf(fp
, "failed to get threads from event\n");
291 perf_thread_map__put(threads
);
295 size_t perf_event__fprintf_cpu_map(union perf_event
*event
, FILE *fp
)
297 struct perf_cpu_map
*cpus
= cpu_map__new_data(&event
->cpu_map
.data
);
300 ret
= fprintf(fp
, ": ");
303 ret
+= cpu_map__fprintf(cpus
, fp
);
305 ret
+= fprintf(fp
, "failed to get cpumap from event\n");
307 perf_cpu_map__put(cpus
);
311 int perf_event__process_mmap(struct perf_tool
*tool __maybe_unused
,
312 union perf_event
*event
,
313 struct perf_sample
*sample
,
314 struct machine
*machine
)
316 return machine__process_mmap_event(machine
, event
, sample
);
319 int perf_event__process_mmap2(struct perf_tool
*tool __maybe_unused
,
320 union perf_event
*event
,
321 struct perf_sample
*sample
,
322 struct machine
*machine
)
324 return machine__process_mmap2_event(machine
, event
, sample
);
327 size_t perf_event__fprintf_task(union perf_event
*event
, FILE *fp
)
329 return fprintf(fp
, "(%d:%d):(%d:%d)\n",
330 event
->fork
.pid
, event
->fork
.tid
,
331 event
->fork
.ppid
, event
->fork
.ptid
);
334 int perf_event__process_fork(struct perf_tool
*tool __maybe_unused
,
335 union perf_event
*event
,
336 struct perf_sample
*sample
,
337 struct machine
*machine
)
339 return machine__process_fork_event(machine
, event
, sample
);
342 int perf_event__process_exit(struct perf_tool
*tool __maybe_unused
,
343 union perf_event
*event
,
344 struct perf_sample
*sample
,
345 struct machine
*machine
)
347 return machine__process_exit_event(machine
, event
, sample
);
350 size_t perf_event__fprintf_aux(union perf_event
*event
, FILE *fp
)
352 return fprintf(fp
, " offset: %#"PRI_lx64
" size: %#"PRI_lx64
" flags: %#"PRI_lx64
" [%s%s%s]\n",
353 event
->aux
.aux_offset
, event
->aux
.aux_size
,
355 event
->aux
.flags
& PERF_AUX_FLAG_TRUNCATED
? "T" : "",
356 event
->aux
.flags
& PERF_AUX_FLAG_OVERWRITE
? "O" : "",
357 event
->aux
.flags
& PERF_AUX_FLAG_PARTIAL
? "P" : "");
360 size_t perf_event__fprintf_itrace_start(union perf_event
*event
, FILE *fp
)
362 return fprintf(fp
, " pid: %u tid: %u\n",
363 event
->itrace_start
.pid
, event
->itrace_start
.tid
);
366 size_t perf_event__fprintf_switch(union perf_event
*event
, FILE *fp
)
368 bool out
= event
->header
.misc
& PERF_RECORD_MISC_SWITCH_OUT
;
369 const char *in_out
= !out
? "IN " :
370 !(event
->header
.misc
& PERF_RECORD_MISC_SWITCH_OUT_PREEMPT
) ?
371 "OUT " : "OUT preempt";
373 if (event
->header
.type
== PERF_RECORD_SWITCH
)
374 return fprintf(fp
, " %s\n", in_out
);
376 return fprintf(fp
, " %s %s pid/tid: %5u/%-5u\n",
377 in_out
, out
? "next" : "prev",
378 event
->context_switch
.next_prev_pid
,
379 event
->context_switch
.next_prev_tid
);
382 static size_t perf_event__fprintf_lost(union perf_event
*event
, FILE *fp
)
384 return fprintf(fp
, " lost %" PRI_lu64
"\n", event
->lost
.lost
);
387 size_t perf_event__fprintf_ksymbol(union perf_event
*event
, FILE *fp
)
389 return fprintf(fp
, " addr %" PRI_lx64
" len %u type %u flags 0x%x name %s\n",
390 event
->ksymbol
.addr
, event
->ksymbol
.len
,
391 event
->ksymbol
.ksym_type
,
392 event
->ksymbol
.flags
, event
->ksymbol
.name
);
395 size_t perf_event__fprintf_bpf(union perf_event
*event
, FILE *fp
)
397 return fprintf(fp
, " type %u, flags %u, id %u\n",
398 event
->bpf
.type
, event
->bpf
.flags
, event
->bpf
.id
);
401 size_t perf_event__fprintf(union perf_event
*event
, FILE *fp
)
403 size_t ret
= fprintf(fp
, "PERF_RECORD_%s",
404 perf_event__name(event
->header
.type
));
406 switch (event
->header
.type
) {
407 case PERF_RECORD_COMM
:
408 ret
+= perf_event__fprintf_comm(event
, fp
);
410 case PERF_RECORD_FORK
:
411 case PERF_RECORD_EXIT
:
412 ret
+= perf_event__fprintf_task(event
, fp
);
414 case PERF_RECORD_MMAP
:
415 ret
+= perf_event__fprintf_mmap(event
, fp
);
417 case PERF_RECORD_NAMESPACES
:
418 ret
+= perf_event__fprintf_namespaces(event
, fp
);
420 case PERF_RECORD_MMAP2
:
421 ret
+= perf_event__fprintf_mmap2(event
, fp
);
423 case PERF_RECORD_AUX
:
424 ret
+= perf_event__fprintf_aux(event
, fp
);
426 case PERF_RECORD_ITRACE_START
:
427 ret
+= perf_event__fprintf_itrace_start(event
, fp
);
429 case PERF_RECORD_SWITCH
:
430 case PERF_RECORD_SWITCH_CPU_WIDE
:
431 ret
+= perf_event__fprintf_switch(event
, fp
);
433 case PERF_RECORD_LOST
:
434 ret
+= perf_event__fprintf_lost(event
, fp
);
436 case PERF_RECORD_KSYMBOL
:
437 ret
+= perf_event__fprintf_ksymbol(event
, fp
);
439 case PERF_RECORD_BPF_EVENT
:
440 ret
+= perf_event__fprintf_bpf(event
, fp
);
443 ret
+= fprintf(fp
, "\n");
449 int perf_event__process(struct perf_tool
*tool __maybe_unused
,
450 union perf_event
*event
,
451 struct perf_sample
*sample
,
452 struct machine
*machine
)
454 return machine__process_event(machine
, event
, sample
);
457 struct map
*thread__find_map(struct thread
*thread
, u8 cpumode
, u64 addr
,
458 struct addr_location
*al
)
460 struct maps
*maps
= thread
->maps
;
461 struct machine
*machine
= maps
->machine
;
462 bool load_map
= false;
467 al
->cpumode
= cpumode
;
470 if (machine
== NULL
) {
475 if (cpumode
== PERF_RECORD_MISC_KERNEL
&& perf_host
) {
477 al
->maps
= maps
= &machine
->kmaps
;
479 } else if (cpumode
== PERF_RECORD_MISC_USER
&& perf_host
) {
481 } else if (cpumode
== PERF_RECORD_MISC_GUEST_KERNEL
&& perf_guest
) {
483 al
->maps
= maps
= &machine
->kmaps
;
485 } else if (cpumode
== PERF_RECORD_MISC_GUEST_USER
&& perf_guest
) {
491 if ((cpumode
== PERF_RECORD_MISC_GUEST_USER
||
492 cpumode
== PERF_RECORD_MISC_GUEST_KERNEL
) &&
494 al
->filtered
|= (1 << HIST_FILTER__GUEST
);
495 if ((cpumode
== PERF_RECORD_MISC_USER
||
496 cpumode
== PERF_RECORD_MISC_KERNEL
) &&
498 al
->filtered
|= (1 << HIST_FILTER__HOST
);
503 al
->map
= maps__find(maps
, al
->addr
);
504 if (al
->map
!= NULL
) {
506 * Kernel maps might be changed when loading symbols so loading
507 * must be done prior to using kernel maps.
511 al
->addr
= al
->map
->map_ip(al
->map
, al
->addr
);
518 * For branch stacks or branch samples, the sample cpumode might not be correct
519 * because it applies only to the sample 'ip' and not necessary to 'addr' or
520 * branch stack addresses. If possible, use a fallback to deal with those cases.
522 struct map
*thread__find_map_fb(struct thread
*thread
, u8 cpumode
, u64 addr
,
523 struct addr_location
*al
)
525 struct map
*map
= thread__find_map(thread
, cpumode
, addr
, al
);
526 struct machine
*machine
= thread
->maps
->machine
;
527 u8 addr_cpumode
= machine__addr_cpumode(machine
, cpumode
, addr
);
529 if (map
|| addr_cpumode
== cpumode
)
532 return thread__find_map(thread
, addr_cpumode
, addr
, al
);
535 struct symbol
*thread__find_symbol(struct thread
*thread
, u8 cpumode
,
536 u64 addr
, struct addr_location
*al
)
539 if (thread__find_map(thread
, cpumode
, addr
, al
))
540 al
->sym
= map__find_symbol(al
->map
, al
->addr
);
544 struct symbol
*thread__find_symbol_fb(struct thread
*thread
, u8 cpumode
,
545 u64 addr
, struct addr_location
*al
)
548 if (thread__find_map_fb(thread
, cpumode
, addr
, al
))
549 al
->sym
= map__find_symbol(al
->map
, al
->addr
);
554 * Callers need to drop the reference to al->thread, obtained in
555 * machine__findnew_thread()
557 int machine__resolve(struct machine
*machine
, struct addr_location
*al
,
558 struct perf_sample
*sample
)
560 struct thread
*thread
= machine__findnew_thread(machine
, sample
->pid
,
566 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread
), thread
->tid
);
567 thread__find_map(thread
, sample
->cpumode
, sample
->ip
, al
);
568 dump_printf(" ...... dso: %s\n",
569 al
->map
? al
->map
->dso
->long_name
:
570 al
->level
== 'H' ? "[hypervisor]" : "<not found>");
572 if (thread__is_filtered(thread
))
573 al
->filtered
|= (1 << HIST_FILTER__THREAD
);
576 al
->cpu
= sample
->cpu
;
581 struct perf_env
*env
= machine
->env
;
584 al
->socket
= env
->cpu
[al
->cpu
].socket_id
;
588 struct dso
*dso
= al
->map
->dso
;
590 if (symbol_conf
.dso_list
&&
591 (!dso
|| !(strlist__has_entry(symbol_conf
.dso_list
,
593 (dso
->short_name
!= dso
->long_name
&&
594 strlist__has_entry(symbol_conf
.dso_list
,
595 dso
->long_name
))))) {
596 al
->filtered
|= (1 << HIST_FILTER__DSO
);
599 al
->sym
= map__find_symbol(al
->map
, al
->addr
);
602 if (symbol_conf
.sym_list
&&
603 (!al
->sym
|| !strlist__has_entry(symbol_conf
.sym_list
,
605 al
->filtered
|= (1 << HIST_FILTER__SYMBOL
);
612 * The preprocess_sample method will return with reference counts for the
613 * in it, when done using (and perhaps getting ref counts if needing to
614 * keep a pointer to one of those entries) it must be paired with
615 * addr_location__put(), so that the refcounts can be decremented.
617 void addr_location__put(struct addr_location
*al
)
619 thread__zput(al
->thread
);
622 bool is_bts_event(struct perf_event_attr
*attr
)
624 return attr
->type
== PERF_TYPE_HARDWARE
&&
625 (attr
->config
& PERF_COUNT_HW_BRANCH_INSTRUCTIONS
) &&
626 attr
->sample_period
== 1;
629 bool sample_addr_correlates_sym(struct perf_event_attr
*attr
)
631 if (attr
->type
== PERF_TYPE_SOFTWARE
&&
632 (attr
->config
== PERF_COUNT_SW_PAGE_FAULTS
||
633 attr
->config
== PERF_COUNT_SW_PAGE_FAULTS_MIN
||
634 attr
->config
== PERF_COUNT_SW_PAGE_FAULTS_MAJ
))
637 if (is_bts_event(attr
))
643 void thread__resolve(struct thread
*thread
, struct addr_location
*al
,
644 struct perf_sample
*sample
)
646 thread__find_map_fb(thread
, sample
->cpumode
, sample
->addr
, al
);
648 al
->cpu
= sample
->cpu
;
652 al
->sym
= map__find_symbol(al
->map
, al
->addr
);