#include <linux/kernel.h>#include <traceevent/event-parse.h> #include <byteswap.h>#include <unistd.h>#include <sys/types.h>#include <sys/mman.h> #include "evlist.h"#include "evsel.h"#include "session.h"#include "tool.h"#include "sort.h"#include "util.h"#include "cpumap.h"#include "perf_regs.h"#include "vdso.h" static int perf_session__open(struct perf_session *session){ struct perf_data_file *file = session->file; if (perf_session__read_header(session) < 0) { pr_err("incompatible file format (rerun with -v to learn more)"); return -1; } if (perf_data_file__is_pipe(file)) return 0; if (!perf_evlist__valid_sample_type(session->evlist)) { pr_err("non matching sample_type"); return -1; } if (!perf_evlist__valid_sample_id_all(session->evlist)) { pr_err("non matching sample_id_all"); return -1; } if (!perf_evlist__valid_read_format(session->evlist)) { pr_err("non matching read_format"); return -1; } return 0;} void perf_session__set_id_hdr_size(struct perf_session *session){ u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); machines__set_id_hdr_size(&session->machines, id_hdr_size);} int perf_session__create_kernel_maps(struct perf_session *session){ int ret = machine__create_kernel_maps(&session->machines.host); if (ret >= 0) ret = machines__create_guest_kernel_maps(&session->machines); return ret;} static void perf_session__destroy_kernel_maps(struct perf_session *session){ machines__destroy_kernel_maps(&session->machines);} struct perf_session *perf_session__new(struct perf_data_file *file, bool repipe, struct perf_tool *tool){ struct perf_session *session = zalloc(sizeof(*session)); if (!session) goto out; session->repipe = repipe; INIT_LIST_HEAD(&session->ordered_samples.samples); INIT_LIST_HEAD(&session->ordered_samples.sample_cache); INIT_LIST_HEAD(&session->ordered_samples.to_free); machines__init(&session->machines); if (file) { if (perf_data_file__open(file)) goto out_delete; session->file = file; if (perf_data_file__is_read(file)) { if (perf_session__open(session) < 0) goto out_close; perf_session__set_id_hdr_size(session); } } if (!file || perf_data_file__is_write(file)) { /* * In O_RDONLY mode this will be performed when reading the * kernel MMAP event, in perf_event__process_mmap(). */ if (perf_session__create_kernel_maps(session) < 0) goto out_delete; } if (tool && tool->ordering_requires_timestamps && tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_samples = false; } return session; out_close: perf_data_file__close(file); out_delete: perf_session__delete(session); out: return NULL;} static void perf_session__delete_dead_threads(struct perf_session *session){ machine__delete_dead_threads(&session->machines.host);} static void perf_session__delete_threads(struct perf_session *session){ machine__delete_threads(&session->machines.host);} static void perf_session_env__delete(struct perf_session_env *env){ free(env->hostname); free(env->os_release); free(env->version); free(env->arch); free(env->cpu_desc); free(env->cpuid); free(env->cmdline); free(env->sibling_cores); free(env->sibling_threads); free(env->numa_nodes); free(env->pmu_mappings);} void perf_session__delete(struct perf_session *session){ perf_session__destroy_kernel_maps(session); perf_session__delete_dead_threads(session); perf_session__delete_threads(session); perf_session_env__delete(&session->header.env); machines__exit(&session->machines); if (session->file) perf_data_file__close(session->file); free(session); vdso__exit();} static int process_event_synth_tracing_data_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused){ dump_printf(": unhandled!\n"); return 0;} static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_evlist **pevlist __maybe_unused){ dump_printf(": unhandled!\n"); return 0;} static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct perf_evsel *evsel __maybe_unused, struct machine *machine __maybe_unused){ dump_printf(": unhandled!\n"); return 0;} static int process_event_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused){ dump_printf(": unhandled!\n"); return 0;} static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *perf_session __maybe_unused){ dump_printf(": unhandled!\n"); return 0;} static int process_finished_round(struct perf_tool *tool, union perf_event *event, struct perf_session *session); void perf_tool__fill_defaults(struct perf_tool *tool){ if (tool->sample == NULL) tool->sample = process_event_sample_stub; if (tool->mmap == NULL) tool->mmap = process_event_stub; if (tool->mmap2 == NULL) tool->mmap2 = process_event_stub; if (tool->comm == NULL) tool->comm = process_event_stub; if (tool->fork == NULL) tool->fork = process_event_stub; if (tool->exit == NULL) tool->exit = process_event_stub; if (tool->lost == NULL) tool->lost = perf_event__process_lost; if (tool->read == NULL) tool->read = process_event_sample_stub; if (tool->throttle == NULL) tool->throttle = process_event_stub; if (tool->unthrottle == NULL) tool->unthrottle = process_event_stub; if (tool->attr == NULL) tool->attr = process_event_synth_attr_stub; if (tool->tracing_data == NULL) tool->tracing_data = process_event_synth_tracing_data_stub; if (tool->build_id == NULL) tool->build_id = process_finished_round_stub; if (tool->finished_round == NULL) { if (tool->ordered_samples) tool->finished_round = process_finished_round; else tool->finished_round = process_finished_round_stub; }} void mem_bswap_32(void *src, int byte_size){ u32 *m = src; while (byte_size > 0) { *m = bswap_32(*m); byte_size -= sizeof(u32); ++m; }} void mem_bswap_64(void *src, int byte_size){ u64 *m = src; while (byte_size > 0) { *m = bswap_64(*m); byte_size -= sizeof(u64); ++m; }} static void swap_sample_id_all(union perf_event *event, void *data){ void *end = (void *) event + event->header.size; int size = end - data; BUG_ON(size % sizeof(u64)); mem_bswap_64(data, size);} static void perf_event__all64_swap(union perf_event *event, bool sample_id_all __maybe_unused){ struct perf_event_header *hdr = &event->header; mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));} static void perf_event__comm_swap(union perf_event *event, bool sample_id_all){ event->comm.pid = bswap_32(event->comm.pid); event->comm.tid = bswap_32(event->comm.tid); if (sample_id_all) { void *data = &event->comm.comm; data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); swap_sample_id_all(event, data); }} static void perf_event__mmap_swap(union perf_event *event, bool sample_id_all){ event->mmap.pid = bswap_32(event->mmap.pid); event->mmap.tid = bswap_32(event->mmap.tid); event->mmap.start = bswap_64(event->mmap.start); event->mmap.len = bswap_64(event->mmap.len); event->mmap.pgoff = bswap_64(event->mmap.pgoff); if (sample_id_all) { void *data = &event->mmap.filename; data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); swap_sample_id_all(event, data); }} static void perf_event__mmap2_swap(union perf_event *event, bool sample_id_all){ event->mmap2.pid = bswap_32(event->mmap2.pid); event->mmap2.tid = bswap_32(event->mmap2.tid); event->mmap2.start = bswap_64(event->mmap2.start); event->mmap2.len = bswap_64(event->mmap2.len); event->mmap2.pgoff = bswap_64(event->mmap2.pgoff); event->mmap2.maj = bswap_32(event->mmap2.maj); event->mmap2.min = bswap_32(event->mmap2.min); event->mmap2.ino = bswap_64(event->mmap2.ino); if (sample_id_all) { void *data = &event->mmap2.filename; data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); swap_sample_id_all(event, data); }}static void perf_event__task_swap(union perf_event *event, bool sample_id_all){ event->fork.pid = bswap_32(event->fork.pid); event->fork.tid = bswap_32(event->fork.tid); event->fork.ppid = bswap_32(event->fork.ppid); event->fork.ptid = bswap_32(event->fork.ptid); event->fork.time = bswap_64(event->fork.time); if (sample_id_all) swap_sample_id_all(event, &event->fork + 1);} static void perf_event__read_swap(union perf_event *event, bool sample_id_all){ event->read.pid = bswap_32(event->read.pid); event->read.tid = bswap_32(event->read.tid); event->read.value = bswap_64(event->read.value); event->read.time_enabled = bswap_64(event->read.time_enabled); event->read.time_running = bswap_64(event->read.time_running); event->read.id = bswap_64(event->read.id); if (sample_id_all) swap_sample_id_all(event, &event->read + 1);} static void perf_event__throttle_swap(union perf_event *event, bool sample_id_all){ event->throttle.time = bswap_64(event->throttle.time); event->throttle.id = bswap_64(event->throttle.id); event->throttle.stream_id = bswap_64(event->throttle.stream_id); if (sample_id_all) swap_sample_id_all(event, &event->throttle + 1);} static u8 revbyte(u8 b){ int rev = (b >> 4) | ((b & 0xf) << 4); rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2); rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1); return (u8) rev;} /* * XXX this is hack in attempt to carry flags bitfield * throught endian village. ABI says: * * Bit-fields are allocated from right to left (least to most significant) * on little-endian implementations and from left to right (most to least * significant) on big-endian implementations. * * The above seems to be byte specific, so we need to reverse each * byte of the bitfield. 'Internet' also says this might be implementation * specific and we probably need proper fix and carry perf_event_attr * bitfield flags in separate data file FEAT_ section. Thought this seems * to work for now. */static void swap_bitfield(u8 *p, unsigned len){ unsigned i; for (i = 0; i < len; i++) { *p = revbyte(*p); p++; }} /* exported for swapping attributes in file header */void perf_event__attr_swap(struct perf_event_attr *attr){ attr->type = bswap_32(attr->type); attr->size = bswap_32(attr->size); attr->config = bswap_64(attr->config); attr->sample_period = bswap_64(attr->sample_period); attr->sample_type = bswap_64(attr->sample_type); attr->read_format = bswap_64(attr->read_format); attr->wakeup_events = bswap_32(attr->wakeup_events); attr->bp_type = bswap_32(attr->bp_type); attr->bp_addr = bswap_64(attr->bp_addr); attr->bp_len = bswap_64(attr->bp_len); attr->branch_sample_type = bswap_64(attr->branch_sample_type); attr->sample_regs_user = bswap_64(attr->sample_regs_user); attr->sample_stack_user = bswap_32(attr->sample_stack_user); swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));} static void perf_event__hdr_attr_swap(union perf_event *event, bool sample_id_all __maybe_unused){ size_t size; perf_event__attr_swap(&event->attr.attr); size = event->header.size; size -= (void *)&event->attr.id - (void *)event; mem_bswap_64(event->attr.id, size);} static void perf_event__event_type_swap(union perf_event *event, bool sample_id_all __maybe_unused){ event->event_type.event_type.event_id = bswap_64(event->event_type.event_type.event_id);} static void perf_event__tracing_data_swap(union perf_event *event, bool sample_id_all __maybe_unused){ event->tracing_data.size = bswap_32(event->tracing_data.size);} typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_MMAP] = perf_event__mmap_swap, [PERF_RECORD_MMAP2] = perf_event__mmap2_swap, [PERF_RECORD_COMM] = perf_event__comm_swap, [PERF_RECORD_FORK] = perf_event__task_swap, [PERF_RECORD_EXIT] = perf_event__task_swap, [PERF_RECORD_LOST] = perf_event__all64_swap, [PERF_RECORD_READ] = perf_event__read_swap, [PERF_RECORD_THROTTLE] = perf_event__throttle_swap, [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap, [PERF_RECORD_SAMPLE] = perf_event__all64_swap, [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, [PERF_RECORD_HEADER_BUILD_ID] = NULL, [PERF_RECORD_HEADER_MAX] = NULL,}; struct sample_queue { u64 timestamp; u64 file_offset; union perf_event *event; struct list_head list;}; static void perf_session_free_sample_buffers(struct perf_session *session){ struct ordered_samples *os = &session->ordered_samples; while (!list_empty(&os->to_free)) { struct sample_queue *sq; sq = list_entry(os->to_free.next, struct sample_queue, list); list_del(&sq->list); free(sq); }} static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, struct perf_tool *tool, u64 file_offset); static int flush_sample_queue(struct perf_session *s, struct perf_tool *tool){ struct ordered_samples *os = &s->ordered_samples; struct list_head *head = &os->samples;Lines 1–500 of 1661. Load more
#include <linux/kernel.h> #include <traceevent/event-parse.h> #include <byteswap.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include "evlist.h" #include "evsel.h" #include "session.h" #include "tool.h" #include "sort.h" #include "util.h" #include "cpumap.h" #include "perf_regs.h" #include "vdso.h" static int perf_session__open(struct perf_session *session) { struct perf_data_file *file = session->file; if (perf_session__read_header(session) < 0) { pr_err("incompatible file format (rerun with -v to learn more)"); return -1; } if (perf_data_file__is_pipe(file)) return 0; if (!perf_evlist__valid_sample_type(session->evlist)) { pr_err("non matching sample_type"); return -1; } if (!perf_evlist__valid_sample_id_all(session->evlist)) { pr_err("non matching sample_id_all"); return -1; } if (!perf_evlist__valid_read_format(session->evlist)) { pr_err("non matching read_format"); return -1; } return 0; } void perf_session__set_id_hdr_size(struct perf_session *session) { u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); machines__set_id_hdr_size(&session->machines, id_hdr_size); } int perf_session__create_kernel_maps(struct perf_session *session) { int ret = machine__create_kernel_maps(&session->machines.host); if (ret >= 0) ret = machines__create_guest_kernel_maps(&session->machines); return ret; } static void perf_session__destroy_kernel_maps(struct perf_session *session) { machines__destroy_kernel_maps(&session->machines); } struct perf_session *perf_session__new(struct perf_data_file *file, bool repipe, struct perf_tool *tool) { struct perf_session *session = zalloc(sizeof(*session)); if (!session) goto out; session->repipe = repipe; INIT_LIST_HEAD(&session->ordered_samples.samples); INIT_LIST_HEAD(&session->ordered_samples.sample_cache); INIT_LIST_HEAD(&session->ordered_samples.to_free); machines__init(&session->machines); if (file) { if (perf_data_file__open(file)) goto out_delete; session->file = file; if (perf_data_file__is_read(file)) { if (perf_session__open(session) < 0) goto out_close; perf_session__set_id_hdr_size(session); } } if (!file || perf_data_file__is_write(file)) { /* * In O_RDONLY mode this will be performed when reading the * kernel MMAP event, in perf_event__process_mmap(). */ if (perf_session__create_kernel_maps(session) < 0) goto out_delete; } if (tool && tool->ordering_requires_timestamps && tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_samples = false; } return session; out_close: perf_data_file__close(file); out_delete: perf_session__delete(session); out: return NULL; } static void perf_session__delete_dead_threads(struct perf_session *session) { machine__delete_dead_threads(&session->machines.host); } static void perf_session__delete_threads(struct perf_session *session) { machine__delete_threads(&session->machines.host); } static void perf_session_env__delete(struct perf_session_env *env) { free(env->hostname); free(env->os_release); free(env->version); free(env->arch); free(env->cpu_desc); free(env->cpuid); free(env->cmdline); free(env->sibling_cores); free(env->sibling_threads); free(env->numa_nodes); free(env->pmu_mappings); } void perf_session__delete(struct perf_session *session) { perf_session__destroy_kernel_maps(session); perf_session__delete_dead_threads(session); perf_session__delete_threads(session); perf_session_env__delete(&session->header.env); machines__exit(&session->machines); if (session->file) perf_data_file__close(session->file); free(session); vdso__exit(); } static int process_event_synth_tracing_data_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { dump_printf(": unhandled!\n"); return 0; } static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_evlist **pevlist __maybe_unused) { dump_printf(": unhandled!\n"); return 0; } static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct perf_evsel *evsel __maybe_unused, struct machine *machine __maybe_unused) { dump_printf(": unhandled!\n"); return 0; } static int process_event_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { dump_printf(": unhandled!\n"); return 0; } static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *perf_session __maybe_unused) { dump_printf(": unhandled!\n"); return 0; } static int process_finished_round(struct perf_tool *tool, union perf_event *event, struct perf_session *session); void perf_tool__fill_defaults(struct perf_tool *tool) { if (tool->sample == NULL) tool->sample = process_event_sample_stub; if (tool->mmap == NULL) tool->mmap = process_event_stub; if (tool->mmap2 == NULL) tool->mmap2 = process_event_stub; if (tool->comm == NULL) tool->comm = process_event_stub; if (tool->fork == NULL) tool->fork = process_event_stub; if (tool->exit == NULL) tool->exit = process_event_stub; if (tool->lost == NULL) tool->lost = perf_event__process_lost; if (tool->read == NULL) tool->read = process_event_sample_stub; if (tool->throttle == NULL) tool->throttle = process_event_stub; if (tool->unthrottle == NULL) tool->unthrottle = process_event_stub; if (tool->attr == NULL) tool->attr = process_event_synth_attr_stub; if (tool->tracing_data == NULL) tool->tracing_data = process_event_synth_tracing_data_stub; if (tool->build_id == NULL) tool->build_id = process_finished_round_stub; if (tool->finished_round == NULL) { if (tool->ordered_samples) tool->finished_round = process_finished_round; else tool->finished_round = process_finished_round_stub; } } void mem_bswap_32(void *src, int byte_size) { u32 *m = src; while (byte_size > 0) { *m = bswap_32(*m); byte_size -= sizeof(u32); ++m; } } void mem_bswap_64(void *src, int byte_size) { u64 *m = src; while (byte_size > 0) { *m = bswap_64(*m); byte_size -= sizeof(u64); ++m; } } static void swap_sample_id_all(union perf_event *event, void *data) { void *end = (void *) event + event->header.size; int size = end - data; BUG_ON(size % sizeof(u64)); mem_bswap_64(data, size); } static void perf_event__all64_swap(union perf_event *event, bool sample_id_all __maybe_unused) { struct perf_event_header *hdr = &event->header; mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); } static void perf_event__comm_swap(union perf_event *event, bool sample_id_all) { event->comm.pid = bswap_32(event->comm.pid); event->comm.tid = bswap_32(event->comm.tid); if (sample_id_all) { void *data = &event->comm.comm; data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); swap_sample_id_all(event, data); } } static void perf_event__mmap_swap(union perf_event *event, bool sample_id_all) { event->mmap.pid = bswap_32(event->mmap.pid); event->mmap.tid = bswap_32(event->mmap.tid); event->mmap.start = bswap_64(event->mmap.start); event->mmap.len = bswap_64(event->mmap.len); event->mmap.pgoff = bswap_64(event->mmap.pgoff); if (sample_id_all) { void *data = &event->mmap.filename; data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); swap_sample_id_all(event, data); } } static void perf_event__mmap2_swap(union perf_event *event, bool sample_id_all) { event->mmap2.pid = bswap_32(event->mmap2.pid); event->mmap2.tid = bswap_32(event->mmap2.tid); event->mmap2.start = bswap_64(event->mmap2.start); event->mmap2.len = bswap_64(event->mmap2.len); event->mmap2.pgoff = bswap_64(event->mmap2.pgoff); event->mmap2.maj = bswap_32(event->mmap2.maj); event->mmap2.min = bswap_32(event->mmap2.min); event->mmap2.ino = bswap_64(event->mmap2.ino); if (sample_id_all) { void *data = &event->mmap2.filename; data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); swap_sample_id_all(event, data); } } static void perf_event__task_swap(union perf_event *event, bool sample_id_all) { event->fork.pid = bswap_32(event->fork.pid); event->fork.tid = bswap_32(event->fork.tid); event->fork.ppid = bswap_32(event->fork.ppid); event->fork.ptid = bswap_32(event->fork.ptid); event->fork.time = bswap_64(event->fork.time); if (sample_id_all) swap_sample_id_all(event, &event->fork + 1); } static void perf_event__read_swap(union perf_event *event, bool sample_id_all) { event->read.pid = bswap_32(event->read.pid); event->read.tid = bswap_32(event->read.tid); event->read.value = bswap_64(event->read.value); event->read.time_enabled = bswap_64(event->read.time_enabled); event->read.time_running = bswap_64(event->read.time_running); event->read.id = bswap_64(event->read.id); if (sample_id_all) swap_sample_id_all(event, &event->read + 1); } static void perf_event__throttle_swap(union perf_event *event, bool sample_id_all) { event->throttle.time = bswap_64(event->throttle.time); event->throttle.id = bswap_64(event->throttle.id); event->throttle.stream_id = bswap_64(event->throttle.stream_id); if (sample_id_all) swap_sample_id_all(event, &event->throttle + 1); } static u8 revbyte(u8 b) { int rev = (b >> 4) | ((b & 0xf) << 4); rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2); rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1); return (u8) rev; } /* * XXX this is hack in attempt to carry flags bitfield * throught endian village. ABI says: * * Bit-fields are allocated from right to left (least to most significant) * on little-endian implementations and from left to right (most to least * significant) on big-endian implementations. * * The above seems to be byte specific, so we need to reverse each * byte of the bitfield. 'Internet' also says this might be implementation * specific and we probably need proper fix and carry perf_event_attr * bitfield flags in separate data file FEAT_ section. Thought this seems * to work for now. */ static void swap_bitfield(u8 *p, unsigned len) { unsigned i; for (i = 0; i < len; i++) { *p = revbyte(*p); p++; } } /* exported for swapping attributes in file header */ void perf_event__attr_swap(struct perf_event_attr *attr) { attr->type = bswap_32(attr->type); attr->size = bswap_32(attr->size); attr->config = bswap_64(attr->config); attr->sample_period = bswap_64(attr->sample_period); attr->sample_type = bswap_64(attr->sample_type); attr->read_format = bswap_64(attr->read_format); attr->wakeup_events = bswap_32(attr->wakeup_events); attr->bp_type = bswap_32(attr->bp_type); attr->bp_addr = bswap_64(attr->bp_addr); attr->bp_len = bswap_64(attr->bp_len); attr->branch_sample_type = bswap_64(attr->branch_sample_type); attr->sample_regs_user = bswap_64(attr->sample_regs_user); attr->sample_stack_user = bswap_32(attr->sample_stack_user); swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); } static void perf_event__hdr_attr_swap(union perf_event *event, bool sample_id_all __maybe_unused) { size_t size; perf_event__attr_swap(&event->attr.attr); size = event->header.size; size -= (void *)&event->attr.id - (void *)event; mem_bswap_64(event->attr.id, size); } static void perf_event__event_type_swap(union perf_event *event, bool sample_id_all __maybe_unused) { event->event_type.event_type.event_id = bswap_64(event->event_type.event_type.event_id); } static void perf_event__tracing_data_swap(union perf_event *event, bool sample_id_all __maybe_unused) { event->tracing_data.size = bswap_32(event->tracing_data.size); } typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_MMAP] = perf_event__mmap_swap, [PERF_RECORD_MMAP2] = perf_event__mmap2_swap, [PERF_RECORD_COMM] = perf_event__comm_swap, [PERF_RECORD_FORK] = perf_event__task_swap, [PERF_RECORD_EXIT] = perf_event__task_swap, [PERF_RECORD_LOST] = perf_event__all64_swap, [PERF_RECORD_READ] = perf_event__read_swap, [PERF_RECORD_THROTTLE] = perf_event__throttle_swap, [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap, [PERF_RECORD_SAMPLE] = perf_event__all64_swap, [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, [PERF_RECORD_HEADER_BUILD_ID] = NULL, [PERF_RECORD_HEADER_MAX] = NULL, }; struct sample_queue { u64 timestamp; u64 file_offset; union perf_event *event; struct list_head list; }; static void perf_session_free_sample_buffers(struct perf_session *session) { struct ordered_samples *os = &session->ordered_samples; while (!list_empty(&os->to_free)) { struct sample_queue *sq; sq = list_entry(os->to_free.next, struct sample_queue, list); list_del(&sq->list); free(sq); } } static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, struct perf_tool *tool, u64 file_offset); static int flush_sample_queue(struct perf_session *s, struct perf_tool *tool) { struct ordered_samples *os = &s->ordered_samples; struct list_head *head = &os->samples;