2675 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <errno.h>3#include <signal.h>4#include <inttypes.h>5#include <linux/err.h>6#include <linux/kernel.h>7#include <linux/zalloc.h>8#include <api/fs/fs.h>9 10#include <byteswap.h>11#include <unistd.h>12#include <sys/types.h>13#include <sys/mman.h>14#include <perf/cpumap.h>15 16#include "map_symbol.h"17#include "branch.h"18#include "debug.h"19#include "env.h"20#include "evlist.h"21#include "evsel.h"22#include "memswap.h"23#include "map.h"24#include "symbol.h"25#include "session.h"26#include "tool.h"27#include "perf_regs.h"28#include "asm/bug.h"29#include "auxtrace.h"30#include "thread.h"31#include "thread-stack.h"32#include "sample-raw.h"33#include "stat.h"34#include "tsc.h"35#include "ui/progress.h"36#include "util.h"37#include "arch/common.h"38#include "units.h"39#include "annotate.h"40#include <internal/lib.h>41 42static int perf_session__deliver_event(struct perf_session *session,43 union perf_event *event,44 const struct perf_tool *tool,45 u64 file_offset,46 const char *file_path);47 48static int perf_session__open(struct perf_session *session)49{50 struct perf_data *data = session->data;51 52 if (perf_session__read_header(session) < 0) {53 pr_err("incompatible file format (rerun with -v to learn more)\n");54 return -1;55 }56 57 if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) {58 /* Auxiliary events may reference exited threads, hold onto dead ones. */59 symbol_conf.keep_exited_threads = true;60 }61 62 if (perf_data__is_pipe(data))63 return 0;64 65 if (perf_header__has_feat(&session->header, HEADER_STAT))66 return 0;67 68 if (!evlist__valid_sample_type(session->evlist)) {69 pr_err("non matching sample_type\n");70 return -1;71 }72 73 if (!evlist__valid_sample_id_all(session->evlist)) {74 pr_err("non matching sample_id_all\n");75 return -1;76 }77 78 if (!evlist__valid_read_format(session->evlist)) {79 pr_err("non matching read_format\n");80 return -1;81 }82 83 return 0;84}85 86void perf_session__set_id_hdr_size(struct perf_session *session)87{88 u16 id_hdr_size = evlist__id_hdr_size(session->evlist);89 90 machines__set_id_hdr_size(&session->machines, id_hdr_size);91}92 93int perf_session__create_kernel_maps(struct perf_session *session)94{95 int ret = machine__create_kernel_maps(&session->machines.host);96 97 if (ret >= 0)98 ret = machines__create_guest_kernel_maps(&session->machines);99 return ret;100}101 102static void perf_session__destroy_kernel_maps(struct perf_session *session)103{104 machines__destroy_kernel_maps(&session->machines);105}106 107static bool perf_session__has_comm_exec(struct perf_session *session)108{109 struct evsel *evsel;110 111 evlist__for_each_entry(session->evlist, evsel) {112 if (evsel->core.attr.comm_exec)113 return true;114 }115 116 return false;117}118 119static void perf_session__set_comm_exec(struct perf_session *session)120{121 bool comm_exec = perf_session__has_comm_exec(session);122 123 machines__set_comm_exec(&session->machines, comm_exec);124}125 126static int ordered_events__deliver_event(struct ordered_events *oe,127 struct ordered_event *event)128{129 struct perf_session *session = container_of(oe, struct perf_session,130 ordered_events);131 132 return perf_session__deliver_event(session, event->event,133 session->tool, event->file_offset,134 event->file_path);135}136 137struct perf_session *__perf_session__new(struct perf_data *data,138 struct perf_tool *tool,139 bool trace_event_repipe)140{141 int ret = -ENOMEM;142 struct perf_session *session = zalloc(sizeof(*session));143 144 if (!session)145 goto out;146 147 session->trace_event_repipe = trace_event_repipe;148 session->tool = tool;149 session->decomp_data.zstd_decomp = &session->zstd_data;150 session->active_decomp = &session->decomp_data;151 INIT_LIST_HEAD(&session->auxtrace_index);152 machines__init(&session->machines);153 ordered_events__init(&session->ordered_events,154 ordered_events__deliver_event, NULL);155 156 perf_env__init(&session->header.env);157 if (data) {158 ret = perf_data__open(data);159 if (ret < 0)160 goto out_delete;161 162 session->data = data;163 164 if (perf_data__is_read(data)) {165 ret = perf_session__open(session);166 if (ret < 0)167 goto out_delete;168 169 /*170 * set session attributes that are present in perf.data171 * but not in pipe-mode.172 */173 if (!data->is_pipe) {174 perf_session__set_id_hdr_size(session);175 perf_session__set_comm_exec(session);176 }177 178 evlist__init_trace_event_sample_raw(session->evlist);179 180 /* Open the directory data. */181 if (data->is_dir) {182 ret = perf_data__open_dir(data);183 if (ret)184 goto out_delete;185 }186 187 if (!symbol_conf.kallsyms_name &&188 !symbol_conf.vmlinux_name)189 symbol_conf.kallsyms_name = perf_data__kallsyms_name(data);190 }191 } else {192 session->machines.host.env = &perf_env;193 }194 195 session->machines.host.single_address_space =196 perf_env__single_address_space(session->machines.host.env);197 198 if (!data || perf_data__is_write(data)) {199 /*200 * In O_RDONLY mode this will be performed when reading the201 * kernel MMAP event, in perf_event__process_mmap().202 */203 if (perf_session__create_kernel_maps(session) < 0)204 pr_warning("Cannot read kernel map\n");205 }206 207 /*208 * In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is209 * processed, so evlist__sample_id_all is not meaningful here.210 */211 if ((!data || !data->is_pipe) && tool && tool->ordering_requires_timestamps &&212 tool->ordered_events && !evlist__sample_id_all(session->evlist)) {213 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");214 tool->ordered_events = false;215 }216 217 return session;218 219 out_delete:220 perf_session__delete(session);221 out:222 return ERR_PTR(ret);223}224 225static void perf_decomp__release_events(struct decomp *next)226{227 struct decomp *decomp;228 size_t mmap_len;229 230 do {231 decomp = next;232 if (decomp == NULL)233 break;234 next = decomp->next;235 mmap_len = decomp->mmap_len;236 munmap(decomp, mmap_len);237 } while (1);238}239 240void perf_session__delete(struct perf_session *session)241{242 if (session == NULL)243 return;244 auxtrace__free(session);245 auxtrace_index__free(&session->auxtrace_index);246 debuginfo_cache__delete();247 perf_session__destroy_kernel_maps(session);248 perf_decomp__release_events(session->decomp_data.decomp);249 perf_env__exit(&session->header.env);250 machines__exit(&session->machines);251 if (session->data) {252 if (perf_data__is_read(session->data))253 evlist__delete(session->evlist);254 perf_data__close(session->data);255 }256#ifdef HAVE_LIBTRACEEVENT257 trace_event__cleanup(&session->tevent);258#endif259 free(session);260}261 262static void swap_sample_id_all(union perf_event *event, void *data)263{264 void *end = (void *) event + event->header.size;265 int size = end - data;266 267 BUG_ON(size % sizeof(u64));268 mem_bswap_64(data, size);269}270 271static void perf_event__all64_swap(union perf_event *event,272 bool sample_id_all __maybe_unused)273{274 struct perf_event_header *hdr = &event->header;275 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));276}277 278static void perf_event__comm_swap(union perf_event *event, bool sample_id_all)279{280 event->comm.pid = bswap_32(event->comm.pid);281 event->comm.tid = bswap_32(event->comm.tid);282 283 if (sample_id_all) {284 void *data = &event->comm.comm;285 286 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));287 swap_sample_id_all(event, data);288 }289}290 291static void perf_event__mmap_swap(union perf_event *event,292 bool sample_id_all)293{294 event->mmap.pid = bswap_32(event->mmap.pid);295 event->mmap.tid = bswap_32(event->mmap.tid);296 event->mmap.start = bswap_64(event->mmap.start);297 event->mmap.len = bswap_64(event->mmap.len);298 event->mmap.pgoff = bswap_64(event->mmap.pgoff);299 300 if (sample_id_all) {301 void *data = &event->mmap.filename;302 303 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));304 swap_sample_id_all(event, data);305 }306}307 308static void perf_event__mmap2_swap(union perf_event *event,309 bool sample_id_all)310{311 event->mmap2.pid = bswap_32(event->mmap2.pid);312 event->mmap2.tid = bswap_32(event->mmap2.tid);313 event->mmap2.start = bswap_64(event->mmap2.start);314 event->mmap2.len = bswap_64(event->mmap2.len);315 event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);316 317 if (!(event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)) {318 event->mmap2.maj = bswap_32(event->mmap2.maj);319 event->mmap2.min = bswap_32(event->mmap2.min);320 event->mmap2.ino = bswap_64(event->mmap2.ino);321 event->mmap2.ino_generation = bswap_64(event->mmap2.ino_generation);322 }323 324 if (sample_id_all) {325 void *data = &event->mmap2.filename;326 327 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));328 swap_sample_id_all(event, data);329 }330}331static void perf_event__task_swap(union perf_event *event, bool sample_id_all)332{333 event->fork.pid = bswap_32(event->fork.pid);334 event->fork.tid = bswap_32(event->fork.tid);335 event->fork.ppid = bswap_32(event->fork.ppid);336 event->fork.ptid = bswap_32(event->fork.ptid);337 event->fork.time = bswap_64(event->fork.time);338 339 if (sample_id_all)340 swap_sample_id_all(event, &event->fork + 1);341}342 343static void perf_event__read_swap(union perf_event *event, bool sample_id_all)344{345 event->read.pid = bswap_32(event->read.pid);346 event->read.tid = bswap_32(event->read.tid);347 event->read.value = bswap_64(event->read.value);348 event->read.time_enabled = bswap_64(event->read.time_enabled);349 event->read.time_running = bswap_64(event->read.time_running);350 event->read.id = bswap_64(event->read.id);351 352 if (sample_id_all)353 swap_sample_id_all(event, &event->read + 1);354}355 356static void perf_event__aux_swap(union perf_event *event, bool sample_id_all)357{358 event->aux.aux_offset = bswap_64(event->aux.aux_offset);359 event->aux.aux_size = bswap_64(event->aux.aux_size);360 event->aux.flags = bswap_64(event->aux.flags);361 362 if (sample_id_all)363 swap_sample_id_all(event, &event->aux + 1);364}365 366static void perf_event__itrace_start_swap(union perf_event *event,367 bool sample_id_all)368{369 event->itrace_start.pid = bswap_32(event->itrace_start.pid);370 event->itrace_start.tid = bswap_32(event->itrace_start.tid);371 372 if (sample_id_all)373 swap_sample_id_all(event, &event->itrace_start + 1);374}375 376static void perf_event__switch_swap(union perf_event *event, bool sample_id_all)377{378 if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {379 event->context_switch.next_prev_pid =380 bswap_32(event->context_switch.next_prev_pid);381 event->context_switch.next_prev_tid =382 bswap_32(event->context_switch.next_prev_tid);383 }384 385 if (sample_id_all)386 swap_sample_id_all(event, &event->context_switch + 1);387}388 389static void perf_event__text_poke_swap(union perf_event *event, bool sample_id_all)390{391 event->text_poke.addr = bswap_64(event->text_poke.addr);392 event->text_poke.old_len = bswap_16(event->text_poke.old_len);393 event->text_poke.new_len = bswap_16(event->text_poke.new_len);394 395 if (sample_id_all) {396 size_t len = sizeof(event->text_poke.old_len) +397 sizeof(event->text_poke.new_len) +398 event->text_poke.old_len +399 event->text_poke.new_len;400 void *data = &event->text_poke.old_len;401 402 data += PERF_ALIGN(len, sizeof(u64));403 swap_sample_id_all(event, data);404 }405}406 407static void perf_event__throttle_swap(union perf_event *event,408 bool sample_id_all)409{410 event->throttle.time = bswap_64(event->throttle.time);411 event->throttle.id = bswap_64(event->throttle.id);412 event->throttle.stream_id = bswap_64(event->throttle.stream_id);413 414 if (sample_id_all)415 swap_sample_id_all(event, &event->throttle + 1);416}417 418static void perf_event__namespaces_swap(union perf_event *event,419 bool sample_id_all)420{421 u64 i;422 423 event->namespaces.pid = bswap_32(event->namespaces.pid);424 event->namespaces.tid = bswap_32(event->namespaces.tid);425 event->namespaces.nr_namespaces = bswap_64(event->namespaces.nr_namespaces);426 427 for (i = 0; i < event->namespaces.nr_namespaces; i++) {428 struct perf_ns_link_info *ns = &event->namespaces.link_info[i];429 430 ns->dev = bswap_64(ns->dev);431 ns->ino = bswap_64(ns->ino);432 }433 434 if (sample_id_all)435 swap_sample_id_all(event, &event->namespaces.link_info[i]);436}437 438static void perf_event__cgroup_swap(union perf_event *event, bool sample_id_all)439{440 event->cgroup.id = bswap_64(event->cgroup.id);441 442 if (sample_id_all) {443 void *data = &event->cgroup.path;444 445 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));446 swap_sample_id_all(event, data);447 }448}449 450static u8 revbyte(u8 b)451{452 int rev = (b >> 4) | ((b & 0xf) << 4);453 rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);454 rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);455 return (u8) rev;456}457 458/*459 * XXX this is hack in attempt to carry flags bitfield460 * through endian village. ABI says:461 *462 * Bit-fields are allocated from right to left (least to most significant)463 * on little-endian implementations and from left to right (most to least464 * significant) on big-endian implementations.465 *466 * The above seems to be byte specific, so we need to reverse each467 * byte of the bitfield. 'Internet' also says this might be implementation468 * specific and we probably need proper fix and carry perf_event_attr469 * bitfield flags in separate data file FEAT_ section. Thought this seems470 * to work for now.471 */472static void swap_bitfield(u8 *p, unsigned len)473{474 unsigned i;475 476 for (i = 0; i < len; i++) {477 *p = revbyte(*p);478 p++;479 }480}481 482/* exported for swapping attributes in file header */483void perf_event__attr_swap(struct perf_event_attr *attr)484{485 attr->type = bswap_32(attr->type);486 attr->size = bswap_32(attr->size);487 488#define bswap_safe(f, n) \489 (attr->size > (offsetof(struct perf_event_attr, f) + \490 sizeof(attr->f) * (n)))491#define bswap_field(f, sz) \492do { \493 if (bswap_safe(f, 0)) \494 attr->f = bswap_##sz(attr->f); \495} while(0)496#define bswap_field_16(f) bswap_field(f, 16)497#define bswap_field_32(f) bswap_field(f, 32)498#define bswap_field_64(f) bswap_field(f, 64)499 500 bswap_field_64(config);501 bswap_field_64(sample_period);502 bswap_field_64(sample_type);503 bswap_field_64(read_format);504 bswap_field_32(wakeup_events);505 bswap_field_32(bp_type);506 bswap_field_64(bp_addr);507 bswap_field_64(bp_len);508 bswap_field_64(branch_sample_type);509 bswap_field_64(sample_regs_user);510 bswap_field_32(sample_stack_user);511 bswap_field_32(aux_watermark);512 bswap_field_16(sample_max_stack);513 bswap_field_32(aux_sample_size);514 515 /*516 * After read_format are bitfields. Check read_format because517 * we are unable to use offsetof on bitfield.518 */519 if (bswap_safe(read_format, 1))520 swap_bitfield((u8 *) (&attr->read_format + 1),521 sizeof(u64));522#undef bswap_field_64523#undef bswap_field_32524#undef bswap_field525#undef bswap_safe526}527 528static void perf_event__hdr_attr_swap(union perf_event *event,529 bool sample_id_all __maybe_unused)530{531 size_t size;532 533 perf_event__attr_swap(&event->attr.attr);534 535 size = event->header.size;536 size -= perf_record_header_attr_id(event) - (void *)event;537 mem_bswap_64(perf_record_header_attr_id(event), size);538}539 540static void perf_event__event_update_swap(union perf_event *event,541 bool sample_id_all __maybe_unused)542{543 event->event_update.type = bswap_64(event->event_update.type);544 event->event_update.id = bswap_64(event->event_update.id);545}546 547static void perf_event__event_type_swap(union perf_event *event,548 bool sample_id_all __maybe_unused)549{550 event->event_type.event_type.event_id =551 bswap_64(event->event_type.event_type.event_id);552}553 554static void perf_event__tracing_data_swap(union perf_event *event,555 bool sample_id_all __maybe_unused)556{557 event->tracing_data.size = bswap_32(event->tracing_data.size);558}559 560static void perf_event__auxtrace_info_swap(union perf_event *event,561 bool sample_id_all __maybe_unused)562{563 size_t size;564 565 event->auxtrace_info.type = bswap_32(event->auxtrace_info.type);566 567 size = event->header.size;568 size -= (void *)&event->auxtrace_info.priv - (void *)event;569 mem_bswap_64(event->auxtrace_info.priv, size);570}571 572static void perf_event__auxtrace_swap(union perf_event *event,573 bool sample_id_all __maybe_unused)574{575 event->auxtrace.size = bswap_64(event->auxtrace.size);576 event->auxtrace.offset = bswap_64(event->auxtrace.offset);577 event->auxtrace.reference = bswap_64(event->auxtrace.reference);578 event->auxtrace.idx = bswap_32(event->auxtrace.idx);579 event->auxtrace.tid = bswap_32(event->auxtrace.tid);580 event->auxtrace.cpu = bswap_32(event->auxtrace.cpu);581}582 583static void perf_event__auxtrace_error_swap(union perf_event *event,584 bool sample_id_all __maybe_unused)585{586 event->auxtrace_error.type = bswap_32(event->auxtrace_error.type);587 event->auxtrace_error.code = bswap_32(event->auxtrace_error.code);588 event->auxtrace_error.cpu = bswap_32(event->auxtrace_error.cpu);589 event->auxtrace_error.pid = bswap_32(event->auxtrace_error.pid);590 event->auxtrace_error.tid = bswap_32(event->auxtrace_error.tid);591 event->auxtrace_error.fmt = bswap_32(event->auxtrace_error.fmt);592 event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip);593 if (event->auxtrace_error.fmt)594 event->auxtrace_error.time = bswap_64(event->auxtrace_error.time);595 if (event->auxtrace_error.fmt >= 2) {596 event->auxtrace_error.machine_pid = bswap_32(event->auxtrace_error.machine_pid);597 event->auxtrace_error.vcpu = bswap_32(event->auxtrace_error.vcpu);598 }599}600 601static void perf_event__thread_map_swap(union perf_event *event,602 bool sample_id_all __maybe_unused)603{604 unsigned i;605 606 event->thread_map.nr = bswap_64(event->thread_map.nr);607 608 for (i = 0; i < event->thread_map.nr; i++)609 event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid);610}611 612static void perf_event__cpu_map_swap(union perf_event *event,613 bool sample_id_all __maybe_unused)614{615 struct perf_record_cpu_map_data *data = &event->cpu_map.data;616 617 data->type = bswap_16(data->type);618 619 switch (data->type) {620 case PERF_CPU_MAP__CPUS:621 data->cpus_data.nr = bswap_16(data->cpus_data.nr);622 623 for (unsigned i = 0; i < data->cpus_data.nr; i++)624 data->cpus_data.cpu[i] = bswap_16(data->cpus_data.cpu[i]);625 break;626 case PERF_CPU_MAP__MASK:627 data->mask32_data.long_size = bswap_16(data->mask32_data.long_size);628 629 switch (data->mask32_data.long_size) {630 case 4:631 data->mask32_data.nr = bswap_16(data->mask32_data.nr);632 for (unsigned i = 0; i < data->mask32_data.nr; i++)633 data->mask32_data.mask[i] = bswap_32(data->mask32_data.mask[i]);634 break;635 case 8:636 data->mask64_data.nr = bswap_16(data->mask64_data.nr);637 for (unsigned i = 0; i < data->mask64_data.nr; i++)638 data->mask64_data.mask[i] = bswap_64(data->mask64_data.mask[i]);639 break;640 default:641 pr_err("cpu_map swap: unsupported long size\n");642 }643 break;644 case PERF_CPU_MAP__RANGE_CPUS:645 data->range_cpu_data.start_cpu = bswap_16(data->range_cpu_data.start_cpu);646 data->range_cpu_data.end_cpu = bswap_16(data->range_cpu_data.end_cpu);647 break;648 default:649 break;650 }651}652 653static void perf_event__stat_config_swap(union perf_event *event,654 bool sample_id_all __maybe_unused)655{656 u64 size;657 658 size = bswap_64(event->stat_config.nr) * sizeof(event->stat_config.data[0]);659 size += 1; /* nr item itself */660 mem_bswap_64(&event->stat_config.nr, size);661}662 663static void perf_event__stat_swap(union perf_event *event,664 bool sample_id_all __maybe_unused)665{666 event->stat.id = bswap_64(event->stat.id);667 event->stat.thread = bswap_32(event->stat.thread);668 event->stat.cpu = bswap_32(event->stat.cpu);669 event->stat.val = bswap_64(event->stat.val);670 event->stat.ena = bswap_64(event->stat.ena);671 event->stat.run = bswap_64(event->stat.run);672}673 674static void perf_event__stat_round_swap(union perf_event *event,675 bool sample_id_all __maybe_unused)676{677 event->stat_round.type = bswap_64(event->stat_round.type);678 event->stat_round.time = bswap_64(event->stat_round.time);679}680 681static void perf_event__time_conv_swap(union perf_event *event,682 bool sample_id_all __maybe_unused)683{684 event->time_conv.time_shift = bswap_64(event->time_conv.time_shift);685 event->time_conv.time_mult = bswap_64(event->time_conv.time_mult);686 event->time_conv.time_zero = bswap_64(event->time_conv.time_zero);687 688 if (event_contains(event->time_conv, time_cycles)) {689 event->time_conv.time_cycles = bswap_64(event->time_conv.time_cycles);690 event->time_conv.time_mask = bswap_64(event->time_conv.time_mask);691 }692}693 694typedef void (*perf_event__swap_op)(union perf_event *event,695 bool sample_id_all);696 697static perf_event__swap_op perf_event__swap_ops[] = {698 [PERF_RECORD_MMAP] = perf_event__mmap_swap,699 [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,700 [PERF_RECORD_COMM] = perf_event__comm_swap,701 [PERF_RECORD_FORK] = perf_event__task_swap,702 [PERF_RECORD_EXIT] = perf_event__task_swap,703 [PERF_RECORD_LOST] = perf_event__all64_swap,704 [PERF_RECORD_READ] = perf_event__read_swap,705 [PERF_RECORD_THROTTLE] = perf_event__throttle_swap,706 [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap,707 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,708 [PERF_RECORD_AUX] = perf_event__aux_swap,709 [PERF_RECORD_ITRACE_START] = perf_event__itrace_start_swap,710 [PERF_RECORD_LOST_SAMPLES] = perf_event__all64_swap,711 [PERF_RECORD_SWITCH] = perf_event__switch_swap,712 [PERF_RECORD_SWITCH_CPU_WIDE] = perf_event__switch_swap,713 [PERF_RECORD_NAMESPACES] = perf_event__namespaces_swap,714 [PERF_RECORD_CGROUP] = perf_event__cgroup_swap,715 [PERF_RECORD_TEXT_POKE] = perf_event__text_poke_swap,716 [PERF_RECORD_AUX_OUTPUT_HW_ID] = perf_event__all64_swap,717 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,718 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,719 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,720 [PERF_RECORD_HEADER_BUILD_ID] = NULL,721 [PERF_RECORD_ID_INDEX] = perf_event__all64_swap,722 [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap,723 [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,724 [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,725 [PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,726 [PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,727 [PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,728 [PERF_RECORD_STAT] = perf_event__stat_swap,729 [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap,730 [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap,731 [PERF_RECORD_TIME_CONV] = perf_event__time_conv_swap,732 [PERF_RECORD_HEADER_MAX] = NULL,733};734 735/*736 * When perf record finishes a pass on every buffers, it records this pseudo737 * event.738 * We record the max timestamp t found in the pass n.739 * Assuming these timestamps are monotonic across cpus, we know that if740 * a buffer still has events with timestamps below t, they will be all741 * available and then read in the pass n + 1.742 * Hence when we start to read the pass n + 2, we can safely flush every743 * events with timestamps below t.744 *745 * ============ PASS n =================746 * CPU 0 | CPU 1747 * |748 * cnt1 timestamps | cnt2 timestamps749 * 1 | 2750 * 2 | 3751 * - | 4 <--- max recorded752 *753 * ============ PASS n + 1 ==============754 * CPU 0 | CPU 1755 * |756 * cnt1 timestamps | cnt2 timestamps757 * 3 | 5758 * 4 | 6759 * 5 | 7 <---- max recorded760 *761 * Flush every events below timestamp 4762 *763 * ============ PASS n + 2 ==============764 * CPU 0 | CPU 1765 * |766 * cnt1 timestamps | cnt2 timestamps767 * 6 | 8768 * 7 | 9769 * - | 10770 *771 * Flush every events below timestamp 7772 * etc...773 */774int perf_event__process_finished_round(const struct perf_tool *tool __maybe_unused,775 union perf_event *event __maybe_unused,776 struct ordered_events *oe)777{778 if (dump_trace)779 fprintf(stdout, "\n");780 return ordered_events__flush(oe, OE_FLUSH__ROUND);781}782 783int perf_session__queue_event(struct perf_session *s, union perf_event *event,784 u64 timestamp, u64 file_offset, const char *file_path)785{786 return ordered_events__queue(&s->ordered_events, event, timestamp, file_offset, file_path);787}788 789static void callchain__lbr_callstack_printf(struct perf_sample *sample)790{791 struct ip_callchain *callchain = sample->callchain;792 struct branch_stack *lbr_stack = sample->branch_stack;793 struct branch_entry *entries = perf_sample__branch_entries(sample);794 u64 kernel_callchain_nr = callchain->nr;795 unsigned int i;796 797 for (i = 0; i < kernel_callchain_nr; i++) {798 if (callchain->ips[i] == PERF_CONTEXT_USER)799 break;800 }801 802 if ((i != kernel_callchain_nr) && lbr_stack->nr) {803 u64 total_nr;804 /*805 * LBR callstack can only get user call chain,806 * i is kernel call chain number,807 * 1 is PERF_CONTEXT_USER.808 *809 * The user call chain is stored in LBR registers.810 * LBR are pair registers. The caller is stored811 * in "from" register, while the callee is stored812 * in "to" register.813 * For example, there is a call stack814 * "A"->"B"->"C"->"D".815 * The LBR registers will be recorded like816 * "C"->"D", "B"->"C", "A"->"B".817 * So only the first "to" register and all "from"818 * registers are needed to construct the whole stack.819 */820 total_nr = i + 1 + lbr_stack->nr + 1;821 kernel_callchain_nr = i + 1;822 823 printf("... LBR call chain: nr:%" PRIu64 "\n", total_nr);824 825 for (i = 0; i < kernel_callchain_nr; i++)826 printf("..... %2d: %016" PRIx64 "\n",827 i, callchain->ips[i]);828 829 printf("..... %2d: %016" PRIx64 "\n",830 (int)(kernel_callchain_nr), entries[0].to);831 for (i = 0; i < lbr_stack->nr; i++)832 printf("..... %2d: %016" PRIx64 "\n",833 (int)(i + kernel_callchain_nr + 1), entries[i].from);834 }835}836 837static void callchain__printf(struct evsel *evsel,838 struct perf_sample *sample)839{840 unsigned int i;841 struct ip_callchain *callchain = sample->callchain;842 843 if (evsel__has_branch_callstack(evsel))844 callchain__lbr_callstack_printf(sample);845 846 printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr);847 848 for (i = 0; i < callchain->nr; i++)849 printf("..... %2d: %016" PRIx64 "\n",850 i, callchain->ips[i]);851}852 853static void branch_stack__printf(struct perf_sample *sample,854 struct evsel *evsel)855{856 struct branch_entry *entries = perf_sample__branch_entries(sample);857 bool callstack = evsel__has_branch_callstack(evsel);858 u64 *branch_stack_cntr = sample->branch_stack_cntr;859 uint64_t i;860 861 if (!callstack) {862 printf("%s: nr:%" PRIu64 "\n", "... branch stack", sample->branch_stack->nr);863 } else {864 /* the reason of adding 1 to nr is because after expanding865 * branch stack it generates nr + 1 callstack records. e.g.,866 * B()->C()867 * A()->B()868 * the final callstack should be:869 * C()870 * B()871 * A()872 */873 printf("%s: nr:%" PRIu64 "\n", "... branch callstack", sample->branch_stack->nr+1);874 }875 876 for (i = 0; i < sample->branch_stack->nr; i++) {877 struct branch_entry *e = &entries[i];878 879 if (!callstack) {880 printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x %s %s\n",881 i, e->from, e->to,882 (unsigned short)e->flags.cycles,883 e->flags.mispred ? "M" : " ",884 e->flags.predicted ? "P" : " ",885 e->flags.abort ? "A" : " ",886 e->flags.in_tx ? "T" : " ",887 (unsigned)e->flags.reserved,888 get_branch_type(e),889 e->flags.spec ? branch_spec_desc(e->flags.spec) : "");890 } else {891 if (i == 0) {892 printf("..... %2"PRIu64": %016" PRIx64 "\n"893 "..... %2"PRIu64": %016" PRIx64 "\n",894 i, e->to, i+1, e->from);895 } else {896 printf("..... %2"PRIu64": %016" PRIx64 "\n", i+1, e->from);897 }898 }899 }900 901 if (branch_stack_cntr) {902 unsigned int br_cntr_width, br_cntr_nr;903 904 perf_env__find_br_cntr_info(evsel__env(evsel), &br_cntr_nr, &br_cntr_width);905 printf("... branch stack counters: nr:%" PRIu64 " (counter width: %u max counter nr:%u)\n",906 sample->branch_stack->nr, br_cntr_width, br_cntr_nr);907 for (i = 0; i < sample->branch_stack->nr; i++)908 printf("..... %2"PRIu64": %016" PRIx64 "\n", i, branch_stack_cntr[i]);909 }910}911 912static void regs_dump__printf(u64 mask, u64 *regs, const char *arch)913{914 unsigned rid, i = 0;915 916 for_each_set_bit(rid, (unsigned long *) &mask, sizeof(mask) * 8) {917 u64 val = regs[i++];918 919 printf(".... %-5s 0x%016" PRIx64 "\n",920 perf_reg_name(rid, arch), val);921 }922}923 924static const char *regs_abi[] = {925 [PERF_SAMPLE_REGS_ABI_NONE] = "none",926 [PERF_SAMPLE_REGS_ABI_32] = "32-bit",927 [PERF_SAMPLE_REGS_ABI_64] = "64-bit",928};929 930static inline const char *regs_dump_abi(struct regs_dump *d)931{932 if (d->abi > PERF_SAMPLE_REGS_ABI_64)933 return "unknown";934 935 return regs_abi[d->abi];936}937 938static void regs__printf(const char *type, struct regs_dump *regs, const char *arch)939{940 u64 mask = regs->mask;941 942 printf("... %s regs: mask 0x%" PRIx64 " ABI %s\n",943 type,944 mask,945 regs_dump_abi(regs));946 947 regs_dump__printf(mask, regs->regs, arch);948}949 950static void regs_user__printf(struct perf_sample *sample, const char *arch)951{952 struct regs_dump *user_regs = &sample->user_regs;953 954 if (user_regs->regs)955 regs__printf("user", user_regs, arch);956}957 958static void regs_intr__printf(struct perf_sample *sample, const char *arch)959{960 struct regs_dump *intr_regs = &sample->intr_regs;961 962 if (intr_regs->regs)963 regs__printf("intr", intr_regs, arch);964}965 966static void stack_user__printf(struct stack_dump *dump)967{968 printf("... ustack: size %" PRIu64 ", offset 0x%x\n",969 dump->size, dump->offset);970}971 972static void evlist__print_tstamp(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)973{974 u64 sample_type = __evlist__combined_sample_type(evlist);975 976 if (event->header.type != PERF_RECORD_SAMPLE &&977 !evlist__sample_id_all(evlist)) {978 fputs("-1 -1 ", stdout);979 return;980 }981 982 if ((sample_type & PERF_SAMPLE_CPU))983 printf("%u ", sample->cpu);984 985 if (sample_type & PERF_SAMPLE_TIME)986 printf("%" PRIu64 " ", sample->time);987}988 989static void sample_read__printf(struct perf_sample *sample, u64 read_format)990{991 printf("... sample_read:\n");992 993 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)994 printf("...... time enabled %016" PRIx64 "\n",995 sample->read.time_enabled);996 997 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)998 printf("...... time running %016" PRIx64 "\n",999 sample->read.time_running);1000 1001 if (read_format & PERF_FORMAT_GROUP) {1002 struct sample_read_value *value = sample->read.group.values;1003 1004 printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);1005 1006 sample_read_group__for_each(value, sample->read.group.nr, read_format) {1007 printf("..... id %016" PRIx641008 ", value %016" PRIx64,1009 value->id, value->value);1010 if (read_format & PERF_FORMAT_LOST)1011 printf(", lost %" PRIu64, value->lost);1012 printf("\n");1013 }1014 } else {1015 printf("..... id %016" PRIx64 ", value %016" PRIx64,1016 sample->read.one.id, sample->read.one.value);1017 if (read_format & PERF_FORMAT_LOST)1018 printf(", lost %" PRIu64, sample->read.one.lost);1019 printf("\n");1020 }1021}1022 1023static void dump_event(struct evlist *evlist, union perf_event *event,1024 u64 file_offset, struct perf_sample *sample,1025 const char *file_path)1026{1027 if (!dump_trace)1028 return;1029 1030 printf("\n%#" PRIx64 "@%s [%#x]: event: %d\n",1031 file_offset, file_path, event->header.size, event->header.type);1032 1033 trace_event(event);1034 if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw)1035 evlist->trace_event_sample_raw(evlist, event, sample);1036 1037 if (sample)1038 evlist__print_tstamp(evlist, event, sample);1039 1040 printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,1041 event->header.size, perf_event__name(event->header.type));1042}1043 1044char *get_page_size_name(u64 size, char *str)1045{1046 if (!size || !unit_number__scnprintf(str, PAGE_SIZE_NAME_LEN, size))1047 snprintf(str, PAGE_SIZE_NAME_LEN, "%s", "N/A");1048 1049 return str;1050}1051 1052static void dump_sample(struct evsel *evsel, union perf_event *event,1053 struct perf_sample *sample, const char *arch)1054{1055 u64 sample_type;1056 char str[PAGE_SIZE_NAME_LEN];1057 1058 if (!dump_trace)1059 return;1060 1061 printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",1062 event->header.misc, sample->pid, sample->tid, sample->ip,1063 sample->period, sample->addr);1064 1065 sample_type = evsel->core.attr.sample_type;1066 1067 if (evsel__has_callchain(evsel))1068 callchain__printf(evsel, sample);1069 1070 if (evsel__has_br_stack(evsel))1071 branch_stack__printf(sample, evsel);1072 1073 if (sample_type & PERF_SAMPLE_REGS_USER)1074 regs_user__printf(sample, arch);1075 1076 if (sample_type & PERF_SAMPLE_REGS_INTR)1077 regs_intr__printf(sample, arch);1078 1079 if (sample_type & PERF_SAMPLE_STACK_USER)1080 stack_user__printf(&sample->user_stack);1081 1082 if (sample_type & PERF_SAMPLE_WEIGHT_TYPE) {1083 printf("... weight: %" PRIu64 "", sample->weight);1084 if (sample_type & PERF_SAMPLE_WEIGHT_STRUCT) {1085 printf(",0x%"PRIx16"", sample->ins_lat);1086 printf(",0x%"PRIx16"", sample->p_stage_cyc);1087 }1088 printf("\n");1089 }1090 1091 if (sample_type & PERF_SAMPLE_DATA_SRC)1092 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);1093 1094 if (sample_type & PERF_SAMPLE_PHYS_ADDR)1095 printf(" .. phys_addr: 0x%"PRIx64"\n", sample->phys_addr);1096 1097 if (sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)1098 printf(" .. data page size: %s\n", get_page_size_name(sample->data_page_size, str));1099 1100 if (sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)1101 printf(" .. code page size: %s\n", get_page_size_name(sample->code_page_size, str));1102 1103 if (sample_type & PERF_SAMPLE_TRANSACTION)1104 printf("... transaction: %" PRIx64 "\n", sample->transaction);1105 1106 if (sample_type & PERF_SAMPLE_READ)1107 sample_read__printf(sample, evsel->core.attr.read_format);1108}1109 1110static void dump_read(struct evsel *evsel, union perf_event *event)1111{1112 struct perf_record_read *read_event = &event->read;1113 u64 read_format;1114 1115 if (!dump_trace)1116 return;1117 1118 printf(": %d %d %s %" PRI_lu64 "\n", event->read.pid, event->read.tid,1119 evsel__name(evsel), event->read.value);1120 1121 if (!evsel)1122 return;1123 1124 read_format = evsel->core.attr.read_format;1125 1126 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)1127 printf("... time enabled : %" PRI_lu64 "\n", read_event->time_enabled);1128 1129 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)1130 printf("... time running : %" PRI_lu64 "\n", read_event->time_running);1131 1132 if (read_format & PERF_FORMAT_ID)1133 printf("... id : %" PRI_lu64 "\n", read_event->id);1134 1135 if (read_format & PERF_FORMAT_LOST)1136 printf("... lost : %" PRI_lu64 "\n", read_event->lost);1137}1138 1139static struct machine *machines__find_for_cpumode(struct machines *machines,1140 union perf_event *event,1141 struct perf_sample *sample)1142{1143 if (perf_guest &&1144 ((sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||1145 (sample->cpumode == PERF_RECORD_MISC_GUEST_USER))) {1146 u32 pid;1147 1148 if (sample->machine_pid)1149 pid = sample->machine_pid;1150 else if (event->header.type == PERF_RECORD_MMAP1151 || event->header.type == PERF_RECORD_MMAP2)1152 pid = event->mmap.pid;1153 else1154 pid = sample->pid;1155 1156 /*1157 * Guest code machine is created as needed and does not use1158 * DEFAULT_GUEST_KERNEL_ID.1159 */1160 if (symbol_conf.guest_code)1161 return machines__findnew(machines, pid);1162 1163 return machines__find_guest(machines, pid);1164 }1165 1166 return &machines->host;1167}1168 1169static int deliver_sample_value(struct evlist *evlist,1170 const struct perf_tool *tool,1171 union perf_event *event,1172 struct perf_sample *sample,1173 struct sample_read_value *v,1174 struct machine *machine)1175{1176 struct perf_sample_id *sid = evlist__id2sid(evlist, v->id);1177 struct evsel *evsel;1178 1179 if (sid) {1180 sample->id = v->id;1181 sample->period = v->value - sid->period;1182 sid->period = v->value;1183 }1184 1185 if (!sid || sid->evsel == NULL) {1186 ++evlist->stats.nr_unknown_id;1187 return 0;1188 }1189 1190 /*1191 * There's no reason to deliver sample1192 * for zero period, bail out.1193 */1194 if (!sample->period)1195 return 0;1196 1197 evsel = container_of(sid->evsel, struct evsel, core);1198 return tool->sample(tool, event, sample, evsel, machine);1199}1200 1201static int deliver_sample_group(struct evlist *evlist,1202 const struct perf_tool *tool,1203 union perf_event *event,1204 struct perf_sample *sample,1205 struct machine *machine,1206 u64 read_format)1207{1208 int ret = -EINVAL;1209 struct sample_read_value *v = sample->read.group.values;1210 1211 if (tool->dont_split_sample_group)1212 return deliver_sample_value(evlist, tool, event, sample, v, machine);1213 1214 sample_read_group__for_each(v, sample->read.group.nr, read_format) {1215 ret = deliver_sample_value(evlist, tool, event, sample, v,1216 machine);1217 if (ret)1218 break;1219 }1220 1221 return ret;1222}1223 1224static int evlist__deliver_sample(struct evlist *evlist, const struct perf_tool *tool,1225 union perf_event *event, struct perf_sample *sample,1226 struct evsel *evsel, struct machine *machine)1227{1228 /* We know evsel != NULL. */1229 u64 sample_type = evsel->core.attr.sample_type;1230 u64 read_format = evsel->core.attr.read_format;1231 1232 /* Standard sample delivery. */1233 if (!(sample_type & PERF_SAMPLE_READ))1234 return tool->sample(tool, event, sample, evsel, machine);1235 1236 /* For PERF_SAMPLE_READ we have either single or group mode. */1237 if (read_format & PERF_FORMAT_GROUP)1238 return deliver_sample_group(evlist, tool, event, sample,1239 machine, read_format);1240 else1241 return deliver_sample_value(evlist, tool, event, sample,1242 &sample->read.one, machine);1243}1244 1245static int machines__deliver_event(struct machines *machines,1246 struct evlist *evlist,1247 union perf_event *event,1248 struct perf_sample *sample,1249 const struct perf_tool *tool, u64 file_offset,1250 const char *file_path)1251{1252 struct evsel *evsel;1253 struct machine *machine;1254 1255 dump_event(evlist, event, file_offset, sample, file_path);1256 1257 evsel = evlist__id2evsel(evlist, sample->id);1258 1259 machine = machines__find_for_cpumode(machines, event, sample);1260 1261 switch (event->header.type) {1262 case PERF_RECORD_SAMPLE:1263 if (evsel == NULL) {1264 ++evlist->stats.nr_unknown_id;1265 return 0;1266 }1267 if (machine == NULL) {1268 ++evlist->stats.nr_unprocessable_samples;1269 dump_sample(evsel, event, sample, perf_env__arch(NULL));1270 return 0;1271 }1272 dump_sample(evsel, event, sample, perf_env__arch(machine->env));1273 return evlist__deliver_sample(evlist, tool, event, sample, evsel, machine);1274 case PERF_RECORD_MMAP:1275 return tool->mmap(tool, event, sample, machine);1276 case PERF_RECORD_MMAP2:1277 if (event->header.misc & PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT)1278 ++evlist->stats.nr_proc_map_timeout;1279 return tool->mmap2(tool, event, sample, machine);1280 case PERF_RECORD_COMM:1281 return tool->comm(tool, event, sample, machine);1282 case PERF_RECORD_NAMESPACES:1283 return tool->namespaces(tool, event, sample, machine);1284 case PERF_RECORD_CGROUP:1285 return tool->cgroup(tool, event, sample, machine);1286 case PERF_RECORD_FORK:1287 return tool->fork(tool, event, sample, machine);1288 case PERF_RECORD_EXIT:1289 return tool->exit(tool, event, sample, machine);1290 case PERF_RECORD_LOST:1291 if (tool->lost == perf_event__process_lost)1292 evlist->stats.total_lost += event->lost.lost;1293 return tool->lost(tool, event, sample, machine);1294 case PERF_RECORD_LOST_SAMPLES:1295 if (event->header.misc & PERF_RECORD_MISC_LOST_SAMPLES_BPF)1296 evlist->stats.total_dropped_samples += event->lost_samples.lost;1297 else if (tool->lost_samples == perf_event__process_lost_samples)1298 evlist->stats.total_lost_samples += event->lost_samples.lost;1299 return tool->lost_samples(tool, event, sample, machine);1300 case PERF_RECORD_READ:1301 dump_read(evsel, event);1302 return tool->read(tool, event, sample, evsel, machine);1303 case PERF_RECORD_THROTTLE:1304 return tool->throttle(tool, event, sample, machine);1305 case PERF_RECORD_UNTHROTTLE:1306 return tool->unthrottle(tool, event, sample, machine);1307 case PERF_RECORD_AUX:1308 if (tool->aux == perf_event__process_aux) {1309 if (event->aux.flags & PERF_AUX_FLAG_TRUNCATED)1310 evlist->stats.total_aux_lost += 1;1311 if (event->aux.flags & PERF_AUX_FLAG_PARTIAL)1312 evlist->stats.total_aux_partial += 1;1313 if (event->aux.flags & PERF_AUX_FLAG_COLLISION)1314 evlist->stats.total_aux_collision += 1;1315 }1316 return tool->aux(tool, event, sample, machine);1317 case PERF_RECORD_ITRACE_START:1318 return tool->itrace_start(tool, event, sample, machine);1319 case PERF_RECORD_SWITCH:1320 case PERF_RECORD_SWITCH_CPU_WIDE:1321 return tool->context_switch(tool, event, sample, machine);1322 case PERF_RECORD_KSYMBOL:1323 return tool->ksymbol(tool, event, sample, machine);1324 case PERF_RECORD_BPF_EVENT:1325 return tool->bpf(tool, event, sample, machine);1326 case PERF_RECORD_TEXT_POKE:1327 return tool->text_poke(tool, event, sample, machine);1328 case PERF_RECORD_AUX_OUTPUT_HW_ID:1329 return tool->aux_output_hw_id(tool, event, sample, machine);1330 default:1331 ++evlist->stats.nr_unknown_events;1332 return -1;1333 }1334}1335 1336static int perf_session__deliver_event(struct perf_session *session,1337 union perf_event *event,1338 const struct perf_tool *tool,1339 u64 file_offset,1340 const char *file_path)1341{1342 struct perf_sample sample;1343 int ret = evlist__parse_sample(session->evlist, event, &sample);1344 1345 if (ret) {1346 pr_err("Can't parse sample, err = %d\n", ret);1347 return ret;1348 }1349 1350 ret = auxtrace__process_event(session, event, &sample, tool);1351 if (ret < 0)1352 return ret;1353 if (ret > 0)1354 return 0;1355 1356 ret = machines__deliver_event(&session->machines, session->evlist,1357 event, &sample, tool, file_offset, file_path);1358 1359 if (dump_trace && sample.aux_sample.size)1360 auxtrace__dump_auxtrace_sample(session, &sample);1361 1362 return ret;1363}1364 1365static s64 perf_session__process_user_event(struct perf_session *session,1366 union perf_event *event,1367 u64 file_offset,1368 const char *file_path)1369{1370 struct ordered_events *oe = &session->ordered_events;1371 const struct perf_tool *tool = session->tool;1372 struct perf_sample sample = { .time = 0, };1373 int fd = perf_data__fd(session->data);1374 int err;1375 1376 if (event->header.type != PERF_RECORD_COMPRESSED || perf_tool__compressed_is_stub(tool))1377 dump_event(session->evlist, event, file_offset, &sample, file_path);1378 1379 /* These events are processed right away */1380 switch (event->header.type) {1381 case PERF_RECORD_HEADER_ATTR:1382 err = tool->attr(tool, event, &session->evlist);1383 if (err == 0) {1384 perf_session__set_id_hdr_size(session);1385 perf_session__set_comm_exec(session);1386 }1387 return err;1388 case PERF_RECORD_EVENT_UPDATE:1389 return tool->event_update(tool, event, &session->evlist);1390 case PERF_RECORD_HEADER_EVENT_TYPE:1391 /*1392 * Deprecated, but we need to handle it for sake1393 * of old data files create in pipe mode.1394 */1395 return 0;1396 case PERF_RECORD_HEADER_TRACING_DATA:1397 /*1398 * Setup for reading amidst mmap, but only when we1399 * are in 'file' mode. The 'pipe' fd is in proper1400 * place already.1401 */1402 if (!perf_data__is_pipe(session->data))1403 lseek(fd, file_offset, SEEK_SET);1404 return tool->tracing_data(session, event);1405 case PERF_RECORD_HEADER_BUILD_ID:1406 return tool->build_id(session, event);1407 case PERF_RECORD_FINISHED_ROUND:1408 return tool->finished_round(tool, event, oe);1409 case PERF_RECORD_ID_INDEX:1410 return tool->id_index(session, event);1411 case PERF_RECORD_AUXTRACE_INFO:1412 return tool->auxtrace_info(session, event);1413 case PERF_RECORD_AUXTRACE:1414 /*1415 * Setup for reading amidst mmap, but only when we1416 * are in 'file' mode. The 'pipe' fd is in proper1417 * place already.1418 */1419 if (!perf_data__is_pipe(session->data))1420 lseek(fd, file_offset + event->header.size, SEEK_SET);1421 return tool->auxtrace(session, event);1422 case PERF_RECORD_AUXTRACE_ERROR:1423 perf_session__auxtrace_error_inc(session, event);1424 return tool->auxtrace_error(session, event);1425 case PERF_RECORD_THREAD_MAP:1426 return tool->thread_map(session, event);1427 case PERF_RECORD_CPU_MAP:1428 return tool->cpu_map(session, event);1429 case PERF_RECORD_STAT_CONFIG:1430 return tool->stat_config(session, event);1431 case PERF_RECORD_STAT:1432 return tool->stat(session, event);1433 case PERF_RECORD_STAT_ROUND:1434 return tool->stat_round(session, event);1435 case PERF_RECORD_TIME_CONV:1436 session->time_conv = event->time_conv;1437 return tool->time_conv(session, event);1438 case PERF_RECORD_HEADER_FEATURE:1439 return tool->feature(session, event);1440 case PERF_RECORD_COMPRESSED:1441 err = tool->compressed(session, event, file_offset, file_path);1442 if (err)1443 dump_event(session->evlist, event, file_offset, &sample, file_path);1444 return err;1445 case PERF_RECORD_FINISHED_INIT:1446 return tool->finished_init(session, event);1447 default:1448 return -EINVAL;1449 }1450}1451 1452int perf_session__deliver_synth_event(struct perf_session *session,1453 union perf_event *event,1454 struct perf_sample *sample)1455{1456 struct evlist *evlist = session->evlist;1457 const struct perf_tool *tool = session->tool;1458 1459 events_stats__inc(&evlist->stats, event->header.type);1460 1461 if (event->header.type >= PERF_RECORD_USER_TYPE_START)1462 return perf_session__process_user_event(session, event, 0, NULL);1463 1464 return machines__deliver_event(&session->machines, evlist, event, sample, tool, 0, NULL);1465}1466 1467int perf_session__deliver_synth_attr_event(struct perf_session *session,1468 const struct perf_event_attr *attr,1469 u64 id)1470{1471 union {1472 struct {1473 struct perf_record_header_attr attr;1474 u64 ids[1];1475 } attr_id;1476 union perf_event ev;1477 } ev = {1478 .attr_id.attr.header.type = PERF_RECORD_HEADER_ATTR,1479 .attr_id.attr.header.size = sizeof(ev.attr_id),1480 .attr_id.ids[0] = id,1481 };1482 1483 if (attr->size != sizeof(ev.attr_id.attr.attr)) {1484 pr_debug("Unexpected perf_event_attr size\n");1485 return -EINVAL;1486 }1487 ev.attr_id.attr.attr = *attr;1488 return perf_session__deliver_synth_event(session, &ev.ev, NULL);1489}1490 1491static void event_swap(union perf_event *event, bool sample_id_all)1492{1493 perf_event__swap_op swap;1494 1495 swap = perf_event__swap_ops[event->header.type];1496 if (swap)1497 swap(event, sample_id_all);1498}1499 1500int perf_session__peek_event(struct perf_session *session, off_t file_offset,1501 void *buf, size_t buf_sz,1502 union perf_event **event_ptr,1503 struct perf_sample *sample)1504{1505 union perf_event *event;1506 size_t hdr_sz, rest;1507 int fd;1508 1509 if (session->one_mmap && !session->header.needs_swap) {1510 event = file_offset - session->one_mmap_offset +1511 session->one_mmap_addr;1512 goto out_parse_sample;1513 }1514 1515 if (perf_data__is_pipe(session->data))1516 return -1;1517 1518 fd = perf_data__fd(session->data);1519 hdr_sz = sizeof(struct perf_event_header);1520 1521 if (buf_sz < hdr_sz)1522 return -1;1523 1524 if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||1525 readn(fd, buf, hdr_sz) != (ssize_t)hdr_sz)1526 return -1;1527 1528 event = (union perf_event *)buf;1529 1530 if (session->header.needs_swap)1531 perf_event_header__bswap(&event->header);1532 1533 if (event->header.size < hdr_sz || event->header.size > buf_sz)1534 return -1;1535 1536 buf += hdr_sz;1537 rest = event->header.size - hdr_sz;1538 1539 if (readn(fd, buf, rest) != (ssize_t)rest)1540 return -1;1541 1542 if (session->header.needs_swap)1543 event_swap(event, evlist__sample_id_all(session->evlist));1544 1545out_parse_sample:1546 1547 if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&1548 evlist__parse_sample(session->evlist, event, sample))1549 return -1;1550 1551 *event_ptr = event;1552 1553 return 0;1554}1555 1556int perf_session__peek_events(struct perf_session *session, u64 offset,1557 u64 size, peek_events_cb_t cb, void *data)1558{1559 u64 max_offset = offset + size;1560 char buf[PERF_SAMPLE_MAX_SIZE];1561 union perf_event *event;1562 int err;1563 1564 do {1565 err = perf_session__peek_event(session, offset, buf,1566 PERF_SAMPLE_MAX_SIZE, &event,1567 NULL);1568 if (err)1569 return err;1570 1571 err = cb(session, event, offset, data);1572 if (err)1573 return err;1574 1575 offset += event->header.size;1576 if (event->header.type == PERF_RECORD_AUXTRACE)1577 offset += event->auxtrace.size;1578 1579 } while (offset < max_offset);1580 1581 return err;1582}1583 1584static s64 perf_session__process_event(struct perf_session *session,1585 union perf_event *event, u64 file_offset,1586 const char *file_path)1587{1588 struct evlist *evlist = session->evlist;1589 const struct perf_tool *tool = session->tool;1590 int ret;1591 1592 if (session->header.needs_swap)1593 event_swap(event, evlist__sample_id_all(evlist));1594 1595 if (event->header.type >= PERF_RECORD_HEADER_MAX)1596 return -EINVAL;1597 1598 events_stats__inc(&evlist->stats, event->header.type);1599 1600 if (event->header.type >= PERF_RECORD_USER_TYPE_START)1601 return perf_session__process_user_event(session, event, file_offset, file_path);1602 1603 if (tool->ordered_events) {1604 u64 timestamp = -1ULL;1605 1606 ret = evlist__parse_sample_timestamp(evlist, event, ×tamp);1607 if (ret && ret != -1)1608 return ret;1609 1610 ret = perf_session__queue_event(session, event, timestamp, file_offset, file_path);1611 if (ret != -ETIME)1612 return ret;1613 }1614 1615 return perf_session__deliver_event(session, event, tool, file_offset, file_path);1616}1617 1618void perf_event_header__bswap(struct perf_event_header *hdr)1619{1620 hdr->type = bswap_32(hdr->type);1621 hdr->misc = bswap_16(hdr->misc);1622 hdr->size = bswap_16(hdr->size);1623}1624 1625struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)1626{1627 return machine__findnew_thread(&session->machines.host, -1, pid);1628}1629 1630int perf_session__register_idle_thread(struct perf_session *session)1631{1632 struct thread *thread = machine__idle_thread(&session->machines.host);1633 1634 /* machine__idle_thread() got the thread, so put it */1635 thread__put(thread);1636 return thread ? 0 : -1;1637}1638 1639static void1640perf_session__warn_order(const struct perf_session *session)1641{1642 const struct ordered_events *oe = &session->ordered_events;1643 struct evsel *evsel;1644 bool should_warn = true;1645 1646 evlist__for_each_entry(session->evlist, evsel) {1647 if (evsel->core.attr.write_backward)1648 should_warn = false;1649 }1650 1651 if (!should_warn)1652 return;1653 if (oe->nr_unordered_events != 0)1654 ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events);1655}1656 1657static void perf_session__warn_about_errors(const struct perf_session *session)1658{1659 const struct events_stats *stats = &session->evlist->stats;1660 1661 if (session->tool->lost == perf_event__process_lost &&1662 stats->nr_events[PERF_RECORD_LOST] != 0) {1663 ui__warning("Processed %d events and lost %d chunks!\n\n"1664 "Check IO/CPU overload!\n\n",1665 stats->nr_events[0],1666 stats->nr_events[PERF_RECORD_LOST]);1667 }1668 1669 if (session->tool->lost_samples == perf_event__process_lost_samples) {1670 double drop_rate;1671 1672 drop_rate = (double)stats->total_lost_samples /1673 (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples);1674 if (drop_rate > 0.05) {1675 ui__warning("Processed %" PRIu64 " samples and lost %3.2f%%!\n\n",1676 stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples,1677 drop_rate * 100.0);1678 }1679 }1680 1681 if (session->tool->aux == perf_event__process_aux &&1682 stats->total_aux_lost != 0) {1683 ui__warning("AUX data lost %" PRIu64 " times out of %u!\n\n",1684 stats->total_aux_lost,1685 stats->nr_events[PERF_RECORD_AUX]);1686 }1687 1688 if (session->tool->aux == perf_event__process_aux &&1689 stats->total_aux_partial != 0) {1690 bool vmm_exclusive = false;1691 1692 (void)sysfs__read_bool("module/kvm_intel/parameters/vmm_exclusive",1693 &vmm_exclusive);1694 1695 ui__warning("AUX data had gaps in it %" PRIu64 " times out of %u!\n\n"1696 "Are you running a KVM guest in the background?%s\n\n",1697 stats->total_aux_partial,1698 stats->nr_events[PERF_RECORD_AUX],1699 vmm_exclusive ?1700 "\nReloading kvm_intel module with vmm_exclusive=0\n"1701 "will reduce the gaps to only guest's timeslices." :1702 "");1703 }1704 1705 if (session->tool->aux == perf_event__process_aux &&1706 stats->total_aux_collision != 0) {1707 ui__warning("AUX data detected collision %" PRIu64 " times out of %u!\n\n",1708 stats->total_aux_collision,1709 stats->nr_events[PERF_RECORD_AUX]);1710 }1711 1712 if (stats->nr_unknown_events != 0) {1713 ui__warning("Found %u unknown events!\n\n"1714 "Is this an older tool processing a perf.data "1715 "file generated by a more recent tool?\n\n"1716 "If that is not the case, consider "1717 "reporting to linux-kernel@vger.kernel.org.\n\n",1718 stats->nr_unknown_events);1719 }1720 1721 if (stats->nr_unknown_id != 0) {1722 ui__warning("%u samples with id not present in the header\n",1723 stats->nr_unknown_id);1724 }1725 1726 if (stats->nr_invalid_chains != 0) {1727 ui__warning("Found invalid callchains!\n\n"1728 "%u out of %u events were discarded for this reason.\n\n"1729 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",1730 stats->nr_invalid_chains,1731 stats->nr_events[PERF_RECORD_SAMPLE]);1732 }1733 1734 if (stats->nr_unprocessable_samples != 0) {1735 ui__warning("%u unprocessable samples recorded.\n"1736 "Do you have a KVM guest running and not using 'perf kvm'?\n",1737 stats->nr_unprocessable_samples);1738 }1739 1740 perf_session__warn_order(session);1741 1742 events_stats__auxtrace_error_warn(stats);1743 1744 if (stats->nr_proc_map_timeout != 0) {1745 ui__warning("%d map information files for pre-existing threads were\n"1746 "not processed, if there are samples for addresses they\n"1747 "will not be resolved, you may find out which are these\n"1748 "threads by running with -v and redirecting the output\n"1749 "to a file.\n"1750 "The time limit to process proc map is too short?\n"1751 "Increase it by --proc-map-timeout\n",1752 stats->nr_proc_map_timeout);1753 }1754}1755 1756static int perf_session__flush_thread_stack(struct thread *thread,1757 void *p __maybe_unused)1758{1759 return thread_stack__flush(thread);1760}1761 1762static int perf_session__flush_thread_stacks(struct perf_session *session)1763{1764 return machines__for_each_thread(&session->machines,1765 perf_session__flush_thread_stack,1766 NULL);1767}1768 1769volatile sig_atomic_t session_done;1770 1771static int __perf_session__process_decomp_events(struct perf_session *session);1772 1773static int __perf_session__process_pipe_events(struct perf_session *session)1774{1775 struct ordered_events *oe = &session->ordered_events;1776 const struct perf_tool *tool = session->tool;1777 struct ui_progress prog;1778 union perf_event *event;1779 uint32_t size, cur_size = 0;1780 void *buf = NULL;1781 s64 skip = 0;1782 u64 head;1783 ssize_t err;1784 void *p;1785 bool update_prog = false;1786 1787 /*1788 * If it's from a file saving pipe data (by redirection), it would have1789 * a file name other than "-". Then we can get the total size and show1790 * the progress.1791 */1792 if (strcmp(session->data->path, "-") && session->data->file.size) {1793 ui_progress__init_size(&prog, session->data->file.size,1794 "Processing events...");1795 update_prog = true;1796 }1797 1798 head = 0;1799 cur_size = sizeof(union perf_event);1800 1801 buf = malloc(cur_size);1802 if (!buf)1803 return -errno;1804 ordered_events__set_copy_on_queue(oe, true);1805more:1806 event = buf;1807 err = perf_data__read(session->data, event,1808 sizeof(struct perf_event_header));1809 if (err <= 0) {1810 if (err == 0)1811 goto done;1812 1813 pr_err("failed to read event header\n");1814 goto out_err;1815 }1816 1817 if (session->header.needs_swap)1818 perf_event_header__bswap(&event->header);1819 1820 size = event->header.size;1821 if (size < sizeof(struct perf_event_header)) {1822 pr_err("bad event header size\n");1823 goto out_err;1824 }1825 1826 if (size > cur_size) {1827 void *new = realloc(buf, size);1828 if (!new) {1829 pr_err("failed to allocate memory to read event\n");1830 goto out_err;1831 }1832 buf = new;1833 cur_size = size;1834 event = buf;1835 }1836 p = event;1837 p += sizeof(struct perf_event_header);1838 1839 if (size - sizeof(struct perf_event_header)) {1840 err = perf_data__read(session->data, p,1841 size - sizeof(struct perf_event_header));1842 if (err <= 0) {1843 if (err == 0) {1844 pr_err("unexpected end of event stream\n");1845 goto done;1846 }1847 1848 pr_err("failed to read event data\n");1849 goto out_err;1850 }1851 }1852 1853 if ((skip = perf_session__process_event(session, event, head, "pipe")) < 0) {1854 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",1855 head, event->header.size, event->header.type);1856 err = -EINVAL;1857 goto out_err;1858 }1859 1860 head += size;1861 1862 if (skip > 0)1863 head += skip;1864 1865 err = __perf_session__process_decomp_events(session);1866 if (err)1867 goto out_err;1868 1869 if (update_prog)1870 ui_progress__update(&prog, size);1871 1872 if (!session_done())1873 goto more;1874done:1875 /* do the final flush for ordered samples */1876 err = ordered_events__flush(oe, OE_FLUSH__FINAL);1877 if (err)1878 goto out_err;1879 err = auxtrace__flush_events(session, tool);1880 if (err)1881 goto out_err;1882 err = perf_session__flush_thread_stacks(session);1883out_err:1884 free(buf);1885 if (update_prog)1886 ui_progress__finish();1887 if (!tool->no_warn)1888 perf_session__warn_about_errors(session);1889 ordered_events__free(&session->ordered_events);1890 auxtrace__free_events(session);1891 return err;1892}1893 1894static union perf_event *1895prefetch_event(char *buf, u64 head, size_t mmap_size,1896 bool needs_swap, union perf_event *error)1897{1898 union perf_event *event;1899 u16 event_size;1900 1901 /*1902 * Ensure we have enough space remaining to read1903 * the size of the event in the headers.1904 */1905 if (head + sizeof(event->header) > mmap_size)1906 return NULL;1907 1908 event = (union perf_event *)(buf + head);1909 if (needs_swap)1910 perf_event_header__bswap(&event->header);1911 1912 event_size = event->header.size;1913 if (head + event_size <= mmap_size)1914 return event;1915 1916 /* We're not fetching the event so swap back again */1917 if (needs_swap)1918 perf_event_header__bswap(&event->header);1919 1920 /* Check if the event fits into the next mmapped buf. */1921 if (event_size <= mmap_size - head % page_size) {1922 /* Remap buf and fetch again. */1923 return NULL;1924 }1925 1926 /* Invalid input. Event size should never exceed mmap_size. */1927 pr_debug("%s: head=%#" PRIx64 " event->header.size=%#x, mmap_size=%#zx:"1928 " fuzzed or compressed perf.data?\n", __func__, head, event_size, mmap_size);1929 1930 return error;1931}1932 1933static union perf_event *1934fetch_mmaped_event(u64 head, size_t mmap_size, char *buf, bool needs_swap)1935{1936 return prefetch_event(buf, head, mmap_size, needs_swap, ERR_PTR(-EINVAL));1937}1938 1939static union perf_event *1940fetch_decomp_event(u64 head, size_t mmap_size, char *buf, bool needs_swap)1941{1942 return prefetch_event(buf, head, mmap_size, needs_swap, NULL);1943}1944 1945static int __perf_session__process_decomp_events(struct perf_session *session)1946{1947 s64 skip;1948 u64 size;1949 struct decomp *decomp = session->active_decomp->decomp_last;1950 1951 if (!decomp)1952 return 0;1953 1954 while (decomp->head < decomp->size && !session_done()) {1955 union perf_event *event = fetch_decomp_event(decomp->head, decomp->size, decomp->data,1956 session->header.needs_swap);1957 1958 if (!event)1959 break;1960 1961 size = event->header.size;1962 1963 if (size < sizeof(struct perf_event_header) ||1964 (skip = perf_session__process_event(session, event, decomp->file_pos,1965 decomp->file_path)) < 0) {1966 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",1967 decomp->file_pos + decomp->head, event->header.size, event->header.type);1968 return -EINVAL;1969 }1970 1971 if (skip)1972 size += skip;1973 1974 decomp->head += size;1975 }1976 1977 return 0;1978}1979 1980/*1981 * On 64bit we can mmap the data file in one go. No need for tiny mmap1982 * slices. On 32bit we use 32MB.1983 */1984#if BITS_PER_LONG == 641985#define MMAP_SIZE ULLONG_MAX1986#define NUM_MMAPS 11987#else1988#define MMAP_SIZE (32 * 1024 * 1024ULL)1989#define NUM_MMAPS 1281990#endif1991 1992struct reader;1993 1994typedef s64 (*reader_cb_t)(struct perf_session *session,1995 union perf_event *event,1996 u64 file_offset,1997 const char *file_path);1998 1999struct reader {2000 int fd;2001 const char *path;2002 u64 data_size;2003 u64 data_offset;2004 reader_cb_t process;2005 bool in_place_update;2006 char *mmaps[NUM_MMAPS];2007 size_t mmap_size;2008 int mmap_idx;2009 char *mmap_cur;2010 u64 file_pos;2011 u64 file_offset;2012 u64 head;2013 u64 size;2014 bool done;2015 struct zstd_data zstd_data;2016 struct decomp_data decomp_data;2017};2018 2019static int2020reader__init(struct reader *rd, bool *one_mmap)2021{2022 u64 data_size = rd->data_size;2023 char **mmaps = rd->mmaps;2024 2025 rd->head = rd->data_offset;2026 data_size += rd->data_offset;2027 2028 rd->mmap_size = MMAP_SIZE;2029 if (rd->mmap_size > data_size) {2030 rd->mmap_size = data_size;2031 if (one_mmap)2032 *one_mmap = true;2033 }2034 2035 memset(mmaps, 0, sizeof(rd->mmaps));2036 2037 if (zstd_init(&rd->zstd_data, 0))2038 return -1;2039 rd->decomp_data.zstd_decomp = &rd->zstd_data;2040 2041 return 0;2042}2043 2044static void2045reader__release_decomp(struct reader *rd)2046{2047 perf_decomp__release_events(rd->decomp_data.decomp);2048 zstd_fini(&rd->zstd_data);2049}2050 2051static int2052reader__mmap(struct reader *rd, struct perf_session *session)2053{2054 int mmap_prot, mmap_flags;2055 char *buf, **mmaps = rd->mmaps;2056 u64 page_offset;2057 2058 mmap_prot = PROT_READ;2059 mmap_flags = MAP_SHARED;2060 2061 if (rd->in_place_update) {2062 mmap_prot |= PROT_WRITE;2063 } else if (session->header.needs_swap) {2064 mmap_prot |= PROT_WRITE;2065 mmap_flags = MAP_PRIVATE;2066 }2067 2068 if (mmaps[rd->mmap_idx]) {2069 munmap(mmaps[rd->mmap_idx], rd->mmap_size);2070 mmaps[rd->mmap_idx] = NULL;2071 }2072 2073 page_offset = page_size * (rd->head / page_size);2074 rd->file_offset += page_offset;2075 rd->head -= page_offset;2076 2077 buf = mmap(NULL, rd->mmap_size, mmap_prot, mmap_flags, rd->fd,2078 rd->file_offset);2079 if (buf == MAP_FAILED) {2080 pr_err("failed to mmap file\n");2081 return -errno;2082 }2083 mmaps[rd->mmap_idx] = rd->mmap_cur = buf;2084 rd->mmap_idx = (rd->mmap_idx + 1) & (ARRAY_SIZE(rd->mmaps) - 1);2085 rd->file_pos = rd->file_offset + rd->head;2086 if (session->one_mmap) {2087 session->one_mmap_addr = buf;2088 session->one_mmap_offset = rd->file_offset;2089 }2090 2091 return 0;2092}2093 2094enum {2095 READER_OK,2096 READER_NODATA,2097};2098 2099static int2100reader__read_event(struct reader *rd, struct perf_session *session,2101 struct ui_progress *prog)2102{2103 u64 size;2104 int err = READER_OK;2105 union perf_event *event;2106 s64 skip;2107 2108 event = fetch_mmaped_event(rd->head, rd->mmap_size, rd->mmap_cur,2109 session->header.needs_swap);2110 if (IS_ERR(event))2111 return PTR_ERR(event);2112 2113 if (!event)2114 return READER_NODATA;2115 2116 size = event->header.size;2117 2118 skip = -EINVAL;2119 2120 if (size < sizeof(struct perf_event_header) ||2121 (skip = rd->process(session, event, rd->file_pos, rd->path)) < 0) {2122 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d [%s]\n",2123 rd->file_offset + rd->head, event->header.size,2124 event->header.type, strerror(-skip));2125 err = skip;2126 goto out;2127 }2128 2129 if (skip)2130 size += skip;2131 2132 rd->size += size;2133 rd->head += size;2134 rd->file_pos += size;2135 2136 err = __perf_session__process_decomp_events(session);2137 if (err)2138 goto out;2139 2140 ui_progress__update(prog, size);2141 2142out:2143 return err;2144}2145 2146static inline bool2147reader__eof(struct reader *rd)2148{2149 return (rd->file_pos >= rd->data_size + rd->data_offset);2150}2151 2152static int2153reader__process_events(struct reader *rd, struct perf_session *session,2154 struct ui_progress *prog)2155{2156 int err;2157 2158 err = reader__init(rd, &session->one_mmap);2159 if (err)2160 goto out;2161 2162 session->active_decomp = &rd->decomp_data;2163 2164remap:2165 err = reader__mmap(rd, session);2166 if (err)2167 goto out;2168 2169more:2170 err = reader__read_event(rd, session, prog);2171 if (err < 0)2172 goto out;2173 else if (err == READER_NODATA)2174 goto remap;2175 2176 if (session_done())2177 goto out;2178 2179 if (!reader__eof(rd))2180 goto more;2181 2182out:2183 session->active_decomp = &session->decomp_data;2184 return err;2185}2186 2187static s64 process_simple(struct perf_session *session,2188 union perf_event *event,2189 u64 file_offset,2190 const char *file_path)2191{2192 return perf_session__process_event(session, event, file_offset, file_path);2193}2194 2195static int __perf_session__process_events(struct perf_session *session)2196{2197 struct reader rd = {2198 .fd = perf_data__fd(session->data),2199 .path = session->data->file.path,2200 .data_size = session->header.data_size,2201 .data_offset = session->header.data_offset,2202 .process = process_simple,2203 .in_place_update = session->data->in_place_update,2204 };2205 struct ordered_events *oe = &session->ordered_events;2206 const struct perf_tool *tool = session->tool;2207 struct ui_progress prog;2208 int err;2209 2210 if (rd.data_size == 0)2211 return -1;2212 2213 ui_progress__init_size(&prog, rd.data_size, "Processing events...");2214 2215 err = reader__process_events(&rd, session, &prog);2216 if (err)2217 goto out_err;2218 /* do the final flush for ordered samples */2219 err = ordered_events__flush(oe, OE_FLUSH__FINAL);2220 if (err)2221 goto out_err;2222 err = auxtrace__flush_events(session, tool);2223 if (err)2224 goto out_err;2225 err = perf_session__flush_thread_stacks(session);2226out_err:2227 ui_progress__finish();2228 if (!tool->no_warn)2229 perf_session__warn_about_errors(session);2230 /*2231 * We may switching perf.data output, make ordered_events2232 * reusable.2233 */2234 ordered_events__reinit(&session->ordered_events);2235 auxtrace__free_events(session);2236 reader__release_decomp(&rd);2237 session->one_mmap = false;2238 return err;2239}2240 2241/*2242 * Processing 2 MB of data from each reader in sequence,2243 * because that's the way the ordered events sorting works2244 * most efficiently.2245 */2246#define READER_MAX_SIZE (2 * 1024 * 1024)2247 2248/*2249 * This function reads, merge and process directory data.2250 * It assumens the version 1 of directory data, where each2251 * data file holds per-cpu data, already sorted by kernel.2252 */2253static int __perf_session__process_dir_events(struct perf_session *session)2254{2255 struct perf_data *data = session->data;2256 const struct perf_tool *tool = session->tool;2257 int i, ret, readers, nr_readers;2258 struct ui_progress prog;2259 u64 total_size = perf_data__size(session->data);2260 struct reader *rd;2261 2262 ui_progress__init_size(&prog, total_size, "Processing events...");2263 2264 nr_readers = 1;2265 for (i = 0; i < data->dir.nr; i++) {2266 if (data->dir.files[i].size)2267 nr_readers++;2268 }2269 2270 rd = zalloc(nr_readers * sizeof(struct reader));2271 if (!rd)2272 return -ENOMEM;2273 2274 rd[0] = (struct reader) {2275 .fd = perf_data__fd(session->data),2276 .path = session->data->file.path,2277 .data_size = session->header.data_size,2278 .data_offset = session->header.data_offset,2279 .process = process_simple,2280 .in_place_update = session->data->in_place_update,2281 };2282 ret = reader__init(&rd[0], NULL);2283 if (ret)2284 goto out_err;2285 ret = reader__mmap(&rd[0], session);2286 if (ret)2287 goto out_err;2288 readers = 1;2289 2290 for (i = 0; i < data->dir.nr; i++) {2291 if (!data->dir.files[i].size)2292 continue;2293 rd[readers] = (struct reader) {2294 .fd = data->dir.files[i].fd,2295 .path = data->dir.files[i].path,2296 .data_size = data->dir.files[i].size,2297 .data_offset = 0,2298 .process = process_simple,2299 .in_place_update = session->data->in_place_update,2300 };2301 ret = reader__init(&rd[readers], NULL);2302 if (ret)2303 goto out_err;2304 ret = reader__mmap(&rd[readers], session);2305 if (ret)2306 goto out_err;2307 readers++;2308 }2309 2310 i = 0;2311 while (readers) {2312 if (session_done())2313 break;2314 2315 if (rd[i].done) {2316 i = (i + 1) % nr_readers;2317 continue;2318 }2319 if (reader__eof(&rd[i])) {2320 rd[i].done = true;2321 readers--;2322 continue;2323 }2324 2325 session->active_decomp = &rd[i].decomp_data;2326 ret = reader__read_event(&rd[i], session, &prog);2327 if (ret < 0) {2328 goto out_err;2329 } else if (ret == READER_NODATA) {2330 ret = reader__mmap(&rd[i], session);2331 if (ret)2332 goto out_err;2333 }2334 2335 if (rd[i].size >= READER_MAX_SIZE) {2336 rd[i].size = 0;2337 i = (i + 1) % nr_readers;2338 }2339 }2340 2341 ret = ordered_events__flush(&session->ordered_events, OE_FLUSH__FINAL);2342 if (ret)2343 goto out_err;2344 2345 ret = perf_session__flush_thread_stacks(session);2346out_err:2347 ui_progress__finish();2348 2349 if (!tool->no_warn)2350 perf_session__warn_about_errors(session);2351 2352 /*2353 * We may switching perf.data output, make ordered_events2354 * reusable.2355 */2356 ordered_events__reinit(&session->ordered_events);2357 2358 session->one_mmap = false;2359 2360 session->active_decomp = &session->decomp_data;2361 for (i = 0; i < nr_readers; i++)2362 reader__release_decomp(&rd[i]);2363 zfree(&rd);2364 2365 return ret;2366}2367 2368int perf_session__process_events(struct perf_session *session)2369{2370 if (perf_session__register_idle_thread(session) < 0)2371 return -ENOMEM;2372 2373 if (perf_data__is_pipe(session->data))2374 return __perf_session__process_pipe_events(session);2375 2376 if (perf_data__is_dir(session->data) && session->data->dir.nr)2377 return __perf_session__process_dir_events(session);2378 2379 return __perf_session__process_events(session);2380}2381 2382bool perf_session__has_traces(struct perf_session *session, const char *msg)2383{2384 struct evsel *evsel;2385 2386 evlist__for_each_entry(session->evlist, evsel) {2387 if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT)2388 return true;2389 }2390 2391 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);2392 return false;2393}2394 2395int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name, u64 addr)2396{2397 char *bracket;2398 struct ref_reloc_sym *ref;2399 struct kmap *kmap;2400 2401 ref = zalloc(sizeof(struct ref_reloc_sym));2402 if (ref == NULL)2403 return -ENOMEM;2404 2405 ref->name = strdup(symbol_name);2406 if (ref->name == NULL) {2407 free(ref);2408 return -ENOMEM;2409 }2410 2411 bracket = strchr(ref->name, ']');2412 if (bracket)2413 *bracket = '\0';2414 2415 ref->addr = addr;2416 2417 kmap = map__kmap(map);2418 if (kmap)2419 kmap->ref_reloc_sym = ref;2420 2421 return 0;2422}2423 2424size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp)2425{2426 return machines__fprintf_dsos(&session->machines, fp);2427}2428 2429size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,2430 bool (skip)(struct dso *dso, int parm), int parm)2431{2432 return machines__fprintf_dsos_buildid(&session->machines, fp, skip, parm);2433}2434 2435size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)2436{2437 size_t ret;2438 const char *msg = "";2439 2440 if (perf_header__has_feat(&session->header, HEADER_AUXTRACE))2441 msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)";2442 2443 ret = fprintf(fp, "\nAggregated stats:%s\n", msg);2444 2445 ret += events_stats__fprintf(&session->evlist->stats, fp);2446 return ret;2447}2448 2449size_t perf_session__fprintf(struct perf_session *session, FILE *fp)2450{2451 /*2452 * FIXME: Here we have to actually print all the machines in this2453 * session, not just the host...2454 */2455 return machine__fprintf(&session->machines.host, fp);2456}2457 2458void perf_session__dump_kmaps(struct perf_session *session)2459{2460 int save_verbose = verbose;2461 2462 fflush(stdout);2463 fprintf(stderr, "Kernel and module maps:\n");2464 verbose = 0; /* Suppress verbose to print a summary only */2465 maps__fprintf(machine__kernel_maps(&session->machines.host), stderr);2466 verbose = save_verbose;2467}2468 2469struct evsel *perf_session__find_first_evtype(struct perf_session *session,2470 unsigned int type)2471{2472 struct evsel *pos;2473 2474 evlist__for_each_entry(session->evlist, pos) {2475 if (pos->core.attr.type == type)2476 return pos;2477 }2478 return NULL;2479}2480 2481int perf_session__cpu_bitmap(struct perf_session *session,2482 const char *cpu_list, unsigned long *cpu_bitmap)2483{2484 int i, err = -1;2485 struct perf_cpu_map *map;2486 int nr_cpus = min(session->header.env.nr_cpus_avail, MAX_NR_CPUS);2487 struct perf_cpu cpu;2488 2489 for (i = 0; i < PERF_TYPE_MAX; ++i) {2490 struct evsel *evsel;2491 2492 evsel = perf_session__find_first_evtype(session, i);2493 if (!evsel)2494 continue;2495 2496 if (!(evsel->core.attr.sample_type & PERF_SAMPLE_CPU)) {2497 pr_err("File does not contain CPU events. "2498 "Remove -C option to proceed.\n");2499 return -1;2500 }2501 }2502 2503 map = perf_cpu_map__new(cpu_list);2504 if (map == NULL) {2505 pr_err("Invalid cpu_list\n");2506 return -1;2507 }2508 2509 perf_cpu_map__for_each_cpu(cpu, i, map) {2510 if (cpu.cpu >= nr_cpus) {2511 pr_err("Requested CPU %d too large. "2512 "Consider raising MAX_NR_CPUS\n", cpu.cpu);2513 goto out_delete_map;2514 }2515 2516 __set_bit(cpu.cpu, cpu_bitmap);2517 }2518 2519 err = 0;2520 2521out_delete_map:2522 perf_cpu_map__put(map);2523 return err;2524}2525 2526void perf_session__fprintf_info(struct perf_session *session, FILE *fp,2527 bool full)2528{2529 if (session == NULL || fp == NULL)2530 return;2531 2532 fprintf(fp, "# ========\n");2533 perf_header__fprintf_info(session, fp, full);2534 fprintf(fp, "# ========\n#\n");2535}2536 2537static int perf_session__register_guest(struct perf_session *session, pid_t machine_pid)2538{2539 struct machine *machine = machines__findnew(&session->machines, machine_pid);2540 struct thread *thread;2541 2542 if (!machine)2543 return -ENOMEM;2544 2545 machine->single_address_space = session->machines.host.single_address_space;2546 2547 thread = machine__idle_thread(machine);2548 if (!thread)2549 return -ENOMEM;2550 thread__put(thread);2551 2552 machine->kallsyms_filename = perf_data__guest_kallsyms_name(session->data, machine_pid);2553 2554 return 0;2555}2556 2557static int perf_session__set_guest_cpu(struct perf_session *session, pid_t pid,2558 pid_t tid, int guest_cpu)2559{2560 struct machine *machine = &session->machines.host;2561 struct thread *thread = machine__findnew_thread(machine, pid, tid);2562 2563 if (!thread)2564 return -ENOMEM;2565 thread__set_guest_cpu(thread, guest_cpu);2566 thread__put(thread);2567 2568 return 0;2569}2570 2571int perf_event__process_id_index(struct perf_session *session,2572 union perf_event *event)2573{2574 struct evlist *evlist = session->evlist;2575 struct perf_record_id_index *ie = &event->id_index;2576 size_t sz = ie->header.size - sizeof(*ie);2577 size_t i, nr, max_nr;2578 size_t e1_sz = sizeof(struct id_index_entry);2579 size_t e2_sz = sizeof(struct id_index_entry_2);2580 size_t etot_sz = e1_sz + e2_sz;2581 struct id_index_entry_2 *e2;2582 pid_t last_pid = 0;2583 2584 max_nr = sz / e1_sz;2585 nr = ie->nr;2586 if (nr > max_nr) {2587 printf("Too big: nr %zu max_nr %zu\n", nr, max_nr);2588 return -EINVAL;2589 }2590 2591 if (sz >= nr * etot_sz) {2592 max_nr = sz / etot_sz;2593 if (nr > max_nr) {2594 printf("Too big2: nr %zu max_nr %zu\n", nr, max_nr);2595 return -EINVAL;2596 }2597 e2 = (void *)ie + sizeof(*ie) + nr * e1_sz;2598 } else {2599 e2 = NULL;2600 }2601 2602 if (dump_trace)2603 fprintf(stdout, " nr: %zu\n", nr);2604 2605 for (i = 0; i < nr; i++, (e2 ? e2++ : 0)) {2606 struct id_index_entry *e = &ie->entries[i];2607 struct perf_sample_id *sid;2608 int ret;2609 2610 if (dump_trace) {2611 fprintf(stdout, " ... id: %"PRI_lu64, e->id);2612 fprintf(stdout, " idx: %"PRI_lu64, e->idx);2613 fprintf(stdout, " cpu: %"PRI_ld64, e->cpu);2614 fprintf(stdout, " tid: %"PRI_ld64, e->tid);2615 if (e2) {2616 fprintf(stdout, " machine_pid: %"PRI_ld64, e2->machine_pid);2617 fprintf(stdout, " vcpu: %"PRI_lu64"\n", e2->vcpu);2618 } else {2619 fprintf(stdout, "\n");2620 }2621 }2622 2623 sid = evlist__id2sid(evlist, e->id);2624 if (!sid)2625 return -ENOENT;2626 2627 sid->idx = e->idx;2628 sid->cpu.cpu = e->cpu;2629 sid->tid = e->tid;2630 2631 if (!e2)2632 continue;2633 2634 sid->machine_pid = e2->machine_pid;2635 sid->vcpu.cpu = e2->vcpu;2636 2637 if (!sid->machine_pid)2638 continue;2639 2640 if (sid->machine_pid != last_pid) {2641 ret = perf_session__register_guest(session, sid->machine_pid);2642 if (ret)2643 return ret;2644 last_pid = sid->machine_pid;2645 perf_guest = true;2646 }2647 2648 ret = perf_session__set_guest_cpu(session, sid->machine_pid, e->tid, e2->vcpu);2649 if (ret)2650 return ret;2651 }2652 return 0;2653}2654 2655int perf_session__dsos_hit_all(struct perf_session *session)2656{2657 struct rb_node *nd;2658 int err;2659 2660 err = machine__hit_all_dsos(&session->machines.host);2661 if (err)2662 return err;2663 2664 for (nd = rb_first_cached(&session->machines.guests); nd;2665 nd = rb_next(nd)) {2666 struct machine *pos = rb_entry(nd, struct machine, rb_node);2667 2668 err = machine__hit_all_dsos(pos);2669 if (err)2670 return err;2671 }2672 2673 return 0;2674}2675