diff options
441 files changed, 13375 insertions, 8857 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 71c92db47c41..bf9cd83de777 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -171,7 +171,7 @@ config HAVE_MMIOTRACE_SUPPORT config X86_DECODER_SELFTEST bool "x86 instruction decoder selftest" - depends on DEBUG_KERNEL && KPROBES + depends on DEBUG_KERNEL && INSTRUCTION_DECODER depends on !COMPILE_TEST ---help--- Perform x86 instruction decoder selftests at build time. diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 325959d19d9a..15b90b1a8fb1 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1005,6 +1005,27 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, /* current number of events already accepted */ n = cpuc->n_events; + if (!cpuc->n_events) + cpuc->pebs_output = 0; + + if (!cpuc->is_fake && leader->attr.precise_ip) { + /* + * For PEBS->PT, if !aux_event, the group leader (PT) went + * away, the group was broken down and this singleton event + * can't schedule any more. + */ + if (is_pebs_pt(leader) && !leader->aux_event) + return -EINVAL; + + /* + * pebs_output: 0: no PEBS so far, 1: PT, 2: DS + */ + if (cpuc->pebs_output && + cpuc->pebs_output != is_pebs_pt(leader) + 1) + return -EINVAL; + + cpuc->pebs_output = is_pebs_pt(leader) + 1; + } if (is_x86_event(leader)) { if (n >= max_count) @@ -2241,6 +2262,17 @@ static int x86_pmu_check_period(struct perf_event *event, u64 value) return 0; } +static int x86_pmu_aux_output_match(struct perf_event *event) +{ + if (!(pmu.capabilities & PERF_PMU_CAP_AUX_OUTPUT)) + return 0; + + if (x86_pmu.aux_output_match) + return x86_pmu.aux_output_match(event); + + return 0; +} + static struct pmu pmu = { .pmu_enable = x86_pmu_enable, .pmu_disable = x86_pmu_disable, @@ -2266,6 +2298,8 @@ static struct pmu pmu = { .sched_task = x86_pmu_sched_task, .task_ctx_size = sizeof(struct x86_perf_task_context), .check_period = x86_pmu_check_period, + + .aux_output_match = x86_pmu_aux_output_match, }; void arch_perf_update_userpage(struct perf_event *event, diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index e4c2cb65ea50..43c966d1208e 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -18,6 +18,7 @@ #include <asm/cpufeature.h> #include <asm/hardirq.h> #include <asm/intel-family.h> +#include <asm/intel_pt.h> #include <asm/apic.h> #include <asm/cpu_device_id.h> @@ -3298,6 +3299,13 @@ static int intel_pmu_hw_config(struct perf_event *event) } } + if (event->attr.aux_output) { + if (!event->attr.precise_ip) + return -EINVAL; + + event->hw.flags |= PERF_X86_EVENT_PEBS_VIA_PT; + } + if (event->attr.type != PERF_TYPE_RAW) return 0; @@ -3816,6 +3824,14 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value) return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0; } +static int intel_pmu_aux_output_match(struct perf_event *event) +{ + if (!x86_pmu.intel_cap.pebs_output_pt_available) + return 0; + + return is_intel_pt_event(event); +} + PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); PMU_FORMAT_ATTR(ldlat, "config1:0-15"); @@ -3940,6 +3956,8 @@ static __initconst const struct x86_pmu intel_pmu = { .sched_task = intel_pmu_sched_task, .check_period = intel_pmu_check_period, + + .aux_output_match = intel_pmu_aux_output_match, }; static __init void intel_clovertown_quirk(void) diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 688592b34564..db498b5d4aae 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -446,7 +446,7 @@ static int cstate_cpu_init(unsigned int cpu) return 0; } -const struct attribute_group *core_attr_update[] = { +static const struct attribute_group *core_attr_update[] = { &group_cstate_core_c1, &group_cstate_core_c3, &group_cstate_core_c6, @@ -454,7 +454,7 @@ const struct attribute_group *core_attr_update[] = { NULL, }; -const struct attribute_group *pkg_attr_update[] = { +static const struct attribute_group *pkg_attr_update[] = { &group_cstate_pkg_c2, &group_cstate_pkg_c3, &group_cstate_pkg_c6, diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index f1269e804e9b..ce83950036c5 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -902,6 +902,9 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event) */ static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc) { + if (cpuc->n_pebs == cpuc->n_pebs_via_pt) + return false; + return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs); } @@ -919,6 +922,9 @@ static inline void pebs_update_threshold(struct cpu_hw_events *cpuc) u64 threshold; int reserved; + if (cpuc->n_pebs_via_pt) + return; + if (x86_pmu.flags & PMU_FL_PEBS_ALL) reserved = x86_pmu.max_pebs_events + x86_pmu.num_counters_fixed; else @@ -1059,10 +1065,40 @@ void intel_pmu_pebs_add(struct perf_event *event) cpuc->n_pebs++; if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS) cpuc->n_large_pebs++; + if (hwc->flags & PERF_X86_EVENT_PEBS_VIA_PT) + cpuc->n_pebs_via_pt++; pebs_update_state(needed_cb, cpuc, event, true); } +static void intel_pmu_pebs_via_pt_disable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + if (!is_pebs_pt(event)) + return; + + if (!(cpuc->pebs_enabled & ~PEBS_VIA_PT_MASK)) + cpuc->pebs_enabled &= ~PEBS_VIA_PT_MASK; +} + +static void intel_pmu_pebs_via_pt_enable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + struct debug_store *ds = cpuc->ds; + + if (!is_pebs_pt(event)) + return; + + if (!(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS)) + cpuc->pebs_enabled |= PEBS_PMI_AFTER_EACH_RECORD; + + cpuc->pebs_enabled |= PEBS_OUTPUT_PT; + + wrmsrl(MSR_RELOAD_PMC0 + hwc->idx, ds->pebs_event_reset[hwc->idx]); +} + void intel_pmu_pebs_enable(struct perf_event *event) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); @@ -1100,6 +1136,8 @@ void intel_pmu_pebs_enable(struct perf_event *event) } else { ds->pebs_event_reset[hwc->idx] = 0; } + + intel_pmu_pebs_via_pt_enable(event); } void intel_pmu_pebs_del(struct perf_event *event) @@ -1111,6 +1149,8 @@ void intel_pmu_pebs_del(struct perf_event *event) cpuc->n_pebs--; if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS) cpuc->n_large_pebs--; + if (hwc->flags & PERF_X86_EVENT_PEBS_VIA_PT) + cpuc->n_pebs_via_pt--; pebs_update_state(needed_cb, cpuc, event, false); } @@ -1120,7 +1160,8 @@ void intel_pmu_pebs_disable(struct perf_event *event) struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; - if (cpuc->n_pebs == cpuc->n_large_pebs) + if (cpuc->n_pebs == cpuc->n_large_pebs && + cpuc->n_pebs != cpuc->n_pebs_via_pt) intel_pmu_drain_pebs_buffer(); cpuc->pebs_enabled &= ~(1ULL << hwc->idx); @@ -1131,6 +1172,8 @@ void intel_pmu_pebs_disable(struct perf_event *event) else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) cpuc->pebs_enabled &= ~(1ULL << 63); + intel_pmu_pebs_via_pt_disable(event); + if (cpuc->enabled) wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); @@ -2031,6 +2074,12 @@ void __init intel_ds_init(void) PERF_SAMPLE_REGS_INTR); } pr_cont("PEBS fmt4%c%s, ", pebs_type, pebs_qual); + + if (x86_pmu.intel_cap.pebs_output_pt_available) { + pr_cont("PEBS-via-PT, "); + x86_get_pmu()->capabilities |= PERF_PMU_CAP_AUX_OUTPUT; + } + break; default: diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 6f814a27416b..ea54634eabf3 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -273,7 +273,7 @@ static inline bool lbr_from_signext_quirk_needed(void) return !tsx_support && (lbr_desc[lbr_format] & LBR_TSX); } -DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key); +static DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key); /* If quirk is enabled, ensure sign extension is 63 bits: */ inline u64 lbr_from_signext_quirk_wr(u64 val) diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index d3dc2274ddd4..b1bb4d28e0be 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -545,33 +545,62 @@ static void pt_config_buffer(void *buf, unsigned int topa_idx, wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, reg); } -/* - * Keep ToPA table-related metadata on the same page as the actual table, - * taking up a few words from the top - */ - -#define TENTS_PER_PAGE (((PAGE_SIZE - 40) / sizeof(struct topa_entry)) - 1) - /** - * struct topa - page-sized ToPA table with metadata at the top - * @table: actual ToPA table entries, as understood by PT hardware + * struct topa - ToPA metadata * @list: linkage to struct pt_buffer's list of tables - * @phys: physical address of this page * @offset: offset of the first entry in this table in the buffer * @size: total size of all entries in this table * @last: index of the last initialized entry in this table + * @z_count: how many times the first entry repeats */ struct topa { - struct topa_entry table[TENTS_PER_PAGE]; struct list_head list; - u64 phys; u64 offset; size_t size; int last; + unsigned int z_count; }; +/* + * Keep ToPA table-related metadata on the same page as the actual table, + * taking up a few words from the top + */ + +#define TENTS_PER_PAGE \ + ((PAGE_SIZE - sizeof(struct topa)) / sizeof(struct topa_entry)) + +/** + * struct topa_page - page-sized ToPA table with metadata at the top + * @table: actual ToPA table entries, as understood by PT hardware + * @topa: metadata + */ +struct topa_page { + struct topa_entry table[TENTS_PER_PAGE]; + struct topa topa; +}; + +static inline struct topa_page *topa_to_page(struct topa *topa) +{ + return container_of(topa, struct topa_page, topa); +} + +static inline struct topa_page *topa_entry_to_page(struct topa_entry *te) +{ + return (struct topa_page *)((unsigned long)te & PAGE_MASK); +} + +static inline phys_addr_t topa_pfn(struct topa *topa) +{ + return PFN_DOWN(virt_to_phys(topa_to_page(topa))); +} + /* make -1 stand for the last table entry */ -#define TOPA_ENTRY(t, i) ((i) == -1 ? &(t)->table[(t)->last] : &(t)->table[(i)]) +#define TOPA_ENTRY(t, i) \ + ((i) == -1 \ + ? &topa_to_page(t)->table[(t)->last] \ + : &topa_to_page(t)->table[(i)]) +#define TOPA_ENTRY_SIZE(t, i) (sizes(TOPA_ENTRY((t), (i))->size)) +#define TOPA_ENTRY_PAGES(t, i) (1 << TOPA_ENTRY((t), (i))->size) /** * topa_alloc() - allocate page-sized ToPA table @@ -583,27 +612,26 @@ struct topa { static struct topa *topa_alloc(int cpu, gfp_t gfp) { int node = cpu_to_node(cpu); - struct topa *topa; + struct topa_page *tp; struct page *p; p = alloc_pages_node(node, gfp | __GFP_ZERO, 0); if (!p) return NULL; - topa = page_address(p); - topa->last = 0; - topa->phys = page_to_phys(p); + tp = page_address(p); + tp->topa.last = 0; /* * In case of singe-entry ToPA, always put the self-referencing END * link as the 2nd entry in the table */ if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries)) { - TOPA_ENTRY(topa, 1)->base = topa->phys >> TOPA_SHIFT; - TOPA_ENTRY(topa, 1)->end = 1; + TOPA_ENTRY(&tp->topa, 1)->base = page_to_phys(p); + TOPA_ENTRY(&tp->topa, 1)->end = 1; } - return topa; + return &tp->topa; } /** @@ -643,7 +671,7 @@ static void topa_insert_table(struct pt_buffer *buf, struct topa *topa) BUG_ON(last->last != TENTS_PER_PAGE - 1); - TOPA_ENTRY(last, -1)->base = topa->phys >> TOPA_SHIFT; + TOPA_ENTRY(last, -1)->base = topa_pfn(topa); TOPA_ENTRY(last, -1)->end = 1; } @@ -670,7 +698,7 @@ static bool topa_table_full(struct topa *topa) * * Return: 0 on success or error code. */ -static int topa_insert_pages(struct pt_buffer *buf, gfp_t gfp) +static int topa_insert_pages(struct pt_buffer *buf, int cpu, gfp_t gfp) { struct topa *topa = buf->last; int order = 0; @@ -681,13 +709,18 @@ static int topa_insert_pages(struct pt_buffer *buf, gfp_t gfp) order = page_private(p); if (topa_table_full(topa)) { - topa = topa_alloc(buf->cpu, gfp); + topa = topa_alloc(cpu, gfp); if (!topa) return -ENOMEM; topa_insert_table(buf, topa); } + if (topa->z_count == topa->last - 1) { + if (order == TOPA_ENTRY(topa, topa->last - 1)->size) + topa->z_count++; + } + TOPA_ENTRY(topa, -1)->base = page_to_phys(p) >> TOPA_SHIFT; TOPA_ENTRY(topa, -1)->size = order; if (!buf->snapshot && @@ -713,23 +746,26 @@ static void pt_topa_dump(struct pt_buffer *buf) struct topa *topa; list_for_each_entry(topa, &buf->tables, list) { + struct topa_page *tp = topa_to_page(topa); int i; - pr_debug("# table @%p (%016Lx), off %llx size %zx\n", topa->table, - topa->phys, topa->offset, topa->size); + pr_debug("# table @%p, off %llx size %zx\n", tp->table, + topa->offset, topa->size); for (i = 0; i < TENTS_PER_PAGE; i++) { pr_debug("# entry @%p (%lx sz %u %c%c%c) raw=%16llx\n", - &topa->table[i], - (unsigned long)topa->table[i].base << TOPA_SHIFT, - sizes(topa->table[i].size), - topa->table[i].end ? 'E' : ' ', - topa->table[i].intr ? 'I' : ' ', - topa->table[i].stop ? 'S' : ' ', - *(u64 *)&topa->table[i]); + &tp->table[i], + (unsigned long)tp->table[i].base << TOPA_SHIFT, + sizes(tp->table[i].size), + tp->table[i].end ? 'E' : ' ', + tp->table[i].intr ? 'I' : ' ', + tp->table[i].stop ? 'S' : ' ', + *(u64 *)&tp->table[i]); if ((intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) && - topa->table[i].stop) || - topa->table[i].end) + tp->table[i].stop) || + tp->table[i].end) break; + if (!i && topa->z_count) + i += topa->z_count; } } } @@ -771,7 +807,7 @@ static void pt_update_head(struct pt *pt) /* offset of the current output region within this table */ for (topa_idx = 0; topa_idx < buf->cur_idx; topa_idx++) - base += sizes(buf->cur->table[topa_idx].size); + base += TOPA_ENTRY_SIZE(buf->cur, topa_idx); if (buf->snapshot) { local_set(&buf->data_size, base); @@ -791,7 +827,7 @@ static void pt_update_head(struct pt *pt) */ static void *pt_buffer_region(struct pt_buffer *buf) { - return phys_to_virt(buf->cur->table[buf->cur_idx].base << TOPA_SHIFT); + return phys_to_virt(TOPA_ENTRY(buf->cur, buf->cur_idx)->base << TOPA_SHIFT); } /** @@ -800,7 +836,7 @@ static void *pt_buffer_region(struct pt_buffer *buf) */ static size_t pt_buffer_region_size(struct pt_buffer *buf) { - return sizes(buf->cur->table[buf->cur_idx].size); + return TOPA_ENTRY_SIZE(buf->cur, buf->cur_idx); } /** @@ -830,7 +866,7 @@ static void pt_handle_status(struct pt *pt) * know. */ if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) || - buf->output_off == sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size)) { + buf->output_off == pt_buffer_region_size(buf)) { perf_aux_output_flag(&pt->handle, PERF_AUX_FLAG_TRUNCATED); advance++; @@ -868,9 +904,11 @@ static void pt_handle_status(struct pt *pt) static void pt_read_offset(struct pt_buffer *buf) { u64 offset, base_topa; + struct topa_page *tp; rdmsrl(MSR_IA32_RTIT_OUTPUT_BASE, base_topa); - buf->cur = phys_to_virt(base_topa); + tp = phys_to_virt(base_topa); + buf->cur = &tp->topa; rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, offset); /* offset within current output region */ @@ -879,29 +917,97 @@ static void pt_read_offset(struct pt_buffer *buf) buf->cur_idx = (offset & 0xffffff80) >> 7; } -/** - * pt_topa_next_entry() - obtain index of the first page in the next ToPA entry - * @buf: PT buffer. - * @pg: Page offset in the buffer. - * - * When advancing to the next output region (ToPA entry), given a page offset - * into the buffer, we need to find the offset of the first page in the next - * region. - */ -static unsigned int pt_topa_next_entry(struct pt_buffer *buf, unsigned int pg) +static struct topa_entry * +pt_topa_entry_for_page(struct pt_buffer *buf, unsigned int pg) { - struct topa_entry *te = buf->topa_index[pg]; + struct topa_page *tp; + struct topa *topa; + unsigned int idx, cur_pg = 0, z_pg = 0, start_idx = 0; - /* one region */ - if (buf->first == buf->last && buf->first->last == 1) - return pg; + /* + * Indicates a bug in the caller. + */ + if (WARN_ON_ONCE(pg >= buf->nr_pages)) + return NULL; + + /* + * First, find the ToPA table where @pg fits. With high + * order allocations, there shouldn't be many of these. + */ + list_for_each_entry(topa, &buf->tables, list) { + if (topa->offset + topa->size > pg << PAGE_SHIFT) + goto found; + } + + /* + * Hitting this means we have a problem in the ToPA + * allocation code. + */ + WARN_ON_ONCE(1); - do { - pg++; - pg &= buf->nr_pages - 1; - } while (buf->topa_index[pg] == te); + return NULL; - return pg; +found: + /* + * Indicates a problem in the ToPA allocation code. + */ + if (WARN_ON_ONCE(topa->last == -1)) + return NULL; + + tp = topa_to_page(topa); + cur_pg = PFN_DOWN(topa->offset); + if (topa->z_count) { + z_pg = TOPA_ENTRY_PAGES(topa, 0) * (topa->z_count + 1); + start_idx = topa->z_count + 1; + } + + /* + * Multiple entries at the beginning of the table have the same size, + * ideally all of them; if @pg falls there, the search is done. + */ + if (pg >= cur_pg && pg < cur_pg + z_pg) { + idx = (pg - cur_pg) / TOPA_ENTRY_PAGES(topa, 0); + return &tp->table[idx]; + } + + /* + * Otherwise, slow path: iterate through the remaining entries. + */ + for (idx = start_idx, cur_pg += z_pg; idx < topa->last; idx++) { + if (cur_pg + TOPA_ENTRY_PAGES(topa, idx) > pg) + return &tp->table[idx]; + + cur_pg += TOPA_ENTRY_PAGES(topa, idx); + } + + /* + * Means we couldn't find a ToPA entry in the table that does match. + */ + WARN_ON_ONCE(1); + + return NULL; +} + +static struct topa_entry * +pt_topa_prev_entry(struct pt_buffer *buf, struct topa_entry *te) +{ + unsigned long table = (unsigned long)te & ~(PAGE_SIZE - 1); + struct topa_page *tp; + struct topa *topa; + + tp = (struct topa_page *)table; + if (tp->table != te) + return --te; + + topa = &tp->topa; + if (topa == buf->first) + topa = buf->last; + else + topa = list_prev_entry(topa, list); + + tp = topa_to_page(topa); + + return &tp->table[topa->last - 1]; } /** @@ -925,8 +1031,7 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, unsigned long idx, npages, wakeup; /* can't stop in the middle of an output region */ - if (buf->output_off + handle->size + 1 < - sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size)) { + if (buf->output_off + handle->size + 1 < pt_buffer_region_size(buf)) { perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); return -EINVAL; } @@ -937,9 +1042,13 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, return 0; /* clear STOP and INT from current entry */ - buf->topa_index[buf->stop_pos]->stop = 0; - buf->topa_index[buf->stop_pos]->intr = 0; - buf->topa_index[buf->intr_pos]->intr = 0; + if (buf->stop_te) { + buf->stop_te->stop = 0; + buf->stop_te->intr = 0; + } + + if (buf->intr_te) + buf->intr_te->intr = 0; /* how many pages till the STOP marker */ npages = handle->size >> PAGE_SHIFT; @@ -950,7 +1059,12 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, idx = (head >> PAGE_SHIFT) + npages; idx &= buf->nr_pages - 1; - buf->stop_pos = idx; + + if (idx != buf->stop_pos) { + buf->stop_pos = idx; + buf->stop_te = pt_topa_entry_for_page(buf, idx); + buf->stop_te = pt_topa_prev_entry(buf, buf->stop_te); + } wakeup = handle->wakeup >> PAGE_SHIFT; @@ -960,51 +1074,20 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, idx = wakeup; idx &= buf->nr_pages - 1; - buf->intr_pos = idx; + if (idx != buf->intr_pos) { + buf->intr_pos = idx; + buf->intr_te = pt_topa_entry_for_page(buf, idx); + buf->intr_te = pt_topa_prev_entry(buf, buf->intr_te); + } - buf->topa_index[buf->stop_pos]->stop = 1; - buf->topa_index[buf->stop_pos]->intr = 1; - buf->topa_index[buf->intr_pos]->intr = 1; + buf->stop_te->stop = 1; + buf->stop_te->intr = 1; + buf->intr_te->intr = 1; return 0; } /** - * pt_buffer_setup_topa_index() - build topa_index[] table of regions - * @buf: PT buffer. - * - * topa_index[] references output regions indexed by offset into the - * buffer for purposes of quick reverse lookup. - */ -static void pt_buffer_setup_topa_index(struct pt_buffer *buf) -{ - struct topa *cur = buf->first, *prev = buf->last; - struct topa_entry *te_cur = TOPA_ENTRY(cur, 0), - *te_prev = TOPA_ENTRY(prev, prev->last - 1); - int pg = 0, idx = 0; - - while (pg < buf->nr_pages) { - int tidx; - - /* pages within one topa entry */ - for (tidx = 0; tidx < 1 << te_cur->size; tidx++, pg++) - buf->topa_index[pg] = te_prev; - - te_prev = te_cur; - - if (idx == cur->last - 1) { - /* advance to next topa table */ - idx = 0; - cur = list_entry(cur->list.next, struct topa, list); - } else { - idx++; - } - te_cur = TOPA_ENTRY(cur, idx); - } - -} - -/** * pt_buffer_reset_offsets() - adjust buffer's write pointers from aux_head * @buf: PT buffer. * @head: Write pointer (aux_head) from AUX buffer. @@ -1021,18 +1104,20 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf) */ static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head) { + struct topa_page *cur_tp; + struct topa_entry *te; int pg; if (buf->snapshot) head &= (buf->nr_pages << PAGE_SHIFT) - 1; pg = (head >> PAGE_SHIFT) & (buf->nr_pages - 1); - pg = pt_topa_next_entry(buf, pg); + te = pt_topa_entry_for_page(buf, pg); - buf->cur = (struct topa *)((unsigned long)buf->topa_index[pg] & PAGE_MASK); - buf->cur_idx = ((unsigned long)buf->topa_index[pg] - - (unsigned long)buf->cur) / sizeof(struct topa_entry); - buf->output_off = head & (sizes(buf->cur->table[buf->cur_idx].size) - 1); + cur_tp = topa_entry_to_page(te); + buf->cur = &cur_tp->topa; + buf->cur_idx = te - TOPA_ENTRY(buf->cur, 0); + buf->output_off = head & (pt_buffer_region_size(buf) - 1); local64_set(&buf->head, head); local_set(&buf->data_size, 0); @@ -1061,31 +1146,29 @@ static void pt_buffer_fini_topa(struct pt_buffer *buf) * @size: Total size of all regions within this ToPA. * @gfp: Allocation flags. */ -static int pt_buffer_init_topa(struct pt_buffer *buf, unsigned long nr_pages, - gfp_t gfp) +static int pt_buffer_init_topa(struct pt_buffer *buf, int cpu, + unsigned long nr_pages, gfp_t gfp) { struct topa *topa; int err; - topa = topa_alloc(buf->cpu, gfp); + topa = topa_alloc(cpu, gfp); if (!topa) return -ENOMEM; topa_insert_table(buf, topa); while (buf->nr_pages < nr_pages) { - err = topa_insert_pages(buf, gfp); + err = topa_insert_pages(buf, cpu, gfp); if (err) { pt_buffer_fini_topa(buf); return -ENOMEM; } } - pt_buffer_setup_topa_index(buf); - /* link last table to the first one, unless we're double buffering */ if (intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries)) { - TOPA_ENTRY(buf->last, -1)->base = buf->first->phys >> TOPA_SHIFT; + TOPA_ENTRY(buf->last, -1)->base = topa_pfn(buf->first); TOPA_ENTRY(buf->last, -1)->end = 1; } @@ -1119,18 +1202,18 @@ pt_buffer_setup_aux(struct perf_event *event, void **pages, cpu = raw_smp_processor_id(); node = cpu_to_node(cpu); - buf = kzalloc_node(offsetof(struct pt_buffer, topa_index[nr_pages]), - GFP_KERNEL, node); + buf = kzalloc_node(sizeof(struct pt_buffer), GFP_KERNEL, node); if (!buf) return NULL; - buf->cpu = cpu; buf->snapshot = snapshot; buf->data_pages = pages; + buf->stop_pos = -1; + buf->intr_pos = -1; INIT_LIST_HEAD(&buf->tables); - ret = pt_buffer_init_topa(buf, nr_pages, GFP_KERNEL); + ret = pt_buffer_init_topa(buf, cpu, nr_pages, GFP_KERNEL); if (ret) { kfree(buf); return NULL; @@ -1296,7 +1379,7 @@ void intel_pt_interrupt(void) return; } - pt_config_buffer(buf->cur->table, buf->cur_idx, + pt_config_buffer(topa_to_page(buf->cur)->table, buf->cur_idx, buf->output_off); pt_config(event); } @@ -1361,7 +1444,7 @@ static void pt_event_start(struct perf_event *event, int mode) WRITE_ONCE(pt->handle_nmi, 1); hwc->state = 0; - pt_config_buffer(buf->cur->table, buf->cur_idx, + pt_config_buffer(topa_to_page(buf->cur)->table, buf->cur_idx, buf->output_off); pt_config(event); @@ -1481,6 +1564,11 @@ void cpu_emergency_stop_pt(void) pt_event_stop(pt->handle.event, PERF_EF_UPDATE); } +int is_intel_pt_event(struct perf_event *event) +{ + return event->pmu == &pt_pmu.pmu; +} + static __init int pt_init(void) { int ret, cpu, prior_warn = 0; diff --git a/arch/x86/events/intel/pt.h b/arch/x86/events/intel/pt.h index 63fe4063fbd6..1d2bb7572374 100644 --- a/arch/x86/events/intel/pt.h +++ b/arch/x86/events/intel/pt.h @@ -53,7 +53,6 @@ struct pt_pmu { /** * struct pt_buffer - buffer configuration; one buffer per task_struct or * cpu, depending on perf event configuration - * @cpu: cpu for per-cpu allocation * @tables: list of ToPA tables in this buffer * @first: shorthand for first topa table * @last: shorthand for last topa table @@ -65,13 +64,14 @@ struct pt_pmu { * @lost: if data was lost/truncated * @head: logical write offset inside the buffer * @snapshot: if this is for a snapshot/overwrite counter - * @stop_pos: STOP topa entry in the buffer - * @intr_pos: INT topa entry in the buffer + * @stop_pos: STOP topa entry index + * @intr_pos: INT topa entry index + * @stop_te: STOP topa entry pointer + * @intr_te: INT topa entry pointer * @data_pages: array of pages from perf * @topa_index: table of topa entries indexed by page offset */ struct pt_buffer { - int cpu; struct list_head tables; struct topa *first, *last, *cur; unsigned int cur_idx; @@ -80,9 +80,9 @@ struct pt_buffer { local_t data_size; local64_t head; bool snapshot; - unsigned long stop_pos, intr_pos; + long stop_pos, intr_pos; + struct topa_entry *stop_te, *intr_te; void **data_pages; - struct topa_entry *topa_index[0]; }; #define PT_FILTERS_NUM 4 diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c index 64ab51ffdf06..f34b9491ea6e 100644 --- a/arch/x86/events/intel/rapl.c +++ b/arch/x86/events/intel/rapl.c @@ -634,7 +634,7 @@ static void cleanup_rapl_pmus(void) kfree(rapl_pmus); } -const struct attribute_group *rapl_attr_update[] = { +static const struct attribute_group *rapl_attr_update[] = { &rapl_events_cores_group, &rapl_events_pkg_group, &rapl_events_ram_group, diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index 9431447541e9..5812e8747d1f 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -167,7 +167,7 @@ static const struct attribute_group *attr_groups[] = { NULL, }; -const struct attribute_group *attr_update[] = { +static const struct attribute_group *attr_update[] = { &group_aperf, &group_mperf, &group_pperf, diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 8751008fc170..ecacfbf4ebc1 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -76,6 +76,7 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode) #define PERF_X86_EVENT_EXCL_ACCT 0x0100 /* accounted EXCL event */ #define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */ #define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */ +#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */ struct amd_nb { int nb_id; /* NorthBridge id */ @@ -85,6 +86,11 @@ struct amd_nb { }; #define PEBS_COUNTER_MASK ((1ULL << MAX_PEBS_EVENTS) - 1) +#define PEBS_PMI_AFTER_EACH_RECORD BIT_ULL(60) +#define PEBS_OUTPUT_OFFSET 61 +#define PEBS_OUTPUT_MASK (3ull << PEBS_OUTPUT_OFFSET) +#define PEBS_OUTPUT_PT (1ull << PEBS_OUTPUT_OFFSET) +#define PEBS_VIA_PT_MASK (PEBS_OUTPUT_PT | PEBS_PMI_AFTER_EACH_RECORD) /* * Flags PEBS can handle without an PMI. @@ -211,6 +217,8 @@ struct cpu_hw_events { u64 pebs_enabled; int n_pebs; int n_large_pebs; + int n_pebs_via_pt; + int pebs_output; /* Current super set of events hardware configuration */ u64 pebs_data_cfg; @@ -510,6 +518,8 @@ union perf_capabilities { */ u64 full_width_write:1; u64 pebs_baseline:1; + u64 pebs_metrics_available:1; + u64 pebs_output_pt_available:1; }; u64 capabilities; }; @@ -692,6 +702,8 @@ struct x86_pmu { * Check period value for PERF_EVENT_IOC_PERIOD ioctl. */ int (*check_period) (struct perf_event *event, u64 period); + + int (*aux_output_match) (struct perf_event *event); }; struct x86_perf_task_context { @@ -901,6 +913,11 @@ static inline int amd_pmu_init(void) #endif /* CONFIG_CPU_SUP_AMD */ +static inline int is_pebs_pt(struct perf_event *event) +{ + return !!(event->hw.flags & PERF_X86_EVENT_PEBS_VIA_PT); +} + #ifdef CONFIG_CPU_SUP_INTEL static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period) diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h index 634f99b1dc22..423b788f495e 100644 --- a/arch/x86/include/asm/intel_pt.h +++ b/arch/x86/include/asm/intel_pt.h @@ -28,10 +28,12 @@ enum pt_capabilities { void cpu_emergency_stop_pt(void); extern u32 intel_pt_validate_hw_cap(enum pt_capabilities cap); extern u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities cap); +extern int is_intel_pt_event(struct perf_event *event); #else static inline void cpu_emergency_stop_pt(void) {} static inline u32 intel_pt_validate_hw_cap(enum pt_capabilities cap) { return 0; } static inline u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities capability) { return 0; } +static inline int is_intel_pt_event(struct perf_event *event) { return 0; } #endif #endif /* _ASM_X86_INTEL_PT_H */ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 271d837d69a8..de753206b427 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -375,6 +375,10 @@ /* Alternative perfctr range with full access. */ #define MSR_IA32_PMC0 0x000004c1 +/* Auto-reload via MSR instead of DS area */ +#define MSR_RELOAD_PMC0 0x000014c1 +#define MSR_RELOAD_FIXED_CTR0 0x00001309 + /* AMD64 MSRs. Not complete. See the architecture manual for a more complete list. */ diff --git a/include/linux/bug.h b/include/linux/bug.h index fe5916550da8..f639bd0122f3 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -47,6 +47,11 @@ void generic_bug_clear_once(void); #else /* !CONFIG_GENERIC_BUG */ +static inline void *find_bug(unsigned long bugaddr) +{ + return NULL; +} + static inline enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs) { diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index e8ad3c590a23..61448c19a132 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -246,6 +246,7 @@ struct perf_event; #define PERF_PMU_CAP_ITRACE 0x20 #define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40 #define PERF_PMU_CAP_NO_EXCLUDE 0x80 +#define PERF_PMU_CAP_AUX_OUTPUT 0x100 /** * struct pmu - generic performance monitoring unit @@ -447,6 +448,16 @@ struct pmu { /* optional */ /* + * Check if event can be used for aux_output purposes for + * events of this PMU. + * + * Runs from perf_event_open(). Should return 0 for "no match" + * or non-zero for "match". + */ + int (*aux_output_match) (struct perf_event *event); + /* optional */ + + /* * Filter events for PMU-specific reasons. */ int (*filter_match) (struct perf_event *event); /* optional */ @@ -681,6 +692,9 @@ struct perf_event { struct perf_addr_filter_range *addr_filter_ranges; unsigned long addr_filters_gen; + /* for aux_output events */ + struct perf_event *aux_event; + void (*destroy)(struct perf_event *); struct rcu_head rcu_head; diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 7198ddd0c6b1..bb7b271397a6 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -374,7 +374,8 @@ struct perf_event_attr { namespaces : 1, /* include namespaces data */ ksymbol : 1, /* include ksymbol events */ bpf_event : 1, /* include bpf events */ - __reserved_1 : 33; + aux_output : 1, /* generate AUX records instead of events */ + __reserved_1 : 32; union { __u32 wakeup_events; /* wakeup every n events */ diff --git a/kernel/events/core.c b/kernel/events/core.c index 0463c1151bae..2aad959e6def 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1887,6 +1887,89 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) ctx->generation++; } +static int +perf_aux_output_match(struct perf_event *event, struct perf_event *aux_event) +{ + if (!has_aux(aux_event)) + return 0; + + if (!event->pmu->aux_output_match) + return 0; + + return event->pmu->aux_output_match(aux_event); +} + +static void put_event(struct perf_event *event); +static void event_sched_out(struct perf_event *event, + struct perf_cpu_context *cpuctx, + struct perf_event_context *ctx); + +static void perf_put_aux_event(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + struct perf_event *iter; + + /* + * If event uses aux_event tear down the link + */ + if (event->aux_event) { + iter = event->aux_event; + event->aux_event = NULL; + put_event(iter); + return; + } + + /* + * If the event is an aux_event, tear down all links to + * it from other events. + */ + for_each_sibling_event(iter, event->group_leader) { + if (iter->aux_event != event) + continue; + + iter->aux_event = NULL; + put_event(event); + + /* + * If it's ACTIVE, schedule it out and put it into ERROR + * state so that we don't try to schedule it again. Note + * that perf_event_enable() will clear the ERROR status. + */ + event_sched_out(iter, cpuctx, ctx); + perf_event_set_state(event, PERF_EVENT_STATE_ERROR); + } +} + +static int perf_get_aux_event(struct perf_event *event, + struct perf_event *group_leader) +{ + /* + * Our group leader must be an aux event if we want to be + * an aux_output. This way, the aux event will precede its + * aux_output events in the group, and therefore will always + * schedule first. + */ + if (!group_leader) + return 0; + + if (!perf_aux_output_match(event, group_leader)) + return 0; + + if (!atomic_long_inc_not_zero(&group_leader->refcount)) + return 0; + + /* + * Link aux_outputs to their aux event; this is undone in + * perf_group_detach() by perf_put_aux_event(). When the + * group in torn down, the aux_output events loose their + * link to the aux_event and can't schedule any more. + */ + event->aux_event = group_leader; + + return 1; +} + static void perf_group_detach(struct perf_event *event) { struct perf_event *sibling, *tmp; @@ -1902,6 +1985,8 @@ static void perf_group_detach(struct perf_event *event) event->attach_state &= ~PERF_ATTACH_GROUP; + perf_put_aux_event(event); + /* * If this is a sibling, remove it from its group. */ @@ -10426,6 +10511,12 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, goto err_ns; } + if (event->attr.aux_output && + !(pmu->capabilities & PERF_PMU_CAP_AUX_OUTPUT)) { + err = -EOPNOTSUPP; + goto err_pmu; + } + err = exclusive_event_init(event); if (err) goto err_pmu; @@ -11082,6 +11173,8 @@ SYSCALL_DEFINE5(perf_event_open, } } + if (event->attr.aux_output && !perf_get_aux_event(event, group_leader)) + goto err_locked; /* * Must be under the same ctx::mutex as perf_install_in_context(), diff --git a/kernel/kprobes.c b/kernel/kprobes.c index d9770a5393c8..ebe8315a756a 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1514,7 +1514,8 @@ static int check_kprobe_address_safe(struct kprobe *p, /* Ensure it is not in reserved area nor out of text */ if (!kernel_text_address((unsigned long) p->addr) || within_kprobe_blacklist((unsigned long) p->addr) || - jump_label_text_reserved(p->addr, p->addr)) { + jump_label_text_reserved(p->addr, p->addr) || + find_bug((unsigned long)p->addr)) { ret = -EINVAL; goto out; } diff --git a/tools/Makefile b/tools/Makefile index 68defd7ecf5d..7e42f7b8bfa7 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -10,6 +10,7 @@ help: @echo 'Possible targets:' @echo '' @echo ' acpi - ACPI tools' + @echo ' bpf - misc BPF tools' @echo ' cgroup - cgroup tools' @echo ' cpupower - a tool for all things x86 CPU power' @echo ' debugging - tools for debugging' @@ -23,12 +24,11 @@ help: @echo ' kvm_stat - top-like utility for displaying kvm statistics' @echo ' leds - LEDs tools' @echo ' liblockdep - user-space wrapper for kernel locking-validator' - @echo ' bpf - misc BPF tools' + @echo ' objtool - an ELF object analysis tool' @echo ' pci - PCI tools' @echo ' perf - Linux performance measurement and analysis tool' @echo ' selftests - various kernel selftests' @echo ' spi - spi tools' - @echo ' objtool - an ELF object analysis tool' @echo ' tmon - thermal monitoring and tuning tool' @echo ' turbostat - Intel CPU idle stats and freq reporting tool' @echo ' usb - USB testing tools' diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 998c2cc08363..e880f2408e29 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -281,6 +281,8 @@ #define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* LLC occupancy monitoring */ #define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* LLC Total MBM monitoring */ #define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* LLC Local MBM monitoring */ +#define X86_FEATURE_FENCE_SWAPGS_USER (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */ +#define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */ @@ -394,5 +396,6 @@ #define X86_BUG_L1TF X86_BUG(18) /* CPU is affected by L1 Terminal Fault */ #define X86_BUG_MDS X86_BUG(19) /* CPU is affected by Microarchitectural data sampling */ #define X86_BUG_MSBDS_ONLY X86_BUG(20) /* CPU is only affected by the MSDBS variant of BUG_MDS */ +#define X86_BUG_SWAPGS X86_BUG(21) /* CPU is affected by speculation through SWAPGS */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/tools/perf/util/intel-pt-decoder/inat.h b/tools/arch/x86/include/asm/inat.h index 877827b7c2c3..877827b7c2c3 100644 --- a/tools/perf/util/intel-pt-decoder/inat.h +++ b/tools/arch/x86/include/asm/inat.h diff --git a/tools/objtool/arch/x86/include/asm/inat_types.h b/tools/arch/x86/include/asm/inat_types.h index b047efa9ddc2..b047efa9ddc2 100644 --- a/tools/objtool/arch/x86/include/asm/inat_types.h +++ b/tools/arch/x86/include/asm/inat_types.h diff --git a/tools/perf/util/intel-pt-decoder/insn.h b/tools/arch/x86/include/asm/insn.h index 37a4c390750b..37a4c390750b 100644 --- a/tools/perf/util/intel-pt-decoder/insn.h +++ b/tools/arch/x86/include/asm/insn.h diff --git a/tools/objtool/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h index 6e060907c163..6e060907c163 100644 --- a/tools/objtool/arch/x86/include/asm/orc_types.h +++ b/tools/arch/x86/include/asm/orc_types.h diff --git a/tools/objtool/arch/x86/lib/inat.c b/tools/arch/x86/lib/inat.c index 12539fca75c4..4f5ed49e1b4e 100644 --- a/tools/objtool/arch/x86/lib/inat.c +++ b/tools/arch/x86/lib/inat.c @@ -4,7 +4,7 @@ * * Written by Masami Hiramatsu <mhiramat@redhat.com> */ -#include <asm/insn.h> +#include "../include/asm/insn.h" /* Attribute tables are generated from opcode map */ #include "inat-tables.c" diff --git a/tools/perf/util/intel-pt-decoder/insn.c b/tools/arch/x86/lib/insn.c index 82783bf43b74..79e048f1d902 100644 --- a/tools/perf/util/intel-pt-decoder/insn.c +++ b/tools/arch/x86/lib/insn.c @@ -10,8 +10,8 @@ #else #include <string.h> #endif -#include "inat.h" -#include "insn.h" +#include "../include/asm/inat.h" +#include "../include/asm/insn.h" /* Verify next sizeof(t) bytes can be on the same instruction */ #define validate_next(t, insn, n) \ diff --git a/tools/objtool/arch/x86/lib/x86-opcode-map.txt b/tools/arch/x86/lib/x86-opcode-map.txt index e0b85930dd77..e0b85930dd77 100644 --- a/tools/objtool/arch/x86/lib/x86-opcode-map.txt +++ b/tools/arch/x86/lib/x86-opcode-map.txt diff --git a/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk b/tools/arch/x86/tools/gen-insn-attr-x86.awk index b02a36b2c14f..b02a36b2c14f 100644 --- a/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk +++ b/tools/arch/x86/tools/gen-insn-attr-x86.awk diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 86b793dffbc4..8a19753cc26a 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -42,6 +42,7 @@ FEATURE_TESTS_BASIC := \ gtk2-infobar \ libaudit \ libbfd \ + libcap \ libelf \ libelf-getphdrnum \ libelf-gelf_getnote \ @@ -110,6 +111,7 @@ FEATURE_DISPLAY ?= \ gtk2 \ libaudit \ libbfd \ + libcap \ libelf \ libnuma \ numa_num_possible_cpus \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 0658b8cd0e53..8499385365c0 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -20,6 +20,7 @@ FILES= \ test-libbfd-liberty.bin \ test-libbfd-liberty-z.bin \ test-cplus-demangle.bin \ + test-libcap.bin \ test-libelf.bin \ test-libelf-getphdrnum.bin \ test-libelf-gelf_getnote.bin \ @@ -105,6 +106,9 @@ $(OUTPUT)test-fortify-source.bin: $(OUTPUT)test-bionic.bin: $(BUILD) +$(OUTPUT)test-libcap.bin: + $(BUILD) -lcap + $(OUTPUT)test-libelf.bin: $(BUILD) -lelf diff --git a/tools/build/feature/test-libcap.c b/tools/build/feature/test-libcap.c new file mode 100644 index 000000000000..d2a2e152195f --- /dev/null +++ b/tools/build/feature/test-libcap.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <sys/capability.h> +#include <linux/capability.h> + +int main(void) +{ + cap_flag_value_t val; + cap_t caps = cap_get_proc(); + + if (!caps) + return 1; + + if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &val) != 0) + return 1; + + if (cap_free(caps) != 0) + return 1; + + return 0; +} diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h index 0b0ef3abc966..140c8362f113 100644 --- a/tools/include/linux/bitops.h +++ b/tools/include/linux/bitops.h @@ -3,6 +3,7 @@ #define _TOOLS_LINUX_BITOPS_H_ #include <asm/types.h> +#include <limits.h> #ifndef __WORDSIZE #define __WORDSIZE (__SIZEOF_LONG__ * 8) #endif diff --git a/tools/include/linux/bits.h b/tools/include/linux/bits.h index 2b7b532c1d51..669d69441a62 100644 --- a/tools/include/linux/bits.h +++ b/tools/include/linux/bits.h @@ -1,13 +1,15 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LINUX_BITS_H #define __LINUX_BITS_H + +#include <linux/const.h> #include <asm/bitsperlong.h> -#define BIT(nr) (1UL << (nr)) -#define BIT_ULL(nr) (1ULL << (nr)) -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT(nr) (UL(1) << (nr)) +#define BIT_ULL(nr) (ULL(1) << (nr)) +#define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) +#define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG)) #define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) #define BITS_PER_BYTE 8 @@ -17,10 +19,11 @@ * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. */ #define GENMASK(h, l) \ - (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + (((~UL(0)) - (UL(1) << (l)) + 1) & \ + (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) #define GENMASK_ULL(h, l) \ - (((~0ULL) - (1ULL << (l)) + 1) & \ - (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) + (((~ULL(0)) - (ULL(1) << (l)) + 1) & \ + (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h)))) #endif /* __LINUX_BITS_H */ diff --git a/tools/include/linux/const.h b/tools/include/linux/const.h new file mode 100644 index 000000000000..7b55a55f5911 --- /dev/null +++ b/tools/include/linux/const.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_CONST_H +#define _LINUX_CONST_H + +#include <uapi/linux/const.h> + +#define UL(x) (_UL(x)) +#define ULL(x) (_ULL(x)) + +#endif /* _LINUX_CONST_H */ diff --git a/tools/include/linux/ring_buffer.h b/tools/include/linux/ring_buffer.h index 9a083ae60473..6c02617377c2 100644 --- a/tools/include/linux/ring_buffer.h +++ b/tools/include/linux/ring_buffer.h @@ -2,6 +2,7 @@ #define _TOOLS_LINUX_RING_BUFFER_H_ #include <asm/barrier.h> +#include <linux/perf_event.h> /* * Contract with kernel for walking the perf ring buffer from diff --git a/tools/include/uapi/asm/bitsperlong.h b/tools/include/uapi/asm/bitsperlong.h index 57aaeaf8e192..edba4d93e9e6 100644 --- a/tools/include/uapi/asm/bitsperlong.h +++ b/tools/include/uapi/asm/bitsperlong.h @@ -1,22 +1,22 @@ /* SPDX-License-Identifier: GPL-2.0 */ #if defined(__i386__) || defined(__x86_64__) -#include "../../arch/x86/include/uapi/asm/bitsperlong.h" +#include "../../../arch/x86/include/uapi/asm/bitsperlong.h" #elif defined(__aarch64__) -#include "../../arch/arm64/include/uapi/asm/bitsperlong.h" +#include "../../../arch/arm64/include/uapi/asm/bitsperlong.h" #elif defined(__powerpc__) -#include "../../arch/powerpc/include/uapi/asm/bitsperlong.h" +#include "../../../arch/powerpc/include/uapi/asm/bitsperlong.h" #elif defined(__s390__) -#include "../../arch/s390/include/uapi/asm/bitsperlong.h" +#include "../../../arch/s390/include/uapi/asm/bitsperlong.h" #elif defined(__sparc__) -#include "../../arch/sparc/include/uapi/asm/bitsperlong.h" +#include "../../../arch/sparc/include/uapi/asm/bitsperlong.h" #elif defined(__mips__) -#include "../../arch/mips/include/uapi/asm/bitsperlong.h" +#include "../../../arch/mips/include/uapi/asm/bitsperlong.h" #elif defined(__ia64__) -#include "../../arch/ia64/include/uapi/asm/bitsperlong.h" +#include "../../../arch/ia64/include/uapi/asm/bitsperlong.h" #elif defined(__riscv) -#include "../../arch/riscv/include/uapi/asm/bitsperlong.h" +#include "../../../arch/riscv/include/uapi/asm/bitsperlong.h" #elif defined(__alpha__) -#include "../../arch/alpha/include/uapi/asm/bitsperlong.h" +#include "../../../arch/alpha/include/uapi/asm/bitsperlong.h" #else #include <asm-generic/bitsperlong.h> #endif diff --git a/tools/include/uapi/linux/const.h b/tools/include/uapi/linux/const.h new file mode 100644 index 000000000000..5ed721ad5b19 --- /dev/null +++ b/tools/include/uapi/linux/const.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* const.h: Macros for dealing with constants. */ + +#ifndef _UAPI_LINUX_CONST_H +#define _UAPI_LINUX_CONST_H + +/* Some constant macros are used in both assembler and + * C code. Therefore we cannot annotate them always with + * 'UL' and other type specifiers unilaterally. We + * use the following macros to deal with this. + * + * Similarly, _AT() will cast an expression with a type in C, but + * leave it unchanged in asm. + */ + +#ifdef __ASSEMBLY__ +#define _AC(X,Y) X +#define _AT(T,X) X +#else +#define __AC(X,Y) (X##Y) +#define _AC(X,Y) __AC(X,Y) +#define _AT(T,X) ((T)(X)) +#endif + +#define _UL(x) (_AC(x, UL)) +#define _ULL(x) (_AC(x, ULL)) + +#define _BITUL(x) (_UL(1) << (x)) +#define _BITULL(x) (_ULL(1) << (x)) + +#endif /* _UAPI_LINUX_CONST_H */ diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index 7198ddd0c6b1..bb7b271397a6 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h @@ -374,7 +374,8 @@ struct perf_event_attr { namespaces : 1, /* include namespaces data */ ksymbol : 1, /* include ksymbol events */ bpf_event : 1, /* include bpf events */ - __reserved_1 : 33; + aux_output : 1, /* generate AUX records instead of events */ + __reserved_1 : 32; union { __u32 wakeup_events; /* wakeup every n events */ diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 3292c290654f..a39cdd0d890d 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -62,15 +62,15 @@ set_plugin_dir := 1 # Set plugin_dir to preffered global plugin location # If we install under $HOME directory we go under -# $(HOME)/.traceevent/plugins +# $(HOME)/.local/lib/traceevent/plugins # # We dont set PLUGIN_DIR in case we install under $HOME # directory, because by default the code looks under: -# $(HOME)/.traceevent/plugins by default. +# $(HOME)/.local/lib/traceevent/plugins by default. # ifeq ($(plugin_dir),) ifeq ($(prefix),$(HOME)) -override plugin_dir = $(HOME)/.traceevent/plugins +override plugin_dir = $(HOME)/.local/lib/traceevent/plugins set_plugin_dir := 0 else override plugin_dir = $(libdir)/traceevent/plugins @@ -266,8 +266,8 @@ endef define do_generate_dynamic_list_file symbol_type=`$(NM) -u -D $1 | awk 'NF>1 {print $$1}' | \ - xargs echo "U W w" | tr ' ' '\n' | sort -u | xargs echo`;\ - if [ "$$symbol_type" = "U W w" ];then \ + xargs echo "U w W" | tr 'w ' 'W\n' | sort -u | xargs echo`;\ + if [ "$$symbol_type" = "U W" ];then \ (echo '{'; \ $(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u;\ echo '};'; \ diff --git a/tools/lib/traceevent/event-parse-api.c b/tools/lib/traceevent/event-parse-api.c index 988587840c80..4faf52a65791 100644 --- a/tools/lib/traceevent/event-parse-api.c +++ b/tools/lib/traceevent/event-parse-api.c @@ -303,33 +303,6 @@ void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian) } /** - * tep_is_latency_format - get if the latency output format is configured - * @tep: a handle to the tep_handle - * - * This returns true if the latency output format is configured - * If @tep is NULL, false is returned. - */ -bool tep_is_latency_format(struct tep_handle *tep) -{ - if (tep) - return (tep->latency_format); - return false; -} - -/** - * tep_set_latency_format - set the latency output format - * @tep: a handle to the tep_handle - * @lat: non zero for latency output format - * - * This sets the latency output format - */ -void tep_set_latency_format(struct tep_handle *tep, int lat) -{ - if (tep) - tep->latency_format = lat; -} - -/** * tep_is_old_format - get if an old kernel is used * @tep: a handle to the tep_handle * @@ -345,19 +318,6 @@ bool tep_is_old_format(struct tep_handle *tep) } /** - * tep_set_print_raw - set a flag to force print in raw format - * @tep: a handle to the tep_handle - * @print_raw: the new value of the print_raw flag - * - * This sets a flag to force print in raw format - */ -void tep_set_print_raw(struct tep_handle *tep, int print_raw) -{ - if (tep) - tep->print_raw = print_raw; -} - -/** * tep_set_test_filters - set a flag to test a filter string * @tep: a handle to the tep_handle * @test_filters: the new value of the test_filters flag diff --git a/tools/lib/traceevent/event-parse-local.h b/tools/lib/traceevent/event-parse-local.h index 09aa142f7fdd..cee469803a34 100644 --- a/tools/lib/traceevent/event-parse-local.h +++ b/tools/lib/traceevent/event-parse-local.h @@ -28,8 +28,6 @@ struct tep_handle { enum tep_endian file_bigendian; enum tep_endian host_bigendian; - int latency_format; - int old_format; int cpus; @@ -70,8 +68,6 @@ struct tep_handle { int ld_offset; int ld_size; - int print_raw; - int test_filters; int flags; @@ -85,8 +81,6 @@ struct tep_handle { /* cache */ struct tep_event *last_event; - - char *trace_clock; }; void tep_free_event(struct tep_event *event); diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index b36b536a9fcb..bb22238debfe 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -142,6 +142,25 @@ static int cmdline_cmp(const void *a, const void *b) return 0; } +/* Looking for where to place the key */ +static int cmdline_slot_cmp(const void *a, const void *b) +{ + const struct tep_cmdline *ca = a; + const struct tep_cmdline *cb = b; + const struct tep_cmdline *cb1 = cb + 1; + + if (ca->pid < cb->pid) + return -1; + + if (ca->pid > cb->pid) { + if (ca->pid <= cb1->pid) + return 0; + return 1; + } + + return 0; +} + struct cmdline_list { struct cmdline_list *next; char *comm; @@ -239,6 +258,7 @@ static int add_new_comm(struct tep_handle *tep, struct tep_cmdline *cmdline; struct tep_cmdline key; char *new_comm; + int cnt; if (!pid) return 0; @@ -269,21 +289,43 @@ static int add_new_comm(struct tep_handle *tep, errno = ENOMEM; return -1; } + tep->cmdlines = cmdlines; - cmdlines[tep->cmdline_count].comm = strdup(comm); - if (!cmdlines[tep->cmdline_count].comm) { - free(cmdlines); + key.comm = strdup(comm); + if (!key.comm) { errno = ENOMEM; return -1; } - cmdlines[tep->cmdline_count].pid = pid; - - if (cmdlines[tep->cmdline_count].comm) + if (!tep->cmdline_count) { + /* no entries yet */ + tep->cmdlines[0] = key; tep->cmdline_count++; + return 0; + } - qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp); - tep->cmdlines = cmdlines; + /* Now find where we want to store the new cmdline */ + cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count - 1, + sizeof(*tep->cmdlines), cmdline_slot_cmp); + + cnt = tep->cmdline_count; + if (cmdline) { + /* cmdline points to the one before the spot we want */ + cmdline++; + cnt -= cmdline - tep->cmdlines; + + } else { + /* The new entry is either before or after the list */ + if (key.pid > tep->cmdlines[tep->cmdline_count - 1].pid) { + tep->cmdlines[tep->cmdline_count++] = key; + return 0; + } + cmdline = &tep->cmdlines[0]; + } + memmove(cmdline + 1, cmdline, (cnt * sizeof(*cmdline))); + *cmdline = key; + + tep->cmdline_count++; return 0; } @@ -351,16 +393,6 @@ int tep_override_comm(struct tep_handle *tep, const char *comm, int pid) return _tep_register_comm(tep, comm, pid, true); } -int tep_register_trace_clock(struct tep_handle *tep, const char *trace_clock) -{ - tep->trace_clock = strdup(trace_clock); - if (!tep->trace_clock) { - errno = ENOMEM; - return -1; - } - return 0; -} - struct func_map { unsigned long long addr; char *func; @@ -5170,24 +5202,20 @@ out_failed: } } -/** - * tep_data_latency_format - parse the data for the latency format - * @tep: a handle to the trace event parser context - * @s: the trace_seq to write to - * @record: the record to read from - * +/* * This parses out the Latency format (interrupts disabled, * need rescheduling, in hard/soft interrupt, preempt count * and lock depth) and places it into the trace_seq. */ -void tep_data_latency_format(struct tep_handle *tep, - struct trace_seq *s, struct tep_record *record) +static void data_latency_format(struct tep_handle *tep, struct trace_seq *s, + char *format, struct tep_record *record) { static int check_lock_depth = 1; static int check_migrate_disable = 1; static int lock_depth_exists; static int migrate_disable_exists; unsigned int lat_flags; + struct trace_seq sq; unsigned int pc; int lock_depth = 0; int migrate_disable = 0; @@ -5195,6 +5223,7 @@ void tep_data_latency_format(struct tep_handle *tep, int softirq; void *data = record->data; + trace_seq_init(&sq); lat_flags = parse_common_flags(tep, data); pc = parse_common_pc(tep, data); /* lock_depth may not always exist */ @@ -5222,7 +5251,7 @@ void tep_data_latency_format(struct tep_handle *tep, hardirq = lat_flags & TRACE_FLAG_HARDIRQ; softirq = lat_flags & TRACE_FLAG_SOFTIRQ; - trace_seq_printf(s, "%c%c%c", + trace_seq_printf(&sq, "%c%c%c", (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' : (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' : '.', @@ -5232,24 +5261,32 @@ void tep_data_latency_format(struct tep_handle *tep, hardirq ? 'h' : softirq ? 's' : '.'); if (pc) - trace_seq_printf(s, "%x", pc); + trace_seq_printf(&sq, "%x", pc); else - trace_seq_putc(s, '.'); + trace_seq_printf(&sq, "."); if (migrate_disable_exists) { if (migrate_disable < 0) - trace_seq_putc(s, '.'); + trace_seq_printf(&sq, "."); else - trace_seq_printf(s, "%d", migrate_disable); + trace_seq_printf(&sq, "%d", migrate_disable); } if (lock_depth_exists) { if (lock_depth < 0) - trace_seq_putc(s, '.'); + trace_seq_printf(&sq, "."); else - trace_seq_printf(s, "%d", lock_depth); + trace_seq_printf(&sq, "%d", lock_depth); + } + + if (sq.state == TRACE_SEQ__MEM_ALLOC_FAILED) { + s->state = TRACE_SEQ__MEM_ALLOC_FAILED; + return; } + trace_seq_terminate(&sq); + trace_seq_puts(s, sq.buffer); + trace_seq_destroy(&sq); trace_seq_terminate(s); } @@ -5410,21 +5447,16 @@ int tep_cmdline_pid(struct tep_handle *tep, struct tep_cmdline *cmdline) return cmdline->pid; } -/** - * tep_event_info - parse the data into the print format - * @s: the trace_seq to write to - * @event: the handle to the event - * @record: the record to read from - * +/* * This parses the raw @data using the given @event information and * writes the print format into the trace_seq. */ -void tep_event_info(struct trace_seq *s, struct tep_event *event, - struct tep_record *record) +static void print_event_info(struct trace_seq *s, char *format, bool raw, + struct tep_event *event, struct tep_record *record) { int print_pretty = 1; - if (event->tep->print_raw || (event->flags & TEP_EVENT_FL_PRINTRAW)) + if (raw || (event->flags & TEP_EVENT_FL_PRINTRAW)) tep_print_fields(s, record->data, record->size, event); else { @@ -5439,20 +5471,6 @@ void tep_event_info(struct trace_seq *s, struct tep_event *event, trace_seq_terminate(s); } -static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) -{ - if (!trace_clock || !use_trace_clock) - return true; - - if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global") - || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf") - || !strncmp(trace_clock, "mono", 4)) - return true; - - /* trace_clock is setting in tsc or counter mode */ - return false; -} - /** * tep_find_event_by_record - return the event from a given record * @tep: a handle to the trace event parser context @@ -5476,129 +5494,195 @@ tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record) return tep_find_event(tep, type); } -/** - * tep_print_event_task - Write the event task comm, pid and CPU - * @tep: a handle to the trace event parser context - * @s: the trace_seq to write to - * @event: the handle to the record's event - * @record: The record to get the event from - * - * Writes the tasks comm, pid and CPU to @s. +/* + * Writes the timestamp of the record into @s. Time divisor and precision can be + * specified as part of printf @format string. Example: + * "%3.1000d" - divide the time by 1000 and print the first 3 digits + * before the dot. Thus, the timestamp "123456000" will be printed as + * "123.456" */ -void tep_print_event_task(struct tep_handle *tep, struct trace_seq *s, - struct tep_event *event, - struct tep_record *record) +static void print_event_time(struct tep_handle *tep, struct trace_seq *s, + char *format, struct tep_event *event, + struct tep_record *record) +{ + unsigned long long time; + char *divstr; + int prec = 0, pr; + int div = 0; + int p10 = 1; + + if (isdigit(*(format + 1))) + prec = atoi(format + 1); + divstr = strchr(format, '.'); + if (divstr && isdigit(*(divstr + 1))) + div = atoi(divstr + 1); + time = record->ts; + if (div) + time /= div; + pr = prec; + while (pr--) + p10 *= 10; + + if (p10 > 1 && p10 < time) + trace_seq_printf(s, "%5llu.%0*llu", time / p10, prec, time % p10); + else + trace_seq_printf(s, "%12llu\n", time); +} + +struct print_event_type { + enum { + EVENT_TYPE_INT = 1, + EVENT_TYPE_STRING, + EVENT_TYPE_UNKNOWN, + } type; + char format[32]; +}; + +static void print_string(struct tep_handle *tep, struct trace_seq *s, + struct tep_record *record, struct tep_event *event, + const char *arg, struct print_event_type *type) { - void *data = record->data; const char *comm; int pid; - pid = parse_common_pid(tep, data); - comm = find_cmdline(tep, pid); + if (strncmp(arg, TEP_PRINT_LATENCY, strlen(TEP_PRINT_LATENCY)) == 0) { + data_latency_format(tep, s, type->format, record); + } else if (strncmp(arg, TEP_PRINT_COMM, strlen(TEP_PRINT_COMM)) == 0) { + pid = parse_common_pid(tep, record->data); + comm = find_cmdline(tep, pid); + trace_seq_printf(s, type->format, comm); + } else if (strncmp(arg, TEP_PRINT_INFO_RAW, strlen(TEP_PRINT_INFO_RAW)) == 0) { + print_event_info(s, type->format, true, event, record); + } else if (strncmp(arg, TEP_PRINT_INFO, strlen(TEP_PRINT_INFO)) == 0) { + print_event_info(s, type->format, false, event, record); + } else if (strncmp(arg, TEP_PRINT_NAME, strlen(TEP_PRINT_NAME)) == 0) { + trace_seq_printf(s, type->format, event->name); + } else { + trace_seq_printf(s, "[UNKNOWN TEP TYPE %s]", arg); + } - if (tep->latency_format) - trace_seq_printf(s, "%8.8s-%-5d %3d", comm, pid, record->cpu); - else - trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); } -/** - * tep_print_event_time - Write the event timestamp - * @tep: a handle to the trace event parser context - * @s: the trace_seq to write to - * @event: the handle to the record's event - * @record: The record to get the event from - * @use_trace_clock: Set to parse according to the @tep->trace_clock - * - * Writes the timestamp of the record into @s. - */ -void tep_print_event_time(struct tep_handle *tep, struct trace_seq *s, - struct tep_event *event, - struct tep_record *record, - bool use_trace_clock) +static void print_int(struct tep_handle *tep, struct trace_seq *s, + struct tep_record *record, struct tep_event *event, + int arg, struct print_event_type *type) { - unsigned long secs; - unsigned long usecs; - unsigned long nsecs; - int p; - bool use_usec_format; + int param; - use_usec_format = is_timestamp_in_us(tep->trace_clock, use_trace_clock); - if (use_usec_format) { - secs = record->ts / NSEC_PER_SEC; - nsecs = record->ts - secs * NSEC_PER_SEC; + switch (arg) { + case TEP_PRINT_CPU: + param = record->cpu; + break; + case TEP_PRINT_PID: + param = parse_common_pid(tep, record->data); + break; + case TEP_PRINT_TIME: + return print_event_time(tep, s, type->format, event, record); + default: + return; } + trace_seq_printf(s, type->format, param); +} - if (tep->latency_format) { - tep_data_latency_format(tep, s, record); - } +static int tep_print_event_param_type(char *format, + struct print_event_type *type) +{ + char *str = format + 1; + int i = 1; - if (use_usec_format) { - if (tep->flags & TEP_NSEC_OUTPUT) { - usecs = nsecs; - p = 9; - } else { - usecs = (nsecs + 500) / NSEC_PER_USEC; - /* To avoid usecs larger than 1 sec */ - if (usecs >= USEC_PER_SEC) { - usecs -= USEC_PER_SEC; - secs++; - } - p = 6; + type->type = EVENT_TYPE_UNKNOWN; + while (*str) { + switch (*str) { + case 'd': + case 'u': + case 'i': + case 'x': + case 'X': + case 'o': + type->type = EVENT_TYPE_INT; + break; + case 's': + type->type = EVENT_TYPE_STRING; + break; } - - trace_seq_printf(s, " %5lu.%0*lu:", secs, p, usecs); - } else - trace_seq_printf(s, " %12llu:", record->ts); + str++; + i++; + if (type->type != EVENT_TYPE_UNKNOWN) + break; + } + memset(type->format, 0, 32); + memcpy(type->format, format, i < 32 ? i : 31); + return i; } /** - * tep_print_event_data - Write the event data section + * tep_print_event - Write various event information * @tep: a handle to the trace event parser context * @s: the trace_seq to write to - * @event: the handle to the record's event * @record: The record to get the event from - * - * Writes the parsing of the record's data to @s. + * @format: a printf format string. Supported event fileds: + * TEP_PRINT_PID, "%d" - event PID + * TEP_PRINT_CPU, "%d" - event CPU + * TEP_PRINT_COMM, "%s" - event command string + * TEP_PRINT_NAME, "%s" - event name + * TEP_PRINT_LATENCY, "%s" - event latency + * TEP_PRINT_TIME, %d - event time stamp. A divisor and precision + * can be specified as part of this format string: + * "%precision.divisord". Example: + * "%3.1000d" - divide the time by 1000 and print the first + * 3 digits before the dot. Thus, the time stamp + * "123456000" will be printed as "123.456" + * TEP_PRINT_INFO, "%s" - event information. If any width is specified in + * the format string, the event information will be printed + * in raw format. + * Writes the specified event information into @s. */ -void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s, - struct tep_event *event, - struct tep_record *record) -{ - static const char *spaces = " "; /* 20 spaces */ - int len; - - trace_seq_printf(s, " %s: ", event->name); - - /* Space out the event names evenly. */ - len = strlen(event->name); - if (len < 20) - trace_seq_printf(s, "%.*s", 20 - len, spaces); - - tep_event_info(s, event, record); -} - void tep_print_event(struct tep_handle *tep, struct trace_seq *s, - struct tep_record *record, bool use_trace_clock) -{ + struct tep_record *record, const char *fmt, ...) +{ + struct print_event_type type; + char *format = strdup(fmt); + char *current = format; + char *str = format; + int offset; + va_list args; struct tep_event *event; - event = tep_find_event_by_record(tep, record); - if (!event) { - int i; - int type = trace_parse_common_type(tep, record->data); - - do_warning("ug! no event found for type %d", type); - trace_seq_printf(s, "[UNKNOWN TYPE %d]", type); - for (i = 0; i < record->size; i++) - trace_seq_printf(s, " %02x", - ((unsigned char *)record->data)[i]); + if (!format) return; - } - tep_print_event_task(tep, s, event, record); - tep_print_event_time(tep, s, event, record, use_trace_clock); - tep_print_event_data(tep, s, event, record); + event = tep_find_event_by_record(tep, record); + va_start(args, fmt); + while (*current) { + current = strchr(str, '%'); + if (!current) { + trace_seq_puts(s, str); + break; + } + memset(&type, 0, sizeof(type)); + offset = tep_print_event_param_type(current, &type); + *current = '\0'; + trace_seq_puts(s, str); + current += offset; + switch (type.type) { + case EVENT_TYPE_STRING: + print_string(tep, s, record, event, + va_arg(args, char*), &type); + break; + case EVENT_TYPE_INT: + print_int(tep, s, record, event, + va_arg(args, int), &type); + break; + case EVENT_TYPE_UNKNOWN: + default: + trace_seq_printf(s, "[UNKNOWN TYPE]"); + break; + } + str = current; + + } + va_end(args); + free(format); } static int events_id_cmp(const void *a, const void *b) @@ -6963,7 +7047,6 @@ void tep_free(struct tep_handle *tep) free_handler(handle); } - free(tep->trace_clock); free(tep->events); free(tep->sort_events); free(tep->func_resolver); diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 642f68ab5fb2..d438ee44289f 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -435,25 +435,24 @@ int tep_set_function_resolver(struct tep_handle *tep, void tep_reset_function_resolver(struct tep_handle *tep); int tep_register_comm(struct tep_handle *tep, const char *comm, int pid); int tep_override_comm(struct tep_handle *tep, const char *comm, int pid); -int tep_register_trace_clock(struct tep_handle *tep, const char *trace_clock); int tep_register_function(struct tep_handle *tep, char *name, unsigned long long addr, char *mod); int tep_register_print_string(struct tep_handle *tep, const char *fmt, unsigned long long addr); bool tep_is_pid_registered(struct tep_handle *tep, int pid); -void tep_print_event_task(struct tep_handle *tep, struct trace_seq *s, - struct tep_event *event, - struct tep_record *record); -void tep_print_event_time(struct tep_handle *tep, struct trace_seq *s, - struct tep_event *event, - struct tep_record *record, - bool use_trace_clock); -void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s, - struct tep_event *event, - struct tep_record *record); +#define TEP_PRINT_INFO "INFO" +#define TEP_PRINT_INFO_RAW "INFO_RAW" +#define TEP_PRINT_COMM "COMM" +#define TEP_PRINT_LATENCY "LATENCY" +#define TEP_PRINT_NAME "NAME" +#define TEP_PRINT_PID 1U +#define TEP_PRINT_TIME 2U +#define TEP_PRINT_CPU 3U + void tep_print_event(struct tep_handle *tep, struct trace_seq *s, - struct tep_record *record, bool use_trace_clock); + struct tep_record *record, const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); int tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size, int long_size); @@ -525,8 +524,6 @@ tep_find_event_by_name(struct tep_handle *tep, const char *sys, const char *name struct tep_event * tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record); -void tep_data_latency_format(struct tep_handle *tep, - struct trace_seq *s, struct tep_record *record); int tep_data_type(struct tep_handle *tep, struct tep_record *rec); int tep_data_pid(struct tep_handle *tep, struct tep_record *rec); int tep_data_preempt_count(struct tep_handle *tep, struct tep_record *rec); @@ -541,8 +538,6 @@ void tep_print_field(struct trace_seq *s, void *data, struct tep_format_field *field); void tep_print_fields(struct trace_seq *s, void *data, int size __maybe_unused, struct tep_event *event); -void tep_event_info(struct trace_seq *s, struct tep_event *event, - struct tep_record *record); int tep_strerror(struct tep_handle *tep, enum tep_errno errnum, char *buf, size_t buflen); @@ -566,12 +561,9 @@ bool tep_is_file_bigendian(struct tep_handle *tep); void tep_set_file_bigendian(struct tep_handle *tep, enum tep_endian endian); bool tep_is_local_bigendian(struct tep_handle *tep); void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian); -bool tep_is_latency_format(struct tep_handle *tep); -void tep_set_latency_format(struct tep_handle *tep, int lat); int tep_get_header_page_size(struct tep_handle *tep); int tep_get_header_timestamp_size(struct tep_handle *tep); bool tep_is_old_format(struct tep_handle *tep); -void tep_set_print_raw(struct tep_handle *tep, int print_raw); void tep_set_test_filters(struct tep_handle *tep, int test_filters); struct tep_handle *tep_alloc(void); diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index 8ca28de9337a..e1f7ddd5a6cf 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c @@ -18,7 +18,7 @@ #include "event-utils.h" #include "trace-seq.h" -#define LOCAL_PLUGIN_DIR ".traceevent/plugins" +#define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/" static struct registered_plugin_options { struct registered_plugin_options *next; diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 20f67fcf378d..d2a19b0bc05a 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -33,7 +33,7 @@ all: $(OBJTOOL) INCLUDES := -I$(srctree)/tools/include \ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ - -I$(srctree)/tools/objtool/arch/$(ARCH)/include + -I$(srctree)/tools/arch/$(ARCH)/include WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS) LDFLAGS += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) @@ -60,7 +60,7 @@ $(LIBSUBCMD): fixdep FORCE clean: $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete - $(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep + $(Q)$(RM) $(OUTPUT)arch/x86/inat-tables.c $(OUTPUT)fixdep FORCE: diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build index b998412c017d..7c5004008e97 100644 --- a/tools/objtool/arch/x86/Build +++ b/tools/objtool/arch/x86/Build @@ -1,7 +1,7 @@ objtool-y += decode.o -inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk -inat_tables_maps = arch/x86/lib/x86-opcode-map.txt +inat_tables_script = ../arch/x86/tools/gen-insn-attr-x86.awk +inat_tables_maps = ../arch/x86/lib/x86-opcode-map.txt $(OUTPUT)arch/x86/lib/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) $(call rule_mkdir) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 0567c47a91b1..a62e032863a8 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -8,8 +8,8 @@ #define unlikely(cond) (cond) #include <asm/insn.h> -#include "lib/inat.c" -#include "lib/insn.c" +#include "../../../arch/x86/lib/inat.c" +#include "../../../arch/x86/lib/insn.c" #include "../../elf.h" #include "../../arch.h" diff --git a/tools/objtool/arch/x86/include/asm/inat.h b/tools/objtool/arch/x86/include/asm/inat.h deleted file mode 100644 index 4cf2ad521f65..000000000000 --- a/tools/objtool/arch/x86/include/asm/inat.h +++ /dev/null @@ -1,230 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_X86_INAT_H -#define _ASM_X86_INAT_H -/* - * x86 instruction attributes - * - * Written by Masami Hiramatsu <mhiramat@redhat.com> - */ -#include <asm/inat_types.h> - -/* - * Internal bits. Don't use bitmasks directly, because these bits are - * unstable. You should use checking functions. - */ - -#define INAT_OPCODE_TABLE_SIZE 256 -#define INAT_GROUP_TABLE_SIZE 8 - -/* Legacy last prefixes */ -#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ -#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ -#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ -/* Other Legacy prefixes */ -#define INAT_PFX_LOCK 4 /* 0xF0 */ -#define INAT_PFX_CS 5 /* 0x2E */ -#define INAT_PFX_DS 6 /* 0x3E */ -#define INAT_PFX_ES 7 /* 0x26 */ -#define INAT_PFX_FS 8 /* 0x64 */ -#define INAT_PFX_GS 9 /* 0x65 */ -#define INAT_PFX_SS 10 /* 0x36 */ -#define INAT_PFX_ADDRSZ 11 /* 0x67 */ -/* x86-64 REX prefix */ -#define INAT_PFX_REX 12 /* 0x4X */ -/* AVX VEX prefixes */ -#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ -#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ -#define INAT_PFX_EVEX 15 /* EVEX prefix */ - -#define INAT_LSTPFX_MAX 3 -#define INAT_LGCPFX_MAX 11 - -/* Immediate size */ -#define INAT_IMM_BYTE 1 -#define INAT_IMM_WORD 2 -#define INAT_IMM_DWORD 3 -#define INAT_IMM_QWORD 4 -#define INAT_IMM_PTR 5 -#define INAT_IMM_VWORD32 6 -#define INAT_IMM_VWORD 7 - -/* Legacy prefix */ -#define INAT_PFX_OFFS 0 -#define INAT_PFX_BITS 4 -#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) -#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) -/* Escape opcodes */ -#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) -#define INAT_ESC_BITS 2 -#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) -#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) -/* Group opcodes (1-16) */ -#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) -#define INAT_GRP_BITS 5 -#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) -#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) -/* Immediates */ -#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) -#define INAT_IMM_BITS 3 -#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) -/* Flags */ -#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) -#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) -#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) -#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) -#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) -#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) -#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) -#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) -#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) -/* Attribute making macros for attribute tables */ -#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) -#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) -#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) -#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) - -/* Identifiers for segment registers */ -#define INAT_SEG_REG_IGNORE 0 -#define INAT_SEG_REG_DEFAULT 1 -#define INAT_SEG_REG_CS 2 -#define INAT_SEG_REG_SS 3 -#define INAT_SEG_REG_DS 4 -#define INAT_SEG_REG_ES 5 -#define INAT_SEG_REG_FS 6 -#define INAT_SEG_REG_GS 7 - -/* Attribute search APIs */ -extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); -extern int inat_get_last_prefix_id(insn_byte_t last_pfx); -extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, - int lpfx_id, - insn_attr_t esc_attr); -extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, - int lpfx_id, - insn_attr_t esc_attr); -extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, - insn_byte_t vex_m, - insn_byte_t vex_pp); - -/* Attribute checking functions */ -static inline int inat_is_legacy_prefix(insn_attr_t attr) -{ - attr &= INAT_PFX_MASK; - return attr && attr <= INAT_LGCPFX_MAX; -} - -static inline int inat_is_address_size_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; -} - -static inline int inat_is_operand_size_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; -} - -static inline int inat_is_rex_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_REX; -} - -static inline int inat_last_prefix_id(insn_attr_t attr) -{ - if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) - return 0; - else - return attr & INAT_PFX_MASK; -} - -static inline int inat_is_vex_prefix(insn_attr_t attr) -{ - attr &= INAT_PFX_MASK; - return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || - attr == INAT_PFX_EVEX; -} - -static inline int inat_is_evex_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; -} - -static inline int inat_is_vex3_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; -} - -static inline int inat_is_escape(insn_attr_t attr) -{ - return attr & INAT_ESC_MASK; -} - -static inline int inat_escape_id(insn_attr_t attr) -{ - return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; -} - -static inline int inat_is_group(insn_attr_t attr) -{ - return attr & INAT_GRP_MASK; -} - -static inline int inat_group_id(insn_attr_t attr) -{ - return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; -} - -static inline int inat_group_common_attribute(insn_attr_t attr) -{ - return attr & ~INAT_GRP_MASK; -} - -static inline int inat_has_immediate(insn_attr_t attr) -{ - return attr & INAT_IMM_MASK; -} - -static inline int inat_immediate_size(insn_attr_t attr) -{ - return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; -} - -static inline int inat_has_modrm(insn_attr_t attr) -{ - return attr & INAT_MODRM; -} - -static inline int inat_is_force64(insn_attr_t attr) -{ - return attr & INAT_FORCE64; -} - -static inline int inat_has_second_immediate(insn_attr_t attr) -{ - return attr & INAT_SCNDIMM; -} - -static inline int inat_has_moffset(insn_attr_t attr) -{ - return attr & INAT_MOFFSET; -} - -static inline int inat_has_variant(insn_attr_t attr) -{ - return attr & INAT_VARIANT; -} - -static inline int inat_accept_vex(insn_attr_t attr) -{ - return attr & INAT_VEXOK; -} - -static inline int inat_must_vex(insn_attr_t attr) -{ - return attr & (INAT_VEXONLY | INAT_EVEXONLY); -} - -static inline int inat_must_evex(insn_attr_t attr) -{ - return attr & INAT_EVEXONLY; -} -#endif diff --git a/tools/objtool/arch/x86/include/asm/insn.h b/tools/objtool/arch/x86/include/asm/insn.h deleted file mode 100644 index 154f27be8bfc..000000000000 --- a/tools/objtool/arch/x86/include/asm/insn.h +++ /dev/null @@ -1,216 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_X86_INSN_H -#define _ASM_X86_INSN_H -/* - * x86 instruction analysis - * - * Copyright (C) IBM Corporation, 2009 - */ - -/* insn_attr_t is defined in inat.h */ -#include <asm/inat.h> - -struct insn_field { - union { - insn_value_t value; - insn_byte_t bytes[4]; - }; - /* !0 if we've run insn_get_xxx() for this field */ - unsigned char got; - unsigned char nbytes; -}; - -struct insn { - struct insn_field prefixes; /* - * Prefixes - * prefixes.bytes[3]: last prefix - */ - struct insn_field rex_prefix; /* REX prefix */ - struct insn_field vex_prefix; /* VEX prefix */ - struct insn_field opcode; /* - * opcode.bytes[0]: opcode1 - * opcode.bytes[1]: opcode2 - * opcode.bytes[2]: opcode3 - */ - struct insn_field modrm; - struct insn_field sib; - struct insn_field displacement; - union { - struct insn_field immediate; - struct insn_field moffset1; /* for 64bit MOV */ - struct insn_field immediate1; /* for 64bit imm or off16/32 */ - }; - union { - struct insn_field moffset2; /* for 64bit MOV */ - struct insn_field immediate2; /* for 64bit imm or seg16 */ - }; - - insn_attr_t attr; - unsigned char opnd_bytes; - unsigned char addr_bytes; - unsigned char length; - unsigned char x86_64; - - const insn_byte_t *kaddr; /* kernel address of insn to analyze */ - const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ - const insn_byte_t *next_byte; -}; - -#define MAX_INSN_SIZE 15 - -#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) -#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) -#define X86_MODRM_RM(modrm) ((modrm) & 0x07) - -#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) -#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) -#define X86_SIB_BASE(sib) ((sib) & 0x07) - -#define X86_REX_W(rex) ((rex) & 8) -#define X86_REX_R(rex) ((rex) & 4) -#define X86_REX_X(rex) ((rex) & 2) -#define X86_REX_B(rex) ((rex) & 1) - -/* VEX bit flags */ -#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ -#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ -#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ -#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ -#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ -/* VEX bit fields */ -#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ -#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ -#define X86_VEX2_M 1 /* VEX2.M always 1 */ -#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ -#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ -#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ - -extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); -extern void insn_get_prefixes(struct insn *insn); -extern void insn_get_opcode(struct insn *insn); -extern void insn_get_modrm(struct insn *insn); -extern void insn_get_sib(struct insn *insn); -extern void insn_get_displacement(struct insn *insn); -extern void insn_get_immediate(struct insn *insn); -extern void insn_get_length(struct insn *insn); - -/* Attribute will be determined after getting ModRM (for opcode groups) */ -static inline void insn_get_attribute(struct insn *insn) -{ - insn_get_modrm(insn); -} - -/* Instruction uses RIP-relative addressing */ -extern int insn_rip_relative(struct insn *insn); - -/* Init insn for kernel text */ -static inline void kernel_insn_init(struct insn *insn, - const void *kaddr, int buf_len) -{ -#ifdef CONFIG_X86_64 - insn_init(insn, kaddr, buf_len, 1); -#else /* CONFIG_X86_32 */ - insn_init(insn, kaddr, buf_len, 0); -#endif -} - -static inline int insn_is_avx(struct insn *insn) -{ - if (!insn->prefixes.got) - insn_get_prefixes(insn); - return (insn->vex_prefix.value != 0); -} - -static inline int insn_is_evex(struct insn *insn) -{ - if (!insn->prefixes.got) - insn_get_prefixes(insn); - return (insn->vex_prefix.nbytes == 4); -} - -/* Ensure this instruction is decoded completely */ -static inline int insn_complete(struct insn *insn) -{ - return insn->opcode.got && insn->modrm.got && insn->sib.got && - insn->displacement.got && insn->immediate.got; -} - -static inline insn_byte_t insn_vex_m_bits(struct insn *insn) -{ - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ - return X86_VEX2_M; - else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ - return X86_VEX3_M(insn->vex_prefix.bytes[1]); - else /* EVEX */ - return X86_EVEX_M(insn->vex_prefix.bytes[1]); -} - -static inline insn_byte_t insn_vex_p_bits(struct insn *insn) -{ - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ - return X86_VEX_P(insn->vex_prefix.bytes[1]); - else - return X86_VEX_P(insn->vex_prefix.bytes[2]); -} - -/* Get the last prefix id from last prefix or VEX prefix */ -static inline int insn_last_prefix_id(struct insn *insn) -{ - if (insn_is_avx(insn)) - return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ - - if (insn->prefixes.bytes[3]) - return inat_get_last_prefix_id(insn->prefixes.bytes[3]); - - return 0; -} - -/* Offset of each field from kaddr */ -static inline int insn_offset_rex_prefix(struct insn *insn) -{ - return insn->prefixes.nbytes; -} -static inline int insn_offset_vex_prefix(struct insn *insn) -{ - return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; -} -static inline int insn_offset_opcode(struct insn *insn) -{ - return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; -} -static inline int insn_offset_modrm(struct insn *insn) -{ - return insn_offset_opcode(insn) + insn->opcode.nbytes; -} -static inline int insn_offset_sib(struct insn *insn) -{ - return insn_offset_modrm(insn) + insn->modrm.nbytes; -} -static inline int insn_offset_displacement(struct insn *insn) -{ - return insn_offset_sib(insn) + insn->sib.nbytes; -} -static inline int insn_offset_immediate(struct insn *insn) -{ - return insn_offset_displacement(insn) + insn->displacement.nbytes; -} - -#define POP_SS_OPCODE 0x1f -#define MOV_SREG_OPCODE 0x8e - -/* - * Intel SDM Vol.3A 6.8.3 states; - * "Any single-step trap that would be delivered following the MOV to SS - * instruction or POP to SS instruction (because EFLAGS.TF is 1) is - * suppressed." - * This function returns true if @insn is MOV SS or POP SS. On these - * instructions, single stepping is suppressed. - */ -static inline int insn_masking_exception(struct insn *insn) -{ - return insn->opcode.bytes[0] == POP_SS_OPCODE || - (insn->opcode.bytes[0] == MOV_SREG_OPCODE && - X86_MODRM_REG(insn->modrm.bytes[0]) == 2); -} - -#endif /* _ASM_X86_INSN_H */ diff --git a/tools/objtool/arch/x86/lib/insn.c b/tools/objtool/arch/x86/lib/insn.c deleted file mode 100644 index 0b5862ba6a75..000000000000 --- a/tools/objtool/arch/x86/lib/insn.c +++ /dev/null @@ -1,593 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * x86 instruction analysis - * - * Copyright (C) IBM Corporation, 2002, 2004, 2009 - */ - -#ifdef __KERNEL__ -#include <linux/string.h> -#else -#include <string.h> -#endif -#include <asm/inat.h> -#include <asm/insn.h> - -/* Verify next sizeof(t) bytes can be on the same instruction */ -#define validate_next(t, insn, n) \ - ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) - -#define __get_next(t, insn) \ - ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) - -#define __peek_nbyte_next(t, insn, n) \ - ({ t r = *(t*)((insn)->next_byte + n); r; }) - -#define get_next(t, insn) \ - ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) - -#define peek_nbyte_next(t, insn, n) \ - ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) - -#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) - -/** - * insn_init() - initialize struct insn - * @insn: &struct insn to be initialized - * @kaddr: address (in kernel memory) of instruction (or copy thereof) - * @x86_64: !0 for 64-bit kernel or 64-bit app - */ -void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) -{ - /* - * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid - * even if the input buffer is long enough to hold them. - */ - if (buf_len > MAX_INSN_SIZE) - buf_len = MAX_INSN_SIZE; - - memset(insn, 0, sizeof(*insn)); - insn->kaddr = kaddr; - insn->end_kaddr = kaddr + buf_len; - insn->next_byte = kaddr; - insn->x86_64 = x86_64 ? 1 : 0; - insn->opnd_bytes = 4; - if (x86_64) - insn->addr_bytes = 8; - else - insn->addr_bytes = 4; -} - -/** - * insn_get_prefixes - scan x86 instruction prefix bytes - * @insn: &struct insn containing instruction - * - * Populates the @insn->prefixes bitmap, and updates @insn->next_byte - * to point to the (first) opcode. No effect if @insn->prefixes.got - * is already set. - */ -void insn_get_prefixes(struct insn *insn) -{ - struct insn_field *prefixes = &insn->prefixes; - insn_attr_t attr; - insn_byte_t b, lb; - int i, nb; - - if (prefixes->got) - return; - - nb = 0; - lb = 0; - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - while (inat_is_legacy_prefix(attr)) { - /* Skip if same prefix */ - for (i = 0; i < nb; i++) - if (prefixes->bytes[i] == b) - goto found; - if (nb == 4) - /* Invalid instruction */ - break; - prefixes->bytes[nb++] = b; - if (inat_is_address_size_prefix(attr)) { - /* address size switches 2/4 or 4/8 */ - if (insn->x86_64) - insn->addr_bytes ^= 12; - else - insn->addr_bytes ^= 6; - } else if (inat_is_operand_size_prefix(attr)) { - /* oprand size switches 2/4 */ - insn->opnd_bytes ^= 6; - } -found: - prefixes->nbytes++; - insn->next_byte++; - lb = b; - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - } - /* Set the last prefix */ - if (lb && lb != insn->prefixes.bytes[3]) { - if (unlikely(insn->prefixes.bytes[3])) { - /* Swap the last prefix */ - b = insn->prefixes.bytes[3]; - for (i = 0; i < nb; i++) - if (prefixes->bytes[i] == lb) - prefixes->bytes[i] = b; - } - insn->prefixes.bytes[3] = lb; - } - - /* Decode REX prefix */ - if (insn->x86_64) { - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_rex_prefix(attr)) { - insn->rex_prefix.value = b; - insn->rex_prefix.nbytes = 1; - insn->next_byte++; - if (X86_REX_W(b)) - /* REX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } - } - insn->rex_prefix.got = 1; - - /* Decode VEX prefix */ - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_vex_prefix(attr)) { - insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); - if (!insn->x86_64) { - /* - * In 32-bits mode, if the [7:6] bits (mod bits of - * ModRM) on the second byte are not 11b, it is - * LDS or LES or BOUND. - */ - if (X86_MODRM_MOD(b2) != 3) - goto vex_end; - } - insn->vex_prefix.bytes[0] = b; - insn->vex_prefix.bytes[1] = b2; - if (inat_is_evex_prefix(attr)) { - b2 = peek_nbyte_next(insn_byte_t, insn, 2); - insn->vex_prefix.bytes[2] = b2; - b2 = peek_nbyte_next(insn_byte_t, insn, 3); - insn->vex_prefix.bytes[3] = b2; - insn->vex_prefix.nbytes = 4; - insn->next_byte += 4; - if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } else if (inat_is_vex3_prefix(attr)) { - b2 = peek_nbyte_next(insn_byte_t, insn, 2); - insn->vex_prefix.bytes[2] = b2; - insn->vex_prefix.nbytes = 3; - insn->next_byte += 3; - if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } else { - /* - * For VEX2, fake VEX3-like byte#2. - * Makes it easier to decode vex.W, vex.vvvv, - * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. - */ - insn->vex_prefix.bytes[2] = b2 & 0x7f; - insn->vex_prefix.nbytes = 2; - insn->next_byte += 2; - } - } -vex_end: - insn->vex_prefix.got = 1; - - prefixes->got = 1; - -err_out: - return; -} - -/** - * insn_get_opcode - collect opcode(s) - * @insn: &struct insn containing instruction - * - * Populates @insn->opcode, updates @insn->next_byte to point past the - * opcode byte(s), and set @insn->attr (except for groups). - * If necessary, first collects any preceding (prefix) bytes. - * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got - * is already 1. - */ -void insn_get_opcode(struct insn *insn) -{ - struct insn_field *opcode = &insn->opcode; - insn_byte_t op; - int pfx_id; - if (opcode->got) - return; - if (!insn->prefixes.got) - insn_get_prefixes(insn); - - /* Get first opcode */ - op = get_next(insn_byte_t, insn); - opcode->bytes[0] = op; - opcode->nbytes = 1; - - /* Check if there is VEX prefix or not */ - if (insn_is_avx(insn)) { - insn_byte_t m, p; - m = insn_vex_m_bits(insn); - p = insn_vex_p_bits(insn); - insn->attr = inat_get_avx_attribute(op, m, p); - if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || - (!inat_accept_vex(insn->attr) && - !inat_is_group(insn->attr))) - insn->attr = 0; /* This instruction is bad */ - goto end; /* VEX has only 1 byte for opcode */ - } - - insn->attr = inat_get_opcode_attribute(op); - while (inat_is_escape(insn->attr)) { - /* Get escaped opcode */ - op = get_next(insn_byte_t, insn); - opcode->bytes[opcode->nbytes++] = op; - pfx_id = insn_last_prefix_id(insn); - insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); - } - if (inat_must_vex(insn->attr)) - insn->attr = 0; /* This instruction is bad */ -end: - opcode->got = 1; - -err_out: - return; -} - -/** - * insn_get_modrm - collect ModRM byte, if any - * @insn: &struct insn containing instruction - * - * Populates @insn->modrm and updates @insn->next_byte to point past the - * ModRM byte, if any. If necessary, first collects the preceding bytes - * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. - */ -void insn_get_modrm(struct insn *insn) -{ - struct insn_field *modrm = &insn->modrm; - insn_byte_t pfx_id, mod; - if (modrm->got) - return; - if (!insn->opcode.got) - insn_get_opcode(insn); - - if (inat_has_modrm(insn->attr)) { - mod = get_next(insn_byte_t, insn); - modrm->value = mod; - modrm->nbytes = 1; - if (inat_is_group(insn->attr)) { - pfx_id = insn_last_prefix_id(insn); - insn->attr = inat_get_group_attribute(mod, pfx_id, - insn->attr); - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) - insn->attr = 0; /* This is bad */ - } - } - - if (insn->x86_64 && inat_is_force64(insn->attr)) - insn->opnd_bytes = 8; - modrm->got = 1; - -err_out: - return; -} - - -/** - * insn_rip_relative() - Does instruction use RIP-relative addressing mode? - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * ModRM byte. No effect if @insn->x86_64 is 0. - */ -int insn_rip_relative(struct insn *insn) -{ - struct insn_field *modrm = &insn->modrm; - - if (!insn->x86_64) - return 0; - if (!modrm->got) - insn_get_modrm(insn); - /* - * For rip-relative instructions, the mod field (top 2 bits) - * is zero and the r/m field (bottom 3 bits) is 0x5. - */ - return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); -} - -/** - * insn_get_sib() - Get the SIB byte of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * ModRM byte. - */ -void insn_get_sib(struct insn *insn) -{ - insn_byte_t modrm; - - if (insn->sib.got) - return; - if (!insn->modrm.got) - insn_get_modrm(insn); - if (insn->modrm.nbytes) { - modrm = (insn_byte_t)insn->modrm.value; - if (insn->addr_bytes != 2 && - X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { - insn->sib.value = get_next(insn_byte_t, insn); - insn->sib.nbytes = 1; - } - } - insn->sib.got = 1; - -err_out: - return; -} - - -/** - * insn_get_displacement() - Get the displacement of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * SIB byte. - * Displacement value is sign-expanded. - */ -void insn_get_displacement(struct insn *insn) -{ - insn_byte_t mod, rm, base; - - if (insn->displacement.got) - return; - if (!insn->sib.got) - insn_get_sib(insn); - if (insn->modrm.nbytes) { - /* - * Interpreting the modrm byte: - * mod = 00 - no displacement fields (exceptions below) - * mod = 01 - 1-byte displacement field - * mod = 10 - displacement field is 4 bytes, or 2 bytes if - * address size = 2 (0x67 prefix in 32-bit mode) - * mod = 11 - no memory operand - * - * If address size = 2... - * mod = 00, r/m = 110 - displacement field is 2 bytes - * - * If address size != 2... - * mod != 11, r/m = 100 - SIB byte exists - * mod = 00, SIB base = 101 - displacement field is 4 bytes - * mod = 00, r/m = 101 - rip-relative addressing, displacement - * field is 4 bytes - */ - mod = X86_MODRM_MOD(insn->modrm.value); - rm = X86_MODRM_RM(insn->modrm.value); - base = X86_SIB_BASE(insn->sib.value); - if (mod == 3) - goto out; - if (mod == 1) { - insn->displacement.value = get_next(signed char, insn); - insn->displacement.nbytes = 1; - } else if (insn->addr_bytes == 2) { - if ((mod == 0 && rm == 6) || mod == 2) { - insn->displacement.value = - get_next(short, insn); - insn->displacement.nbytes = 2; - } - } else { - if ((mod == 0 && rm == 5) || mod == 2 || - (mod == 0 && base == 5)) { - insn->displacement.value = get_next(int, insn); - insn->displacement.nbytes = 4; - } - } - } -out: - insn->displacement.got = 1; - -err_out: - return; -} - -/* Decode moffset16/32/64. Return 0 if failed */ -static int __get_moffset(struct insn *insn) -{ - switch (insn->addr_bytes) { - case 2: - insn->moffset1.value = get_next(short, insn); - insn->moffset1.nbytes = 2; - break; - case 4: - insn->moffset1.value = get_next(int, insn); - insn->moffset1.nbytes = 4; - break; - case 8: - insn->moffset1.value = get_next(int, insn); - insn->moffset1.nbytes = 4; - insn->moffset2.value = get_next(int, insn); - insn->moffset2.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->moffset1.got = insn->moffset2.got = 1; - - return 1; - -err_out: - return 0; -} - -/* Decode imm v32(Iz). Return 0 if failed */ -static int __get_immv32(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate.value = get_next(short, insn); - insn->immediate.nbytes = 2; - break; - case 4: - case 8: - insn->immediate.value = get_next(int, insn); - insn->immediate.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - - return 1; - -err_out: - return 0; -} - -/* Decode imm v64(Iv/Ov), Return 0 if failed */ -static int __get_immv(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate1.value = get_next(short, insn); - insn->immediate1.nbytes = 2; - break; - case 4: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - break; - case 8: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - insn->immediate2.value = get_next(int, insn); - insn->immediate2.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->immediate1.got = insn->immediate2.got = 1; - - return 1; -err_out: - return 0; -} - -/* Decode ptr16:16/32(Ap) */ -static int __get_immptr(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate1.value = get_next(short, insn); - insn->immediate1.nbytes = 2; - break; - case 4: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - break; - case 8: - /* ptr16:64 is not exist (no segment) */ - return 0; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->immediate2.value = get_next(unsigned short, insn); - insn->immediate2.nbytes = 2; - insn->immediate1.got = insn->immediate2.got = 1; - - return 1; -err_out: - return 0; -} - -/** - * insn_get_immediate() - Get the immediates of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * displacement bytes. - * Basically, most of immediates are sign-expanded. Unsigned-value can be - * get by bit masking with ((1 << (nbytes * 8)) - 1) - */ -void insn_get_immediate(struct insn *insn) -{ - if (insn->immediate.got) - return; - if (!insn->displacement.got) - insn_get_displacement(insn); - - if (inat_has_moffset(insn->attr)) { - if (!__get_moffset(insn)) - goto err_out; - goto done; - } - - if (!inat_has_immediate(insn->attr)) - /* no immediates */ - goto done; - - switch (inat_immediate_size(insn->attr)) { - case INAT_IMM_BYTE: - insn->immediate.value = get_next(signed char, insn); - insn->immediate.nbytes = 1; - break; - case INAT_IMM_WORD: - insn->immediate.value = get_next(short, insn); - insn->immediate.nbytes = 2; - break; - case INAT_IMM_DWORD: - insn->immediate.value = get_next(int, insn); - insn->immediate.nbytes = 4; - break; - case INAT_IMM_QWORD: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - insn->immediate2.value = get_next(int, insn); - insn->immediate2.nbytes = 4; - break; - case INAT_IMM_PTR: - if (!__get_immptr(insn)) - goto err_out; - break; - case INAT_IMM_VWORD32: - if (!__get_immv32(insn)) - goto err_out; - break; - case INAT_IMM_VWORD: - if (!__get_immv(insn)) - goto err_out; - break; - default: - /* Here, insn must have an immediate, but failed */ - goto err_out; - } - if (inat_has_second_immediate(insn->attr)) { - insn->immediate2.value = get_next(signed char, insn); - insn->immediate2.nbytes = 1; - } -done: - insn->immediate.got = 1; - -err_out: - return; -} - -/** - * insn_get_length() - Get the length of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * immediates bytes. - */ -void insn_get_length(struct insn *insn) -{ - if (insn->length) - return; - if (!insn->immediate.got) - insn_get_immediate(insn); - insn->length = (unsigned char)((unsigned long)insn->next_byte - - (unsigned long)insn->kaddr); -} diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index 1470e74e9d66..0a832e265a50 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -2,28 +2,50 @@ # SPDX-License-Identifier: GPL-2.0 FILES=' -arch/x86/lib/insn.c -arch/x86/lib/inat.c -arch/x86/lib/x86-opcode-map.txt -arch/x86/tools/gen-insn-attr-x86.awk -arch/x86/include/asm/insn.h -arch/x86/include/asm/inat.h arch/x86/include/asm/inat_types.h arch/x86/include/asm/orc_types.h +arch/x86/lib/x86-opcode-map.txt +arch/x86/tools/gen-insn-attr-x86.awk ' -check() -{ - local file=$1 +check_2 () { + file1=$1 + file2=$2 - diff $file ../../$file > /dev/null || - echo "Warning: synced file at 'tools/objtool/$file' differs from latest kernel version at '$file'" + shift + shift + + cmd="diff $* $file1 $file2 > /dev/null" + + test -f $file2 && { + eval $cmd || { + echo "Warning: Kernel ABI header at '$file1' differs from latest version at '$file2'" >&2 + echo diff -u $file1 $file2 + } + } +} + +check () { + file=$1 + + shift + + check_2 tools/$file $file $* } if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then exit 0 fi +cd ../.. + for i in $FILES; do check $i done + +check arch/x86/include/asm/inat.h '-I "^#include [\"<]\(asm/\)*inat_types.h[\">]"' +check arch/x86/include/asm/insn.h '-I "^#include [\"<]\(asm/\)*inat.h[\">]"' +check arch/x86/lib/inat.c '-I "^#include [\"<]\(../include/\)*asm/insn.h[\">]"' +check arch/x86/lib/insn.c '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]"' + +cd - diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 3e5135dded16..bf1252dc2cb0 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -34,3 +34,6 @@ arch/*/include/generated/ trace/beauty/generated/ pmu-events/pmu-events.c pmu-events/jevents +feature/ +fixdep +libtraceevent-dynamic-list diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index 50c5b60101bd..e0d9e7dd4f17 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt @@ -919,3 +919,18 @@ amended to take the number of elements as a parameter. Note there is currently no advantage to using Intel PT instead of LBR, but that may change in the future if greater use is made of the data. + + +PEBS via Intel PT +================= + +Some hardware has the feature to redirect PEBS records to the Intel PT trace. +Recording is selected by using the aux-output config term e.g. + + perf record -c 10000 -e '{intel_pt/branch=0/,cycles/aux-output/ppp}' uname + +Note that currently, software only supports redirecting at most one PEBS event. + +To display PEBS events from the Intel PT trace, use the itrace 'o' option e.g. + + perf script --itrace=oe diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index c2182cbabde3..82ff7dad40c2 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -5,6 +5,8 @@ x synthesize transactions events w synthesize ptwrite events p synthesize power events + o synthesize other events recorded due to the use + of aux-output (refer to perf record) e synthesize error events d create a debug log g synthesize a call chain (use with i or x) diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index e4aa268d2e38..c599623a1f3d 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -40,6 +40,10 @@ The '$HOME/.perfconfig' file is used to store a per-user configuration. The file '$(sysconfdir)/perfconfig' can be used to store a system-wide default configuration. +One an disable reading config files by setting the PERF_CONFIG environment +variable to /dev/null, or provide an alternate config file by setting that +variable. + When reading or writing, the values are read from the system and user configuration files by default, and options '--system' and '--user' can be used to tell the command to read from or write to only that location. diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 15e0fa87241b..c6f9f31b6039 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -60,6 +60,8 @@ OPTIONS - 'name' : User defined event name. Single quotes (') may be used to escape symbols in the name from parsing by shell and tool like this: name=\'CPU_CLK_UNHALTED.THREAD:cmask=0x1\'. + - 'aux-output': Generate AUX records instead of events. This requires + that an AUX area event is also provided. See the linkperf:perf-list[1] man page for more parameters. @@ -422,9 +424,14 @@ CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI. -S:: --snapshot:: Select AUX area tracing Snapshot Mode. This option is valid only with an -AUX area tracing event. Optionally the number of bytes to capture per -snapshot can be specified. In Snapshot Mode, trace data is captured only when -signal SIGUSR2 is received. +AUX area tracing event. Optionally, certain snapshot capturing parameters +can be specified in a string that follows this option: + 'e': take one last snapshot on exit; guarantees that there is at least one + snapshot in the output file; + <size>: if the PMU supports this, specify the desired snapshot size. + +In Snapshot Mode trace data is captured only when signal SIGUSR2 is received +and on exit if the above 'e' option is given. --proc-map-timeout:: When processing pre-existing threads /proc/XXX/mmap, it may take a long time, diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 987261d158d4..7315f155803f 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -438,6 +438,23 @@ OPTIONS perf report --time 0%-10%,30%-40% +--switch-on EVENT_NAME:: + Only consider events after this event is found. + + This may be interesting to measure a workload only after some initialization + phase is over, i.e. insert a perf probe at that point and then using this + option with that probe. + +--switch-off EVENT_NAME:: + Stop considering events after this event is found. + +--show-on-off-events:: + Show the --switch-on/off events too. This has no effect in 'perf report' now + but probably we'll make the default not to show the switch-on/off events + on the --group mode and if there is only one event besides the off/on ones, + go straight to the histogram browser, just like 'perf report' with no events + explicitely specified does. + --itrace:: Options for decoding instruction tracing data. The options are: diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index caaab28f8400..2599b057e47b 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -417,6 +417,15 @@ include::itrace.txt[] For itrace only show specified functions and their callees for itrace. Multiple functions can be separated by comma. +--switch-on EVENT_NAME:: + Only consider events after this event is found. + +--switch-off EVENT_NAME:: + Stop considering events after this event is found. + +--show-on-off-events:: + Show the --switch-on/off events too. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1], diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index cfea87c6f38e..5596129a71cf 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -266,6 +266,44 @@ Default is to monitor all CPUS. Record events of type PERF_RECORD_NAMESPACES and display it with the 'cgroup_id' sort key. +--switch-on EVENT_NAME:: + Only consider events after this event is found. + + E.g.: + + Find out where broadcast packets are handled + + perf probe -L icmp_rcv + + Insert a probe there: + + perf probe icmp_rcv:59 + + Start perf top and ask it to only consider the cycles events when a + broadcast packet arrives This will show a menu with two entries and + will start counting when a broadcast packet arrives: + + perf top -e cycles,probe:icmp_rcv --switch-on=probe:icmp_rcv + + Alternatively one can ask for --group and then two overhead columns + will appear, the first for cycles and the second for the switch-on event. + + perf top --group -e cycles,probe:icmp_rcv --switch-on=probe:icmp_rcv + + This may be interesting to measure a workload only after some initialization + phase is over, i.e. insert a perf probe at that point and use the above + examples replacing probe:icmp_rcv with the just-after-init probe. + +--switch-off EVENT_NAME:: + Stop considering events after this event is found. + +--show-on-off-events:: + Show the --switch-on/off events too. This has no effect in 'perf top' now + but probably we'll make the default not to show the switch-on/off events + on the --group mode and if there is only one event besides the off/on ones, + go straight to the histogram browser, just like 'perf top' with no events + explicitely specified does. + INTERACTIVE PROMPTING KEYS -------------------------- diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index fc6e43262c41..25b74fdb36fa 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -176,6 +176,15 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. only at exit time or when a syscall is interrupted, i.e. in those cases this option is equivalent to the number of lines printed. +--switch-on EVENT_NAME:: + Only consider events after this event is found. + +--switch-off EVENT_NAME:: + Stop considering events after this event is found. + +--show-on-off-events:: + Show the --switch-on/off events too. + --max-stack:: Set the stack depth limit when parsing the callchain, anything beyond the specified depth will be ignored. Note that at this point diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt index d030c87ed9f5..b0152e1095c5 100644 --- a/tools/perf/Documentation/perf.data-file-format.txt +++ b/tools/perf/Documentation/perf.data-file-format.txt @@ -298,16 +298,21 @@ Physical memory map and its node assignments. The format of data in MEM_TOPOLOGY is as follows: - 0 - version | for future changes - 8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes - 16 - count | number of nodes - -For each node we store map of physical indexes: - - 32 - node id | node index - 40 - size | size of bitmap - 48 - bitmap | bitmap of memory indexes that belongs to node - | /sys/devices/system/node/node<NODE>/memory<INDEX> + u64 version; // Currently 1 + u64 block_size_bytes; // /sys/devices/system/memory/block_size_bytes + u64 count; // number of nodes + +struct memory_node { + u64 node_id; // node index + u64 size; // size of bitmap + struct bitmap { + /* size of bitmap again */ + u64 bitmapsize; + /* bitmap of memory indexes that belongs to node */ + /* /sys/devices/system/node/node<NODE>/memory<INDEX> */ + u64 entries[(bitmapsize/64)+1]; + } +}[count]; The MEM_TOPOLOGY can be displayed with following command: diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index eaf25ee104e4..a269d78456b6 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -281,11 +281,12 @@ ifeq ($(DEBUG),0) endif endif +INC_FLAGS += -I$(src-perf)/lib/include INC_FLAGS += -I$(src-perf)/util/include INC_FLAGS += -I$(src-perf)/arch/$(SRCARCH)/include -INC_FLAGS += -I$(srctree)/tools/include/uapi INC_FLAGS += -I$(srctree)/tools/include/ INC_FLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi +INC_FLAGS += -I$(srctree)/tools/include/uapi INC_FLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/ INC_FLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/ @@ -827,6 +828,17 @@ ifndef NO_LIBZSTD endif endif +ifndef NO_LIBCAP + ifeq ($(feature-libcap), 1) + CFLAGS += -DHAVE_LIBCAP_SUPPORT + EXTLIBS += -lcap + $(call detected,CONFIG_LIBCAP) + else + msg := $(warning No libcap found, disables capability support, please install libcap-devel/libcap-dev); + NO_LIBCAP := 1 + endif +endif + ifndef NO_BACKTRACE ifeq ($(feature-backtrace), 1) CFLAGS += -DHAVE_BACKTRACE_SUPPORT diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 0fffd2bb6cd9..f9807d8c005b 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -88,6 +88,8 @@ include ../scripts/utilities.mak # # Define NO_LIBBPF if you do not want BPF support # +# Define NO_LIBCAP if you do not want process capabilities considered by perf +# # Define NO_SDT if you do not want to define SDT event in perf tools, # note that it doesn't disable SDT scanning support. # @@ -224,6 +226,7 @@ LIB_DIR = $(srctree)/tools/lib/api/ TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ BPF_DIR = $(srctree)/tools/lib/bpf/ SUBCMD_DIR = $(srctree)/tools/lib/subcmd/ +LIBPERF_DIR = $(srctree)/tools/perf/lib/ # Set FEATURE_TESTS to 'all' so all possible feature checkers are executed. # Without this setting the output feature dump file misses some features, for @@ -272,6 +275,7 @@ ifneq ($(OUTPUT),) TE_PATH=$(OUTPUT) BPF_PATH=$(OUTPUT) SUBCMD_PATH=$(OUTPUT) + LIBPERF_PATH=$(OUTPUT) ifneq ($(subdir),) API_PATH=$(OUTPUT)/../lib/api/ else @@ -282,6 +286,7 @@ else API_PATH=$(LIB_DIR) BPF_PATH=$(BPF_DIR) SUBCMD_PATH=$(SUBCMD_DIR) + LIBPERF_PATH=$(LIBPERF_DIR) endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a @@ -303,6 +308,9 @@ LIBBPF = $(BPF_PATH)libbpf.a LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a +LIBPERF = $(LIBPERF_PATH)libperf.a +export LIBPERF + # python extension build directories PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ @@ -348,9 +356,7 @@ endif export PERL_PATH -LIBPERF_A=$(OUTPUT)libperf.a - -PERFLIBS = $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD) +PERFLIBS = $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD) $(LIBPERF) ifndef NO_LIBBPF PERFLIBS += $(LIBBPF) endif @@ -583,8 +589,6 @@ JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o PMU_EVENTS_IN := $(OUTPUT)pmu-events/pmu-events-in.o -LIBPERF_IN := $(OUTPUT)libperf-in.o - export JEVENTS build := -f $(srctree)/tools/build/Makefile.build dir=. obj @@ -601,12 +605,9 @@ $(JEVENTS): $(JEVENTS_IN) $(PMU_EVENTS_IN): $(JEVENTS) FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=pmu-events -$(LIBPERF_IN): prepare FORCE - $(Q)$(MAKE) $(build)=libperf - -$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBPERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) +$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ - $(PERF_IN) $(PMU_EVENTS_IN) $(LIBPERF_IN) $(LIBS) -o $@ + $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@ $(GTK_IN): FORCE $(Q)$(MAKE) $(build)=gtk @@ -727,9 +728,6 @@ endif $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) -$(LIBPERF_A): $(LIBPERF_IN) - $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) $(LIB_OBJS) - LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' 'LDFLAGS=$(LDFLAGS)' $(LIBTRACEEVENT): FORCE @@ -762,6 +760,13 @@ $(LIBBPF)-clean: $(call QUIET_CLEAN, libbpf) $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null +$(LIBPERF): FORCE + $(Q)$(MAKE) -C $(LIBPERF_DIR) O=$(OUTPUT) $(OUTPUT)libperf.a + +$(LIBPERF)-clean: + $(call QUIET_CLEAN, libperf) + $(Q)$(MAKE) -C $(LIBPERF_DIR) O=$(OUTPUT) clean >/dev/null + $(LIBSUBCMD): FORCE $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a @@ -948,7 +953,7 @@ config-clean: python-clean: $(python-clean) -clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean fixdep-clean python-clean +clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBPERF)-clean config-clean fixdep-clean python-clean $(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete $(Q)$(RM) $(OUTPUT).config-detected diff --git a/tools/perf/arch/arm/annotate/instructions.c b/tools/perf/arch/arm/annotate/instructions.c index c7d1a69b894f..e1d4b484cc4b 100644 --- a/tools/perf/arch/arm/annotate/instructions.c +++ b/tools/perf/arch/arm/annotate/instructions.c @@ -3,6 +3,7 @@ #include <linux/zalloc.h> #include <sys/types.h> #include <regex.h> +#include <stdlib.h> struct arm_annotate { regex_t call_insn, diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c index 02014740a1aa..0a6e75b8777a 100644 --- a/tools/perf/arch/arm/util/auxtrace.c +++ b/tools/perf/arch/arm/util/auxtrace.c @@ -9,6 +9,7 @@ #include <linux/zalloc.h> #include "../../util/auxtrace.h" +#include "../../util/debug.h" #include "../../util/evlist.h" #include "../../util/pmu.h" #include "cs-etm.h" @@ -50,10 +51,10 @@ static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err) } struct auxtrace_record -*auxtrace_record__init(struct perf_evlist *evlist, int *err) +*auxtrace_record__init(struct evlist *evlist, int *err) { struct perf_pmu *cs_etm_pmu; - struct perf_evsel *evsel; + struct evsel *evsel; bool found_etm = false; bool found_spe = false; static struct perf_pmu **arm_spe_pmus = NULL; @@ -70,14 +71,14 @@ struct auxtrace_record evlist__for_each_entry(evlist, evsel) { if (cs_etm_pmu && - evsel->attr.type == cs_etm_pmu->type) + evsel->core.attr.type == cs_etm_pmu->type) found_etm = true; if (!nr_spes) continue; for (i = 0; i < nr_spes; i++) { - if (evsel->attr.type == arm_spe_pmus[i]->type) { + if (evsel->core.attr.type == arm_spe_pmus[i]->type) { found_spe = true; break; } diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 4208974c24f8..c32db09baf0d 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -11,19 +11,22 @@ #include <linux/coresight-pmu.h> #include <linux/kernel.h> #include <linux/log2.h> +#include <linux/string.h> #include <linux/types.h> #include <linux/zalloc.h> #include "cs-etm.h" -#include "../../perf.h" +#include "../../util/debug.h" +#include "../../util/record.h" #include "../../util/auxtrace.h" #include "../../util/cpumap.h" +#include "../../util/event.h" #include "../../util/evlist.h" #include "../../util/evsel.h" #include "../../util/pmu.h" -#include "../../util/thread_map.h" #include "../../util/cs-etm.h" #include "../../util/util.h" +#include "../../util/session.h" #include <errno.h> #include <stdlib.h> @@ -32,7 +35,7 @@ struct cs_etm_recording { struct auxtrace_record itr; struct perf_pmu *cs_etm_pmu; - struct perf_evlist *evlist; + struct evlist *evlist; int wrapped_cnt; bool *wrapped; bool snapshot_mode; @@ -55,7 +58,7 @@ static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); static int cs_etm_set_context_id(struct auxtrace_record *itr, - struct perf_evsel *evsel, int cpu) + struct evsel *evsel, int cpu) { struct cs_etm_recording *ptr; struct perf_pmu *cs_etm_pmu; @@ -95,7 +98,7 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, } /* All good, let the kernel know */ - evsel->attr.config |= (1 << ETM_OPT_CTXTID); + evsel->core.attr.config |= (1 << ETM_OPT_CTXTID); err = 0; out: @@ -104,7 +107,7 @@ out: } static int cs_etm_set_timestamp(struct auxtrace_record *itr, - struct perf_evsel *evsel, int cpu) + struct evsel *evsel, int cpu) { struct cs_etm_recording *ptr; struct perf_pmu *cs_etm_pmu; @@ -144,7 +147,7 @@ static int cs_etm_set_timestamp(struct auxtrace_record *itr, } /* All good, let the kernel know */ - evsel->attr.config |= (1 << ETM_OPT_TS); + evsel->core.attr.config |= (1 << ETM_OPT_TS); err = 0; out: @@ -152,11 +155,11 @@ out: } static int cs_etm_set_option(struct auxtrace_record *itr, - struct perf_evsel *evsel, u32 option) + struct evsel *evsel, u32 option) { int i, err = -EINVAL; - struct cpu_map *event_cpus = evsel->evlist->cpus; - struct cpu_map *online_cpus = cpu_map__new(NULL); + struct perf_cpu_map *event_cpus = evsel->evlist->core.cpus; + struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); /* Set option of each CPU we have */ for (i = 0; i < cpu__max_cpu(); i++) { @@ -181,7 +184,7 @@ static int cs_etm_set_option(struct auxtrace_record *itr, err = 0; out: - cpu_map__put(online_cpus); + perf_cpu_map__put(online_cpus); return err; } @@ -208,14 +211,14 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, } static int cs_etm_set_sink_attr(struct perf_pmu *pmu, - struct perf_evsel *evsel) + struct evsel *evsel) { char msg[BUFSIZ], path[PATH_MAX], *sink; struct perf_evsel_config_term *term; int ret = -EINVAL; u32 hash; - if (evsel->attr.config2 & GENMASK(31, 0)) + if (evsel->core.attr.config2 & GENMASK(31, 0)) return 0; list_for_each_entry(term, &evsel->config_terms, list) { @@ -233,7 +236,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, return ret; } - evsel->attr.config2 |= hash; + evsel->core.attr.config2 |= hash; return 0; } @@ -245,16 +248,16 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, } static int cs_etm_recording_options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts) { int ret; struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; - struct perf_evsel *evsel, *cs_etm_evsel = NULL; - struct cpu_map *cpus = evlist->cpus; - bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0); + struct evsel *evsel, *cs_etm_evsel = NULL; + struct perf_cpu_map *cpus = evlist->core.cpus; + bool privileged = perf_event_paranoid_check(-1); int err = 0; ptr->evlist = evlist; @@ -264,14 +267,14 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, opts->record_switch_events = true; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == cs_etm_pmu->type) { + if (evsel->core.attr.type == cs_etm_pmu->type) { if (cs_etm_evsel) { pr_err("There may be only one %s event\n", CORESIGHT_ETM_PMU_NAME); return -EINVAL; } - evsel->attr.freq = 0; - evsel->attr.sample_period = 1; + evsel->core.attr.freq = 0; + evsel->core.attr.sample_period = 1; cs_etm_evsel = evsel; opts->full_auxtrace = true; } @@ -396,7 +399,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, * AUX event. We also need the contextID in order to be notified * when a context switch happened. */ - if (!cpu_map__empty(cpus)) { + if (!perf_cpu_map__empty(cpus)) { perf_evsel__set_sample_bit(cs_etm_evsel, CPU); err = cs_etm_set_option(itr, cs_etm_evsel, @@ -407,7 +410,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, /* Add dummy event to keep tracking */ if (opts->full_auxtrace) { - struct perf_evsel *tracking_evsel; + struct evsel *tracking_evsel; err = parse_events(evlist, "dummy:u", NULL); if (err) @@ -416,11 +419,11 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, tracking_evsel = perf_evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); - tracking_evsel->attr.freq = 0; - tracking_evsel->attr.sample_period = 1; + tracking_evsel->core.attr.freq = 0; + tracking_evsel->core.attr.sample_period = 1; /* In per-cpu case, always need the time of mmap events etc */ - if (!cpu_map__empty(cpus)) + if (!perf_cpu_map__empty(cpus)) perf_evsel__set_sample_bit(tracking_evsel, TIME); } @@ -434,11 +437,11 @@ static u64 cs_etm_get_config(struct auxtrace_record *itr) struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; - struct perf_evlist *evlist = ptr->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = ptr->evlist; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == cs_etm_pmu->type) { + if (evsel->core.attr.type == cs_etm_pmu->type) { /* * Variable perf_event_attr::config is assigned to * ETMv3/PTM. The bit fields have been made to match @@ -447,7 +450,7 @@ static u64 cs_etm_get_config(struct auxtrace_record *itr) * drivers/hwtracing/coresight/coresight-perf.c for * details. */ - config = evsel->attr.config; + config = evsel->core.attr.config; break; } } @@ -485,15 +488,15 @@ static u64 cs_etmv4_get_config(struct auxtrace_record *itr) static size_t cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { int i; int etmv3 = 0, etmv4 = 0; - struct cpu_map *event_cpus = evlist->cpus; - struct cpu_map *online_cpus = cpu_map__new(NULL); + struct perf_cpu_map *event_cpus = evlist->core.cpus; + struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); /* cpu map is not empty, we have specific CPUs to work with */ - if (!cpu_map__empty(event_cpus)) { + if (!perf_cpu_map__empty(event_cpus)) { for (i = 0; i < cpu__max_cpu(); i++) { if (!cpu_map__has(event_cpus, i) || !cpu_map__has(online_cpus, i)) @@ -517,7 +520,7 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, } } - cpu_map__put(online_cpus); + perf_cpu_map__put(online_cpus); return (CS_ETM_HEADER_SIZE + (etmv4 * CS_ETMV4_PRIV_SIZE) + @@ -564,7 +567,7 @@ static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) static void cs_etm_get_metadata(int cpu, u32 *offset, struct auxtrace_record *itr, - struct auxtrace_info_event *info) + struct perf_record_auxtrace_info *info) { u32 increment; u64 magic; @@ -629,15 +632,15 @@ static void cs_etm_get_metadata(int cpu, u32 *offset, static int cs_etm_info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *info, + struct perf_record_auxtrace_info *info, size_t priv_size) { int i; u32 offset; u64 nr_cpu, type; - struct cpu_map *cpu_map; - struct cpu_map *event_cpus = session->evlist->cpus; - struct cpu_map *online_cpus = cpu_map__new(NULL); + struct perf_cpu_map *cpu_map; + struct perf_cpu_map *event_cpus = session->evlist->core.cpus; + struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; @@ -649,11 +652,11 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, return -EINVAL; /* If the cpu_map is empty all online CPUs are involved */ - if (cpu_map__empty(event_cpus)) { + if (perf_cpu_map__empty(event_cpus)) { cpu_map = online_cpus; } else { /* Make sure all specified CPUs are online */ - for (i = 0; i < cpu_map__nr(event_cpus); i++) { + for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { if (cpu_map__has(event_cpus, i) && !cpu_map__has(online_cpus, i)) return -EINVAL; @@ -662,7 +665,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, cpu_map = event_cpus; } - nr_cpu = cpu_map__nr(cpu_map); + nr_cpu = perf_cpu_map__nr(cpu_map); /* Get PMU type as dynamically assigned by the core */ type = cs_etm_pmu->type; @@ -679,7 +682,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, if (cpu_map__has(cpu_map, i)) cs_etm_get_metadata(i, &offset, itr, info); - cpu_map__put(online_cpus); + perf_cpu_map__put(online_cpus); return 0; } @@ -817,11 +820,11 @@ static int cs_etm_snapshot_start(struct auxtrace_record *itr) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(ptr->evlist, evsel) { - if (evsel->attr.type == ptr->cs_etm_pmu->type) - return perf_evsel__disable(evsel); + if (evsel->core.attr.type == ptr->cs_etm_pmu->type) + return evsel__disable(evsel); } return -EINVAL; } @@ -830,11 +833,11 @@ static int cs_etm_snapshot_finish(struct auxtrace_record *itr) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(ptr->evlist, evsel) { - if (evsel->attr.type == ptr->cs_etm_pmu->type) - return perf_evsel__enable(evsel); + if (evsel->core.attr.type == ptr->cs_etm_pmu->type) + return evsel__enable(evsel); } return -EINVAL; } @@ -858,10 +861,10 @@ static int cs_etm_read_finish(struct auxtrace_record *itr, int idx) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(ptr->evlist, evsel) { - if (evsel->attr.type == ptr->cs_etm_pmu->type) + if (evsel->core.attr.type == ptr->cs_etm_pmu->type) return perf_evlist__enable_event_idx(ptr->evlist, evsel, idx); } diff --git a/tools/perf/arch/arm64/annotate/instructions.c b/tools/perf/arch/arm64/annotate/instructions.c index 8f70a1b282df..43aa93ed8414 100644 --- a/tools/perf/arch/arm64/annotate/instructions.c +++ b/tools/perf/arch/arm64/annotate/instructions.c @@ -2,6 +2,7 @@ #include <linux/compiler.h> #include <sys/types.h> #include <regex.h> +#include <stdlib.h> struct arm64_annotate { regex_t call_insn, diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 2c009aa74633..4b364692da67 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -12,6 +12,7 @@ #include <time.h> #include "../../util/cpumap.h" +#include "../../util/event.h" #include "../../util/evsel.h" #include "../../util/evlist.h" #include "../../util/session.h" @@ -19,6 +20,7 @@ #include "../../util/pmu.h" #include "../../util/debug.h" #include "../../util/auxtrace.h" +#include "../../util/record.h" #include "../../util/arm-spe.h" #define KiB(x) ((x) * 1024) @@ -27,19 +29,19 @@ struct arm_spe_recording { struct auxtrace_record itr; struct perf_pmu *arm_spe_pmu; - struct perf_evlist *evlist; + struct evlist *evlist; }; static size_t arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return ARM_SPE_AUXTRACE_PRIV_SIZE; } static int arm_spe_info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size) { struct arm_spe_recording *sper = @@ -59,27 +61,27 @@ static int arm_spe_info_fill(struct auxtrace_record *itr, } static int arm_spe_recording_options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts) { struct arm_spe_recording *sper = container_of(itr, struct arm_spe_recording, itr); struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; - struct perf_evsel *evsel, *arm_spe_evsel = NULL; - bool privileged = geteuid() == 0 || perf_event_paranoid() < 0; - struct perf_evsel *tracking_evsel; + struct evsel *evsel, *arm_spe_evsel = NULL; + bool privileged = perf_event_paranoid_check(-1); + struct evsel *tracking_evsel; int err; sper->evlist = evlist; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == arm_spe_pmu->type) { + if (evsel->core.attr.type == arm_spe_pmu->type) { if (arm_spe_evsel) { pr_err("There may be only one " ARM_SPE_PMU_NAME "x event\n"); return -EINVAL; } - evsel->attr.freq = 0; - evsel->attr.sample_period = 1; + evsel->core.attr.freq = 0; + evsel->core.attr.sample_period = 1; arm_spe_evsel = evsel; opts->full_auxtrace = true; } @@ -130,8 +132,8 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, tracking_evsel = perf_evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); - tracking_evsel->attr.freq = 0; - tracking_evsel->attr.sample_period = 1; + tracking_evsel->core.attr.freq = 0; + tracking_evsel->core.attr.sample_period = 1; perf_evsel__set_sample_bit(tracking_evsel, TIME); perf_evsel__set_sample_bit(tracking_evsel, CPU); perf_evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK); @@ -160,10 +162,10 @@ static int arm_spe_read_finish(struct auxtrace_record *itr, int idx) { struct arm_spe_recording *sper = container_of(itr, struct arm_spe_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(sper->evlist, evsel) { - if (evsel->attr.type == sper->arm_spe_pmu->type) + if (evsel->core.attr.type == sper->arm_spe_pmu->type) return perf_evlist__enable_event_idx(sper->evlist, evsel, idx); } diff --git a/tools/perf/arch/arm64/util/header.c b/tools/perf/arch/arm64/util/header.c index 534cd2507d83..e41defaaa2e6 100644 --- a/tools/perf/arch/arm64/util/header.c +++ b/tools/perf/arch/arm64/util/header.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdlib.h> #include <api/fs/fs.h> +#include "debug.h" #include "header.h" #define MIDR "/regs/identification/midr_el1" @@ -16,7 +17,7 @@ char *get_cpuid_str(struct perf_pmu *pmu) const char *sysfs = sysfs__mountpoint(); int cpu; u64 midr = 0; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; FILE *file; if (!sysfs || !pmu || !pmu->cpus) @@ -27,7 +28,7 @@ char *get_cpuid_str(struct perf_pmu *pmu) return NULL; /* read midr from list of cpus mapped to this pmu */ - cpus = cpu_map__get(pmu->cpus); + cpus = perf_cpu_map__get(pmu->cpus); for (cpu = 0; cpu < cpus->nr; cpu++) { scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d"MIDR, sysfs, cpus->map[cpu]); @@ -60,6 +61,6 @@ char *get_cpuid_str(struct perf_pmu *pmu) buf = NULL; } - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return buf; } diff --git a/tools/perf/arch/arm64/util/sym-handling.c b/tools/perf/arch/arm64/util/sym-handling.c index 27fcf24d6850..5df788985130 100644 --- a/tools/perf/arch/arm64/util/sym-handling.c +++ b/tools/perf/arch/arm64/util/sym-handling.c @@ -4,11 +4,9 @@ * Copyright (C) 2015 Naveen N. Rao, IBM Corporation */ -#include "debug.h" -#include "symbol.h" -#include "map.h" -#include "probe-event.h" -#include "probe-file.h" +#include "symbol.h" // for the elf__needs_adjust_symbols() prototype +#include <stdbool.h> +#include <gelf.h> #ifdef HAVE_LIBELF_SUPPORT bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 1a9e22f78c22..59dd875fd5e4 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 +#include <limits.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <unistd.h> #include "common.h" #include "../util/env.h" #include "../util/debug.h" diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index c298a446d1f6..e965ed8bb328 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -2,7 +2,9 @@ #ifndef ARCH_PERF_COMMON_H #define ARCH_PERF_COMMON_H -#include "../util/env.h" +#include <stdbool.h> + +struct perf_env; int perf_env__lookup_objdump(struct perf_env *env, const char **path); bool perf_env__single_address_space(struct perf_env *env); diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl index db3bbb8744af..43f736ed47f2 100644 --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -20,7 +20,9 @@ 10 common unlink sys_unlink 11 nospu execve sys_execve compat_sys_execve 12 common chdir sys_chdir -13 common time sys_time compat_sys_time +13 32 time sys_time32 +13 64 time sys_time +13 spu time sys_time 14 common mknod sys_mknod 15 common chmod sys_chmod 16 common lchown sys_lchown @@ -36,14 +38,17 @@ 22 spu umount sys_ni_syscall 23 common setuid sys_setuid 24 common getuid sys_getuid -25 common stime sys_stime compat_sys_stime +25 32 stime sys_stime32 +25 64 stime sys_stime +25 spu stime sys_stime 26 nospu ptrace sys_ptrace compat_sys_ptrace 27 common alarm sys_alarm 28 32 oldfstat sys_fstat sys_ni_syscall 28 64 oldfstat sys_ni_syscall 28 spu oldfstat sys_ni_syscall 29 nospu pause sys_pause -30 nospu utime sys_utime compat_sys_utime +30 32 utime sys_utime32 +30 64 utime sys_utime 31 common stty sys_ni_syscall 32 common gtty sys_ni_syscall 33 common access sys_access @@ -157,7 +162,9 @@ 121 common setdomainname sys_setdomainname 122 common uname sys_newuname 123 common modify_ldt sys_ni_syscall -124 common adjtimex sys_adjtimex compat_sys_adjtimex +124 32 adjtimex sys_adjtimex_time32 +124 64 adjtimex sys_adjtimex +124 spu adjtimex sys_adjtimex 125 common mprotect sys_mprotect 126 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask 126 64 sigprocmask sys_ni_syscall @@ -198,8 +205,12 @@ 158 common sched_yield sys_sched_yield 159 common sched_get_priority_max sys_sched_get_priority_max 160 common sched_get_priority_min sys_sched_get_priority_min -161 common sched_rr_get_interval sys_sched_rr_get_interval compat_sys_sched_rr_get_interval -162 common nanosleep sys_nanosleep compat_sys_nanosleep +161 32 sched_rr_get_interval sys_sched_rr_get_interval_time32 +161 64 sched_rr_get_interval sys_sched_rr_get_interval +161 spu sched_rr_get_interval sys_sched_rr_get_interval +162 32 nanosleep sys_nanosleep_time32 +162 64 nanosleep sys_nanosleep +162 spu nanosleep sys_nanosleep 163 common mremap sys_mremap 164 common setresuid sys_setresuid 165 common getresuid sys_getresuid @@ -213,7 +224,8 @@ 173 nospu rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction 174 nospu rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask 175 nospu rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending -176 nospu rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait +176 32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32 +176 64 rt_sigtimedwait sys_rt_sigtimedwait 177 nospu rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo 178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend 179 common pread64 sys_pread64 compat_sys_pread64 @@ -260,7 +272,9 @@ 218 common removexattr sys_removexattr 219 common lremovexattr sys_lremovexattr 220 common fremovexattr sys_fremovexattr -221 common futex sys_futex compat_sys_futex +221 32 futex sys_futex_time32 +221 64 futex sys_futex +221 spu futex sys_futex 222 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity 223 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity # 224 unused @@ -268,7 +282,9 @@ 226 32 sendfile64 sys_sendfile64 compat_sys_sendfile64 227 common io_setup sys_io_setup compat_sys_io_setup 228 common io_destroy sys_io_destroy -229 common io_getevents sys_io_getevents compat_sys_io_getevents +229 32 io_getevents sys_io_getevents_time32 +229 64 io_getevents sys_io_getevents +229 spu io_getevents sys_io_getevents 230 common io_submit sys_io_submit compat_sys_io_submit 231 common io_cancel sys_io_cancel 232 nospu set_tid_address sys_set_tid_address @@ -280,19 +296,33 @@ 238 common epoll_wait sys_epoll_wait 239 common remap_file_pages sys_remap_file_pages 240 common timer_create sys_timer_create compat_sys_timer_create -241 common timer_settime sys_timer_settime compat_sys_timer_settime -242 common timer_gettime sys_timer_gettime compat_sys_timer_gettime +241 32 timer_settime sys_timer_settime32 +241 64 timer_settime sys_timer_settime +241 spu timer_settime sys_timer_settime +242 32 timer_gettime sys_timer_gettime32 +242 64 timer_gettime sys_timer_gettime +242 spu timer_gettime sys_timer_gettime 243 common timer_getoverrun sys_timer_getoverrun 244 common timer_delete sys_timer_delete -245 common clock_settime sys_clock_settime compat_sys_clock_settime -246 common clock_gettime sys_clock_gettime compat_sys_clock_gettime -247 common clock_getres sys_clock_getres compat_sys_clock_getres -248 common clock_nanosleep sys_clock_nanosleep compat_sys_clock_nanosleep +245 32 clock_settime sys_clock_settime32 +245 64 clock_settime sys_clock_settime +245 spu clock_settime sys_clock_settime +246 32 clock_gettime sys_clock_gettime32 +246 64 clock_gettime sys_clock_gettime +246 spu clock_gettime sys_clock_gettime +247 32 clock_getres sys_clock_getres_time32 +247 64 clock_getres sys_clock_getres +247 spu clock_getres sys_clock_getres +248 32 clock_nanosleep sys_clock_nanosleep_time32 +248 64 clock_nanosleep sys_clock_nanosleep +248 spu clock_nanosleep sys_clock_nanosleep 249 32 swapcontext ppc_swapcontext ppc32_swapcontext 249 64 swapcontext ppc64_swapcontext 249 spu swapcontext sys_ni_syscall 250 common tgkill sys_tgkill -251 common utimes sys_utimes compat_sys_utimes +251 32 utimes sys_utimes_time32 +251 64 utimes sys_utimes +251 spu utimes sys_utimes 252 common statfs64 sys_statfs64 compat_sys_statfs64 253 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 254 32 fadvise64_64 ppc_fadvise64_64 @@ -308,8 +338,10 @@ 261 nospu set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy 262 nospu mq_open sys_mq_open compat_sys_mq_open 263 nospu mq_unlink sys_mq_unlink -264 nospu mq_timedsend sys_mq_timedsend compat_sys_mq_timedsend -265 nospu mq_timedreceive sys_mq_timedreceive compat_sys_mq_timedreceive +264 32 mq_timedsend sys_mq_timedsend_time32 +264 64 mq_timedsend sys_mq_timedsend +265 32 mq_timedreceive sys_mq_timedreceive_time32 +265 64 mq_timedreceive sys_mq_timedreceive 266 nospu mq_notify sys_mq_notify compat_sys_mq_notify 267 nospu mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr 268 nospu kexec_load sys_kexec_load compat_sys_kexec_load @@ -324,8 +356,10 @@ 277 nospu inotify_rm_watch sys_inotify_rm_watch 278 nospu spu_run sys_spu_run 279 nospu spu_create sys_spu_create -280 nospu pselect6 sys_pselect6 compat_sys_pselect6 -281 nospu ppoll sys_ppoll compat_sys_ppoll +280 32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32 +280 64 pselect6 sys_pselect6 +281 32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32 +281 64 ppoll sys_ppoll 282 common unshare sys_unshare 283 common splice sys_splice 284 common tee sys_tee @@ -334,7 +368,9 @@ 287 common mkdirat sys_mkdirat 288 common mknodat sys_mknodat 289 common fchownat sys_fchownat -290 common futimesat sys_futimesat compat_sys_futimesat +290 32 futimesat sys_futimesat_time32 +290 64 futimesat sys_futimesat +290 spu utimesat sys_futimesat 291 32 fstatat64 sys_fstatat64 291 64 newfstatat sys_newfstatat 291 spu newfstatat sys_newfstatat @@ -350,15 +386,21 @@ 301 common move_pages sys_move_pages compat_sys_move_pages 302 common getcpu sys_getcpu 303 nospu epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait -304 common utimensat sys_utimensat compat_sys_utimensat +304 32 utimensat sys_utimensat_time32 +304 64 utimensat sys_utimensat +304 spu utimensat sys_utimensat 305 common signalfd sys_signalfd compat_sys_signalfd 306 common timerfd_create sys_timerfd_create 307 common eventfd sys_eventfd 308 common sync_file_range2 sys_sync_file_range2 compat_sys_sync_file_range2 309 nospu fallocate sys_fallocate compat_sys_fallocate 310 nospu subpage_prot sys_subpage_prot -311 common timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime -312 common timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime +311 32 timerfd_settime sys_timerfd_settime32 +311 64 timerfd_settime sys_timerfd_settime +311 spu timerfd_settime sys_timerfd_settime +312 32 timerfd_gettime sys_timerfd_gettime32 +312 64 timerfd_gettime sys_timerfd_gettime +312 spu timerfd_gettime sys_timerfd_gettime 313 common signalfd4 sys_signalfd4 compat_sys_signalfd4 314 common eventfd2 sys_eventfd2 315 common epoll_create1 sys_epoll_create1 @@ -389,11 +431,15 @@ 340 common getsockopt sys_getsockopt compat_sys_getsockopt 341 common sendmsg sys_sendmsg compat_sys_sendmsg 342 common recvmsg sys_recvmsg compat_sys_recvmsg -343 common recvmmsg sys_recvmmsg compat_sys_recvmmsg +343 32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32 +343 64 recvmmsg sys_recvmmsg +343 spu recvmmsg sys_recvmmsg 344 common accept4 sys_accept4 345 common name_to_handle_at sys_name_to_handle_at 346 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at -347 common clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime +347 32 clock_adjtime sys_clock_adjtime32 +347 64 clock_adjtime sys_clock_adjtime +347 spu clock_adjtime sys_clock_adjtime 348 common syncfs sys_syncfs 349 common sendmmsg sys_sendmmsg compat_sys_sendmmsg 350 common setns sys_setns @@ -414,6 +460,7 @@ 363 spu switch_endian sys_ni_syscall 364 common userfaultfd sys_userfaultfd 365 common membarrier sys_membarrier +# 366-377 originally left for IPC, now unused 378 nospu mlock2 sys_mlock2 379 nospu copy_file_range sys_copy_file_range 380 common preadv2 sys_preadv2 compat_sys_preadv2 @@ -424,4 +471,49 @@ 385 nospu pkey_free sys_pkey_free 386 nospu pkey_mprotect sys_pkey_mprotect 387 nospu rseq sys_rseq -388 nospu io_pgetevents sys_io_pgetevents compat_sys_io_pgetevents +388 32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents +388 64 io_pgetevents sys_io_pgetevents +# room for arch specific syscalls +392 64 semtimedop sys_semtimedop +393 common semget sys_semget +394 common semctl sys_semctl compat_sys_semctl +395 common shmget sys_shmget +396 common shmctl sys_shmctl compat_sys_shmctl +397 common shmat sys_shmat compat_sys_shmat +398 common shmdt sys_shmdt +399 common msgget sys_msgget +400 common msgsnd sys_msgsnd compat_sys_msgsnd +401 common msgrcv sys_msgrcv compat_sys_msgrcv +402 common msgctl sys_msgctl compat_sys_msgctl +403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime +404 32 clock_settime64 sys_clock_settime sys_clock_settime +405 32 clock_adjtime64 sys_clock_adjtime sys_clock_adjtime +406 32 clock_getres_time64 sys_clock_getres sys_clock_getres +407 32 clock_nanosleep_time64 sys_clock_nanosleep sys_clock_nanosleep +408 32 timer_gettime64 sys_timer_gettime sys_timer_gettime +409 32 timer_settime64 sys_timer_settime sys_timer_settime +410 32 timerfd_gettime64 sys_timerfd_gettime sys_timerfd_gettime +411 32 timerfd_settime64 sys_timerfd_settime sys_timerfd_settime +412 32 utimensat_time64 sys_utimensat sys_utimensat +413 32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64 +414 32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64 +416 32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents +417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64 +418 32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend +419 32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive +420 32 semtimedop_time64 sys_semtimedop sys_semtimedop +421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64 +422 32 futex_time64 sys_futex sys_futex +423 32 sched_rr_get_interval_time64 sys_sched_rr_get_interval sys_sched_rr_get_interval +424 common pidfd_send_signal sys_pidfd_send_signal +425 common io_uring_setup sys_io_uring_setup +426 common io_uring_enter sys_io_uring_enter +427 common io_uring_register sys_io_uring_register +428 common open_tree sys_open_tree +429 common move_mount sys_move_mount +430 common fsopen sys_fsopen +431 common fsconfig sys_fsconfig +432 common fsmount sys_fsmount +433 common fspick sys_fspick +434 common pidfd_open sys_pidfd_open +435 nospu clone3 ppc_clone3 diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c index f9db341c47b6..f0dbf7b075c8 100644 --- a/tools/perf/arch/powerpc/util/kvm-stat.c +++ b/tools/perf/arch/powerpc/util/kvm-stat.c @@ -32,7 +32,7 @@ const char *ppc_book3s_hv_kvm_tp[] = { const char *kvm_events_tp[NR_TPS + 1]; const char *kvm_exit_reason; -static void hcall_event_get_key(struct perf_evsel *evsel, +static void hcall_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -55,14 +55,14 @@ static const char *get_hcall_exit_reason(u64 exit_code) return "UNKNOWN"; } -static bool hcall_event_end(struct perf_evsel *evsel, +static bool hcall_event_end(struct evsel *evsel, struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) { return (!strcmp(evsel->name, kvm_events_tp[3])); } -static bool hcall_event_begin(struct perf_evsel *evsel, +static bool hcall_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { if (!strcmp(evsel->name, kvm_events_tp[2])) { @@ -106,7 +106,7 @@ const char * const kvm_skip_events[] = { }; -static int is_tracepoint_available(const char *str, struct perf_evlist *evlist) +static int is_tracepoint_available(const char *str, struct evlist *evlist) { struct parse_events_error err; int ret; @@ -119,7 +119,7 @@ static int is_tracepoint_available(const char *str, struct perf_evlist *evlist) } static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm, - struct perf_evlist *evlist) + struct evlist *evlist) { const char **events_ptr; int i, nr_tp = 0, err = -1; @@ -146,7 +146,7 @@ static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm, /* Wrapper to setup kvm tracepoints */ static int ppc__setup_kvm_tp(struct perf_kvm_stat *kvm) { - struct perf_evlist *evlist = perf_evlist__new(); + struct evlist *evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; diff --git a/tools/perf/arch/powerpc/util/mem-events.c b/tools/perf/arch/powerpc/util/mem-events.c index d08311f04e95..07fb5e049488 100644 --- a/tools/perf/arch/powerpc/util/mem-events.c +++ b/tools/perf/arch/powerpc/util/mem-events.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include "map_symbol.h" #include "mem-events.h" /* PowerPC does not support 'ldlat' parameter. */ diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c index f14102b85509..e9c436eeffc9 100644 --- a/tools/perf/arch/powerpc/util/perf_regs.c +++ b/tools/perf/arch/powerpc/util/perf_regs.c @@ -4,7 +4,6 @@ #include <regex.h> #include <linux/zalloc.h> -#include "../../perf.h" #include "../../util/perf_regs.h" #include "../../util/debug.h" diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index b0a67eaf2ce8..8a4b717e0a53 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -5,6 +5,7 @@ */ #include "debug.h" +#include "dso.h" #include "symbol.h" #include "map.h" #include "probe-event.h" diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/arch/powerpc/util/unwind-libdw.c index 7a1f05ef2fc0..abf2dbc7f829 100644 --- a/tools/perf/arch/powerpc/util/unwind-libdw.c +++ b/tools/perf/arch/powerpc/util/unwind-libdw.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <elfutils/libdwfl.h> +#include <linux/kernel.h> #include "../../util/unwind-libdw.h" #include "../../util/perf_regs.h" #include "../../util/event.h" diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c index 0fe1be93f375..b0fb70e38960 100644 --- a/tools/perf/arch/s390/util/auxtrace.c +++ b/tools/perf/arch/s390/util/auxtrace.c @@ -8,6 +8,7 @@ #include "../../util/evlist.h" #include "../../util/auxtrace.h" #include "../../util/evsel.h" +#include "../../util/record.h" #define PERF_EVENT_CPUM_SF 0xB0000 /* Event: Basic-sampling */ #define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */ @@ -20,7 +21,7 @@ static void cpumsf_free(struct auxtrace_record *itr) } static size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } @@ -28,7 +29,7 @@ static size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused, static int cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused, struct perf_session *session __maybe_unused, - struct auxtrace_info_event *auxtrace_info __maybe_unused, + struct perf_record_auxtrace_info *auxtrace_info __maybe_unused, size_t priv_size __maybe_unused) { auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF; @@ -43,7 +44,7 @@ cpumsf_reference(struct auxtrace_record *itr __maybe_unused) static int cpumsf_recording_options(struct auxtrace_record *ar __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, struct record_opts *opts) { unsigned int factor = 1; @@ -82,19 +83,19 @@ cpumsf_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused, * auxtrace_record__init is called when perf record * check if the event really need auxtrace */ -struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err) { struct auxtrace_record *aux; - struct perf_evsel *pos; + struct evsel *pos; int diagnose = 0; *err = 0; - if (evlist->nr_entries == 0) + if (evlist->core.nr_entries == 0) return NULL; evlist__for_each_entry(evlist, pos) { - if (pos->attr.config == PERF_EVENT_CPUM_SF_DIAG) { + if (pos->core.attr.config == PERF_EVENT_CPUM_SF_DIAG) { diagnose = 1; break; } diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c index f852f2a77e0a..0fd4e9f49ed0 100644 --- a/tools/perf/arch/s390/util/kvm-stat.c +++ b/tools/perf/arch/s390/util/kvm-stat.c @@ -7,6 +7,7 @@ */ #include <errno.h> +#include <string.h> #include "../../util/kvm-stat.h" #include "../../util/evsel.h" #include <asm/sie.h> @@ -23,7 +24,7 @@ const char *kvm_exit_reason = "icptcode"; const char *kvm_entry_trace = "kvm:kvm_s390_sie_enter"; const char *kvm_exit_trace = "kvm:kvm_s390_sie_exit"; -static void event_icpt_insn_get_key(struct perf_evsel *evsel, +static void event_icpt_insn_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -34,7 +35,7 @@ static void event_icpt_insn_get_key(struct perf_evsel *evsel, key->exit_reasons = sie_icpt_insn_codes; } -static void event_sigp_get_key(struct perf_evsel *evsel, +static void event_sigp_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -42,7 +43,7 @@ static void event_sigp_get_key(struct perf_evsel *evsel, key->exit_reasons = sie_sigp_order_codes; } -static void event_diag_get_key(struct perf_evsel *evsel, +static void event_diag_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -50,7 +51,7 @@ static void event_diag_get_key(struct perf_evsel *evsel, key->exit_reasons = sie_diagnose_codes; } -static void event_icpt_prog_get_key(struct perf_evsel *evsel, +static void event_icpt_prog_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { diff --git a/tools/perf/arch/x86/tests/bp-modify.c b/tools/perf/arch/x86/tests/bp-modify.c index f53e4406709f..adcacf1b6609 100644 --- a/tools/perf/arch/x86/tests/bp-modify.c +++ b/tools/perf/arch/x86/tests/bp-modify.c @@ -7,6 +7,7 @@ #include <unistd.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/ptrace.h> #include <asm/ptrace.h> #include <errno.h> diff --git a/tools/perf/arch/x86/tests/insn-x86.c b/tools/perf/arch/x86/tests/insn-x86.c index c3e5f4ab0d3e..745f29adb14b 100644 --- a/tools/perf/arch/x86/tests/insn-x86.c +++ b/tools/perf/arch/x86/tests/insn-x86.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/types.h> +#include "../../../../arch/x86/include/asm/insn.h" +#include <string.h> #include "debug.h" #include "tests/tests.h" #include "arch-tests.h" -#include "intel-pt-decoder/insn.h" #include "intel-pt-decoder/intel-pt-insn-decoder.h" struct test_data { diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c index 94aa0b673b7f..3b5cc3373821 100644 --- a/tools/perf/arch/x86/tests/intel-cqm.c +++ b/tools/perf/arch/x86/tests/intel-cqm.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "tests/tests.h" -#include "perf.h" #include "cloexec.h" #include "debug.h" #include "evlist.h" @@ -40,8 +39,8 @@ static pid_t spawn(void) */ int test__intel_cqm_count_nmi_context(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct perf_evlist *evlist = NULL; - struct perf_evsel *evsel = NULL; + struct evlist *evlist = NULL; + struct evsel *evsel = NULL; struct perf_event_attr pe; int i, fd[2], flag, ret; size_t mmap_len; @@ -51,7 +50,7 @@ int test__intel_cqm_count_nmi_context(struct test *test __maybe_unused, int subt flag = perf_event_open_cloexec_flag(); - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) { pr_debug("perf_evlist__new failed\n"); return TEST_FAIL; @@ -124,6 +123,6 @@ int test__intel_cqm_count_nmi_context(struct test *test __maybe_unused, int subt kill(pid, SIGKILL); wait(NULL); out: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index 7a7721604b86..eb3635941c2b 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c @@ -1,16 +1,22 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <inttypes.h> +#include <limits.h> +#include <stdbool.h> #include <stdio.h> #include <unistd.h> #include <linux/types.h> #include <sys/prctl.h> +#include <perf/cpumap.h> +#include <perf/evlist.h> +#include "debug.h" #include "parse-events.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "record.h" #include "tsc.h" #include "tests/tests.h" @@ -49,10 +55,10 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe }, .sample_time = true, }; - struct thread_map *threads = NULL; - struct cpu_map *cpus = NULL; - struct perf_evlist *evlist = NULL; - struct perf_evsel *evsel = NULL; + struct perf_thread_map *threads = NULL; + struct perf_cpu_map *cpus = NULL; + struct evlist *evlist = NULL; + struct evsel *evsel = NULL; int err = -1, ret, i; const char *comm1, *comm2; struct perf_tsc_conversion tc; @@ -65,13 +71,13 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe threads = thread_map__new(-1, getpid(), UINT_MAX); CHECK_NOT_NULL__(threads); - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); CHECK_NOT_NULL__(cpus); - evlist = perf_evlist__new(); + evlist = evlist__new(); CHECK_NOT_NULL__(evlist); - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); CHECK__(parse_events(evlist, "cycles:u", NULL)); @@ -79,11 +85,11 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe evsel = perf_evlist__first(evlist); - evsel->attr.comm = 1; - evsel->attr.disabled = 1; - evsel->attr.enable_on_exec = 0; + evsel->core.attr.comm = 1; + evsel->core.attr.disabled = 1; + evsel->core.attr.enable_on_exec = 0; - CHECK__(perf_evlist__open(evlist)); + CHECK__(evlist__open(evlist)); CHECK__(perf_evlist__mmap(evlist, UINT_MAX)); @@ -97,7 +103,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe goto out_err; } - perf_evlist__enable(evlist); + evlist__enable(evlist); comm1 = "Test COMM 1"; CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); @@ -107,7 +113,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe comm2 = "Test COMM 2"; CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); - perf_evlist__disable(evlist); + evlist__disable(evlist); for (i = 0; i < evlist->nr_mmaps; i++) { md = &evlist->mmap[i]; @@ -163,6 +169,6 @@ next_event: err = 0; out_err: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c index 7a11f02d6c6c..6e67cee792b1 100644 --- a/tools/perf/arch/x86/tests/rdpmc.c +++ b/tools/perf/arch/x86/tests/rdpmc.c @@ -6,11 +6,13 @@ #include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> +#include <linux/string.h> #include <linux/types.h> -#include "perf.h" +#include "perf-sys.h" #include "debug.h" #include "tests/tests.h" #include "cloexec.h" +#include "event.h" #include "util.h" #include "arch-tests.h" diff --git a/tools/perf/arch/x86/util/archinsn.c b/tools/perf/arch/x86/util/archinsn.c index 4237bb2e7fa2..9876c7a7ed7c 100644 --- a/tools/perf/arch/x86/util/archinsn.c +++ b/tools/perf/arch/x86/util/archinsn.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" +#include "../../../../arch/x86/include/asm/insn.h" #include "archinsn.h" -#include "util/intel-pt-decoder/insn.h" #include "machine.h" #include "thread.h" #include "symbol.h" diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c index d711268af330..96f4a2c11893 100644 --- a/tools/perf/arch/x86/util/auxtrace.c +++ b/tools/perf/arch/x86/util/auxtrace.c @@ -16,12 +16,12 @@ #include "../../util/evlist.h" static -struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist, +struct auxtrace_record *auxtrace_record__init_intel(struct evlist *evlist, int *err) { struct perf_pmu *intel_pt_pmu; struct perf_pmu *intel_bts_pmu; - struct perf_evsel *evsel; + struct evsel *evsel; bool found_pt = false; bool found_bts = false; @@ -29,9 +29,9 @@ struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist, intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME); evlist__for_each_entry(evlist, evsel) { - if (intel_pt_pmu && evsel->attr.type == intel_pt_pmu->type) + if (intel_pt_pmu && evsel->core.attr.type == intel_pt_pmu->type) found_pt = true; - if (intel_bts_pmu && evsel->attr.type == intel_bts_pmu->type) + if (intel_bts_pmu && evsel->core.attr.type == intel_bts_pmu->type) found_bts = true; } @@ -50,7 +50,7 @@ struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist, return NULL; } -struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err) { char buffer[64]; diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c index af9a9f2600be..662ecf84a421 100644 --- a/tools/perf/arch/x86/util/header.c +++ b/tools/perf/arch/x86/util/header.c @@ -6,6 +6,7 @@ #include <string.h> #include <regex.h> +#include "../../util/debug.h" #include "../../util/header.h" static inline void diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index ec5c1bb84095..d263430c045f 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -12,14 +12,17 @@ #include <linux/zalloc.h> #include "../../util/cpumap.h" +#include "../../util/event.h" #include "../../util/evsel.h" #include "../../util/evlist.h" #include "../../util/session.h" #include "../../util/pmu.h" #include "../../util/debug.h" +#include "../../util/record.h" #include "../../util/tsc.h" #include "../../util/auxtrace.h" #include "../../util/intel-bts.h" +#include "../../util/util.h" #define KiB(x) ((x) * 1024) #define MiB(x) ((x) * 1024 * 1024) @@ -35,7 +38,7 @@ struct intel_bts_snapshot_ref { struct intel_bts_recording { struct auxtrace_record itr; struct perf_pmu *intel_bts_pmu; - struct perf_evlist *evlist; + struct evlist *evlist; bool snapshot_mode; size_t snapshot_size; int snapshot_ref_cnt; @@ -50,14 +53,14 @@ struct branch { static size_t intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return INTEL_BTS_AUXTRACE_PRIV_SIZE; } static int intel_bts_info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size) { struct intel_bts_recording *btsr = @@ -99,27 +102,27 @@ static int intel_bts_info_fill(struct auxtrace_record *itr, } static int intel_bts_recording_options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts) { struct intel_bts_recording *btsr = container_of(itr, struct intel_bts_recording, itr); struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; - struct perf_evsel *evsel, *intel_bts_evsel = NULL; - const struct cpu_map *cpus = evlist->cpus; - bool privileged = geteuid() == 0 || perf_event_paranoid() < 0; + struct evsel *evsel, *intel_bts_evsel = NULL; + const struct perf_cpu_map *cpus = evlist->core.cpus; + bool privileged = perf_event_paranoid_check(-1); btsr->evlist = evlist; btsr->snapshot_mode = opts->auxtrace_snapshot_mode; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == intel_bts_pmu->type) { + if (evsel->core.attr.type == intel_bts_pmu->type) { if (intel_bts_evsel) { pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n"); return -EINVAL; } - evsel->attr.freq = 0; - evsel->attr.sample_period = 1; + evsel->core.attr.freq = 0; + evsel->core.attr.sample_period = 1; intel_bts_evsel = evsel; opts->full_auxtrace = true; } @@ -133,7 +136,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, if (!opts->full_auxtrace) return 0; - if (opts->full_auxtrace && !cpu_map__empty(cpus)) { + if (opts->full_auxtrace && !perf_cpu_map__empty(cpus)) { pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n"); return -EINVAL; } @@ -214,13 +217,13 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, we need the CPU on the * AUX event. */ - if (!cpu_map__empty(cpus)) + if (!perf_cpu_map__empty(cpus)) perf_evsel__set_sample_bit(intel_bts_evsel, CPU); } /* Add dummy event to keep tracking */ if (opts->full_auxtrace) { - struct perf_evsel *tracking_evsel; + struct evsel *tracking_evsel; int err; err = parse_events(evlist, "dummy:u", NULL); @@ -231,8 +234,8 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, perf_evlist__set_tracking_event(evlist, tracking_evsel); - tracking_evsel->attr.freq = 0; - tracking_evsel->attr.sample_period = 1; + tracking_evsel->core.attr.freq = 0; + tracking_evsel->core.attr.sample_period = 1; } return 0; @@ -313,11 +316,11 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr) { struct intel_bts_recording *btsr = container_of(itr, struct intel_bts_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(btsr->evlist, evsel) { - if (evsel->attr.type == btsr->intel_bts_pmu->type) - return perf_evsel__disable(evsel); + if (evsel->core.attr.type == btsr->intel_bts_pmu->type) + return evsel__disable(evsel); } return -EINVAL; } @@ -326,11 +329,11 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr) { struct intel_bts_recording *btsr = container_of(itr, struct intel_bts_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(btsr->evlist, evsel) { - if (evsel->attr.type == btsr->intel_bts_pmu->type) - return perf_evsel__enable(evsel); + if (evsel->core.attr.type == btsr->intel_bts_pmu->type) + return evsel__enable(evsel); } return -EINVAL; } @@ -408,10 +411,10 @@ static int intel_bts_read_finish(struct auxtrace_record *itr, int idx) { struct intel_bts_recording *btsr = container_of(itr, struct intel_bts_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(btsr->evlist, evsel) { - if (evsel->attr.type == btsr->intel_bts_pmu->type) + if (evsel->core.attr.type == btsr->intel_bts_pmu->type) return perf_evlist__enable_event_idx(btsr->evlist, evsel, idx); } diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 609088c01e3a..cb7cf16af79c 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -13,7 +13,6 @@ #include <linux/zalloc.h> #include <cpuid.h> -#include "../../perf.h" #include "../../util/session.h" #include "../../util/event.h" #include "../../util/evlist.h" @@ -24,7 +23,10 @@ #include "../../util/pmu.h" #include "../../util/debug.h" #include "../../util/auxtrace.h" +#include "../../util/record.h" +#include "../../util/target.h" #include "../../util/tsc.h" +#include "../../util/util.h" #include "../../util/intel-pt.h" #define KiB(x) ((x) * 1024) @@ -44,7 +46,7 @@ struct intel_pt_recording { struct auxtrace_record itr; struct perf_pmu *intel_pt_pmu; int have_sched_switch; - struct perf_evlist *evlist; + struct evlist *evlist; bool snapshot_mode; bool snapshot_init_done; size_t snapshot_size; @@ -110,9 +112,9 @@ static u64 intel_pt_masked_bits(u64 mask, u64 bits) } static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str, - struct perf_evlist *evlist, u64 *res) + struct evlist *evlist, u64 *res) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 mask; *res = 0; @@ -122,8 +124,8 @@ static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str, return -EINVAL; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == intel_pt_pmu->type) { - *res = intel_pt_masked_bits(mask, evsel->attr.config); + if (evsel->core.attr.type == intel_pt_pmu->type) { + *res = intel_pt_masked_bits(mask, evsel->core.attr.config); return 0; } } @@ -132,7 +134,7 @@ static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str, } static size_t intel_pt_psb_period(struct perf_pmu *intel_pt_pmu, - struct perf_evlist *evlist) + struct evlist *evlist) { u64 val; int err, topa_multiple_entries; @@ -268,13 +270,13 @@ intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu) return attr; } -static const char *intel_pt_find_filter(struct perf_evlist *evlist, +static const char *intel_pt_find_filter(struct evlist *evlist, struct perf_pmu *intel_pt_pmu) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == intel_pt_pmu->type) + if (evsel->core.attr.type == intel_pt_pmu->type) return evsel->filter; } @@ -289,7 +291,7 @@ static size_t intel_pt_filter_bytes(const char *filter) } static size_t -intel_pt_info_priv_size(struct auxtrace_record *itr, struct perf_evlist *evlist) +intel_pt_info_priv_size(struct auxtrace_record *itr, struct evlist *evlist) { struct intel_pt_recording *ptr = container_of(itr, struct intel_pt_recording, itr); @@ -312,7 +314,7 @@ static void intel_pt_tsc_ctc_ratio(u32 *n, u32 *d) static int intel_pt_info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size) { struct intel_pt_recording *ptr = @@ -326,7 +328,7 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, unsigned long max_non_turbo_ratio; size_t filter_str_len; const char *filter; - u64 *info; + __u64 *info; int err; if (priv_size != ptr->priv_size) @@ -365,7 +367,7 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, ui__warning("Intel Processor Trace: TSC not available\n"); } - per_cpu_mmaps = !cpu_map__empty(session->evlist->cpus); + per_cpu_mmaps = !perf_cpu_map__empty(session->evlist->core.cpus); auxtrace_info->type = PERF_AUXTRACE_INTEL_PT; auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type; @@ -398,10 +400,10 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, return 0; } -static int intel_pt_track_switches(struct perf_evlist *evlist) +static int intel_pt_track_switches(struct evlist *evlist) { const char *sched_switch = "sched:sched_switch"; - struct perf_evsel *evsel; + struct evsel *evsel; int err; if (!perf_evlist__can_select_event(evlist, sched_switch)) @@ -513,7 +515,7 @@ out_err: } static int intel_pt_validate_config(struct perf_pmu *intel_pt_pmu, - struct perf_evsel *evsel) + struct evsel *evsel) { int err; char c; @@ -526,39 +528,59 @@ static int intel_pt_validate_config(struct perf_pmu *intel_pt_pmu, * sets pt=0, which avoids senseless kernel errors. */ if (perf_pmu__scan_file(intel_pt_pmu, "format/pt", "%c", &c) == 1 && - !(evsel->attr.config & 1)) { + !(evsel->core.attr.config & 1)) { pr_warning("pt=0 doesn't make sense, forcing pt=1\n"); - evsel->attr.config |= 1; + evsel->core.attr.config |= 1; } err = intel_pt_val_config_term(intel_pt_pmu, "caps/cycle_thresholds", "cyc_thresh", "caps/psb_cyc", - evsel->attr.config); + evsel->core.attr.config); if (err) return err; err = intel_pt_val_config_term(intel_pt_pmu, "caps/mtc_periods", "mtc_period", "caps/mtc", - evsel->attr.config); + evsel->core.attr.config); if (err) return err; return intel_pt_val_config_term(intel_pt_pmu, "caps/psb_periods", "psb_period", "caps/psb_cyc", - evsel->attr.config); + evsel->core.attr.config); +} + +/* + * Currently, there is not enough information to disambiguate different PEBS + * events, so only allow one. + */ +static bool intel_pt_too_many_aux_output(struct evlist *evlist) +{ + struct evsel *evsel; + int aux_output_cnt = 0; + + evlist__for_each_entry(evlist, evsel) + aux_output_cnt += !!evsel->core.attr.aux_output; + + if (aux_output_cnt > 1) { + pr_err(INTEL_PT_PMU_NAME " supports at most one event with aux-output\n"); + return true; + } + + return false; } static int intel_pt_recording_options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts) { struct intel_pt_recording *ptr = container_of(itr, struct intel_pt_recording, itr); struct perf_pmu *intel_pt_pmu = ptr->intel_pt_pmu; bool have_timing_info, need_immediate = false; - struct perf_evsel *evsel, *intel_pt_evsel = NULL; - const struct cpu_map *cpus = evlist->cpus; - bool privileged = geteuid() == 0 || perf_event_paranoid() < 0; + struct evsel *evsel, *intel_pt_evsel = NULL; + const struct perf_cpu_map *cpus = evlist->core.cpus; + bool privileged = perf_event_paranoid_check(-1); u64 tsc_bit; int err; @@ -566,13 +588,13 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, ptr->snapshot_mode = opts->auxtrace_snapshot_mode; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == intel_pt_pmu->type) { + if (evsel->core.attr.type == intel_pt_pmu->type) { if (intel_pt_evsel) { pr_err("There may be only one " INTEL_PT_PMU_NAME " event\n"); return -EINVAL; } - evsel->attr.freq = 0; - evsel->attr.sample_period = 1; + evsel->core.attr.freq = 0; + evsel->core.attr.sample_period = 1; intel_pt_evsel = evsel; opts->full_auxtrace = true; } @@ -588,6 +610,9 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, return -EINVAL; } + if (intel_pt_too_many_aux_output(evlist)) + return -EINVAL; + if (!opts->full_auxtrace) return 0; @@ -670,7 +695,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, intel_pt_parse_terms(&intel_pt_pmu->format, "tsc", &tsc_bit); - if (opts->full_auxtrace && (intel_pt_evsel->attr.config & tsc_bit)) + if (opts->full_auxtrace && (intel_pt_evsel->core.attr.config & tsc_bit)) have_timing_info = true; else have_timing_info = false; @@ -679,13 +704,13 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * Per-cpu recording needs sched_switch events to distinguish different * threads. */ - if (have_timing_info && !cpu_map__empty(cpus)) { + if (have_timing_info && !perf_cpu_map__empty(cpus)) { if (perf_can_record_switch_events()) { bool cpu_wide = !target__none(&opts->target) && !target__has_task(&opts->target); if (!cpu_wide && perf_can_record_cpu_wide()) { - struct perf_evsel *switch_evsel; + struct evsel *switch_evsel; err = parse_events(evlist, "dummy:u", NULL); if (err) @@ -693,9 +718,9 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, switch_evsel = perf_evlist__last(evlist); - switch_evsel->attr.freq = 0; - switch_evsel->attr.sample_period = 1; - switch_evsel->attr.context_switch = 1; + switch_evsel->core.attr.freq = 0; + switch_evsel->core.attr.sample_period = 1; + switch_evsel->core.attr.context_switch = 1; switch_evsel->system_wide = true; switch_evsel->no_aux_samples = true; @@ -737,13 +762,13 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, we need the CPU on the * AUX event. */ - if (!cpu_map__empty(cpus)) + if (!perf_cpu_map__empty(cpus)) perf_evsel__set_sample_bit(intel_pt_evsel, CPU); } /* Add dummy event to keep tracking */ if (opts->full_auxtrace) { - struct perf_evsel *tracking_evsel; + struct evsel *tracking_evsel; err = parse_events(evlist, "dummy:u", NULL); if (err) @@ -753,15 +778,15 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, perf_evlist__set_tracking_event(evlist, tracking_evsel); - tracking_evsel->attr.freq = 0; - tracking_evsel->attr.sample_period = 1; + tracking_evsel->core.attr.freq = 0; + tracking_evsel->core.attr.sample_period = 1; tracking_evsel->no_aux_samples = true; if (need_immediate) tracking_evsel->immediate = true; /* In per-cpu case, always need the time of mmap events etc */ - if (!cpu_map__empty(cpus)) { + if (!perf_cpu_map__empty(cpus)) { perf_evsel__set_sample_bit(tracking_evsel, TIME); /* And the CPU for switch events */ perf_evsel__set_sample_bit(tracking_evsel, CPU); @@ -773,7 +798,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * Warn the user when we do not have enough information to decode i.e. * per-cpu with no sched_switch (except workload-only). */ - if (!ptr->have_sched_switch && !cpu_map__empty(cpus) && + if (!ptr->have_sched_switch && !perf_cpu_map__empty(cpus) && !target__none(&opts->target)) ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n"); @@ -784,11 +809,11 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr) { struct intel_pt_recording *ptr = container_of(itr, struct intel_pt_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(ptr->evlist, evsel) { - if (evsel->attr.type == ptr->intel_pt_pmu->type) - return perf_evsel__disable(evsel); + if (evsel->core.attr.type == ptr->intel_pt_pmu->type) + return evsel__disable(evsel); } return -EINVAL; } @@ -797,11 +822,11 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr) { struct intel_pt_recording *ptr = container_of(itr, struct intel_pt_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(ptr->evlist, evsel) { - if (evsel->attr.type == ptr->intel_pt_pmu->type) - return perf_evsel__enable(evsel); + if (evsel->core.attr.type == ptr->intel_pt_pmu->type) + return evsel__enable(evsel); } return -EINVAL; } @@ -1070,10 +1095,10 @@ static int intel_pt_read_finish(struct auxtrace_record *itr, int idx) { struct intel_pt_recording *ptr = container_of(itr, struct intel_pt_recording, itr); - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(ptr->evlist, evsel) { - if (evsel->attr.type == ptr->intel_pt_pmu->type) + if (evsel->core.attr.type == ptr->intel_pt_pmu->type) return perf_evlist__enable_event_idx(ptr->evlist, evsel, idx); } diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c index 865a9762f22e..c0775c39227f 100644 --- a/tools/perf/arch/x86/util/kvm-stat.c +++ b/tools/perf/arch/x86/util/kvm-stat.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> -#include "../../util/kvm-stat.h" -#include "../../util/evsel.h" +#include <string.h> +#include "../../../util/kvm-stat.h" +#include "../../../util/evsel.h" #include <asm/svm.h> #include <asm/vmx.h> #include <asm/kvm.h> @@ -27,7 +28,7 @@ const char *kvm_exit_trace = "kvm:kvm_exit"; * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). */ -static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, +static void mmio_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { key->key = perf_evsel__intval(evsel, sample, "gpa"); @@ -38,7 +39,7 @@ static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sam #define KVM_TRACE_MMIO_READ 1 #define KVM_TRACE_MMIO_WRITE 2 -static bool mmio_event_begin(struct perf_evsel *evsel, +static bool mmio_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { /* MMIO read begin event in kernel. */ @@ -55,7 +56,7 @@ static bool mmio_event_begin(struct perf_evsel *evsel, return false; } -static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, +static bool mmio_event_end(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { /* MMIO write end event in kernel. */ @@ -89,7 +90,7 @@ static struct kvm_events_ops mmio_events = { }; /* The time of emulation pio access is from kvm_pio to kvm_entry. */ -static void ioport_event_get_key(struct perf_evsel *evsel, +static void ioport_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -97,7 +98,7 @@ static void ioport_event_get_key(struct perf_evsel *evsel, key->info = perf_evsel__intval(evsel, sample, "rw"); } -static bool ioport_event_begin(struct perf_evsel *evsel, +static bool ioport_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -109,7 +110,7 @@ static bool ioport_event_begin(struct perf_evsel *evsel, return false; } -static bool ioport_event_end(struct perf_evsel *evsel, +static bool ioport_event_end(struct evsel *evsel, struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) { diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c index 0d7b77ff0ae6..c218b83e063b 100644 --- a/tools/perf/arch/x86/util/perf_regs.c +++ b/tools/perf/arch/x86/util/perf_regs.c @@ -2,11 +2,13 @@ #include <errno.h> #include <string.h> #include <regex.h> +#include <linux/kernel.h> #include <linux/zalloc.h> -#include "../../perf.h" +#include "../../perf-sys.h" #include "../../util/perf_regs.h" #include "../../util/debug.h" +#include "../../util/event.h" const struct sample_reg sample_reg_masks[] = { SMPL_REG(AX, PERF_REG_X86_AX), diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 950539f9a4f7..c5197a15119b 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c @@ -5,10 +5,10 @@ #include <linux/stddef.h> #include <linux/perf_event.h> -#include "../../perf.h" #include <linux/types.h> -#include "../../util/debug.h" -#include "../../util/tsc.h" +#include <asm/barrier.h> +#include "../../../util/debug.h" +#include "../../../util/tsc.h" int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, struct perf_tsc_conversion *tc) @@ -57,7 +57,7 @@ int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, .time_conv = { .header = { .type = PERF_RECORD_TIME_CONV, - .size = sizeof(struct time_conv_event), + .size = sizeof(struct perf_record_time_conv), }, }, }; diff --git a/tools/perf/bench/epoll-ctl.c b/tools/perf/bench/epoll-ctl.c index 2af067859966..d1caa4a0a12a 100644 --- a/tools/perf/bench/epoll-ctl.c +++ b/tools/perf/bench/epoll-ctl.c @@ -14,12 +14,14 @@ #include <inttypes.h> #include <signal.h> #include <stdlib.h> +#include <unistd.h> #include <linux/compiler.h> #include <linux/kernel.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/epoll.h> #include <sys/eventfd.h> +#include <perf/cpumap.h> #include "../util/stat.h" #include <subcmd/parse-options.h> @@ -219,7 +221,7 @@ static void init_fdmaps(struct worker *w, int pct) } } -static int do_threads(struct worker *worker, struct cpu_map *cpu) +static int do_threads(struct worker *worker, struct perf_cpu_map *cpu) { pthread_attr_t thread_attr, *attrp = NULL; cpu_set_t cpuset; @@ -301,7 +303,7 @@ int bench_epoll_ctl(int argc, const char **argv) int j, ret = 0; struct sigaction act; struct worker *worker = NULL; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; struct rlimit rl, prevrl; unsigned int i; @@ -315,7 +317,7 @@ int bench_epoll_ctl(int argc, const char **argv) act.sa_sigaction = toggle_done; sigaction(SIGINT, &act, NULL); - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) goto errmem; diff --git a/tools/perf/bench/epoll-wait.c b/tools/perf/bench/epoll-wait.c index fe85448abd45..f6b4472847d2 100644 --- a/tools/perf/bench/epoll-wait.c +++ b/tools/perf/bench/epoll-wait.c @@ -63,6 +63,7 @@ /* For the CLR_() macros */ #include <string.h> #include <pthread.h> +#include <unistd.h> #include <errno.h> #include <inttypes.h> @@ -75,6 +76,7 @@ #include <sys/epoll.h> #include <sys/eventfd.h> #include <sys/types.h> +#include <perf/cpumap.h> #include "../util/stat.h" #include <subcmd/parse-options.h> @@ -288,7 +290,7 @@ static void print_summary(void) (int) runtime.tv_sec); } -static int do_threads(struct worker *worker, struct cpu_map *cpu) +static int do_threads(struct worker *worker, struct perf_cpu_map *cpu) { pthread_attr_t thread_attr, *attrp = NULL; cpu_set_t cpuset; @@ -415,7 +417,7 @@ int bench_epoll_wait(int argc, const char **argv) struct sigaction act; unsigned int i; struct worker *worker = NULL; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; pthread_t wthread; struct rlimit rl, prevrl; @@ -429,7 +431,7 @@ int bench_epoll_wait(int argc, const char **argv) act.sa_sigaction = toggle_done; sigaction(SIGINT, &act, NULL); - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) goto errmem; diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index a80797763e1f..80e138904c66 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <sys/time.h> +#include <perf/cpumap.h> #include "../util/stat.h" #include <subcmd/parse-options.h> @@ -124,7 +125,7 @@ int bench_futex_hash(int argc, const char **argv) unsigned int i; pthread_attr_t thread_attr; struct worker *worker = NULL; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; argc = parse_options(argc, argv, options, bench_futex_hash_usage, 0); if (argc) { @@ -132,7 +133,7 @@ int bench_futex_hash(int argc, const char **argv) exit(EXIT_FAILURE); } - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) goto errmem; diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index d02330a69745..c5d6d0abbaa9 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <errno.h> +#include <perf/cpumap.h> #include "bench.h" #include "futex.h" #include "cpumap.h" @@ -116,7 +117,7 @@ static void *workerfn(void *arg) } static void create_threads(struct worker *w, pthread_attr_t thread_attr, - struct cpu_map *cpu) + struct perf_cpu_map *cpu) { cpu_set_t cpuset; unsigned int i; @@ -150,13 +151,13 @@ int bench_futex_lock_pi(int argc, const char **argv) unsigned int i; struct sigaction act; pthread_attr_t thread_attr; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; argc = parse_options(argc, argv, options, bench_futex_lock_pi_usage, 0); if (argc) goto err; - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) err(EXIT_FAILURE, "calloc"); diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index fc692efa0c05..75d3418c1a88 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/time64.h> #include <errno.h> +#include <perf/cpumap.h> #include "bench.h" #include "futex.h" #include "cpumap.h" @@ -84,7 +85,7 @@ static void *workerfn(void *arg __maybe_unused) } static void block_threads(pthread_t *w, - pthread_attr_t thread_attr, struct cpu_map *cpu) + pthread_attr_t thread_attr, struct perf_cpu_map *cpu) { cpu_set_t cpuset; unsigned int i; @@ -117,13 +118,13 @@ int bench_futex_requeue(int argc, const char **argv) unsigned int i, j; struct sigaction act; pthread_attr_t thread_attr; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; argc = parse_options(argc, argv, options, bench_futex_requeue_usage, 0); if (argc) goto err; - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) err(EXIT_FAILURE, "cpu_map__new"); diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 69d8fdc87315..163fe16c275a 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -138,7 +138,7 @@ static void *blocked_workerfn(void *arg __maybe_unused) } static void block_threads(pthread_t *w, pthread_attr_t thread_attr, - struct cpu_map *cpu) + struct perf_cpu_map *cpu) { cpu_set_t cpuset; unsigned int i; @@ -224,7 +224,7 @@ int bench_futex_wake_parallel(int argc, const char **argv) struct sigaction act; pthread_attr_t thread_attr; struct thread_data *waking_worker; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; argc = parse_options(argc, argv, options, bench_futex_wake_parallel_usage, 0); @@ -237,7 +237,7 @@ int bench_futex_wake_parallel(int argc, const char **argv) act.sa_sigaction = toggle_done; sigaction(SIGINT, &act, NULL); - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) err(EXIT_FAILURE, "calloc"); diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index e8181ad7d088..77dcdc13618a 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/time64.h> #include <errno.h> +#include <perf/cpumap.h> #include "bench.h" #include "futex.h" #include "cpumap.h" @@ -90,7 +91,7 @@ static void print_summary(void) } static void block_threads(pthread_t *w, - pthread_attr_t thread_attr, struct cpu_map *cpu) + pthread_attr_t thread_attr, struct perf_cpu_map *cpu) { cpu_set_t cpuset; unsigned int i; @@ -123,7 +124,7 @@ int bench_futex_wake(int argc, const char **argv) unsigned int i, j; struct sigaction act; pthread_attr_t thread_attr; - struct cpu_map *cpu; + struct perf_cpu_map *cpu; argc = parse_options(argc, argv, options, bench_futex_wake_usage, 0); if (argc) { @@ -131,7 +132,7 @@ int bench_futex_wake(int argc, const char **argv) exit(EXIT_FAILURE); } - cpu = cpu_map__new(NULL); + cpu = perf_cpu_map__new(NULL); if (!cpu) err(EXIT_FAILURE, "calloc"); diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 64dc994c72ea..9235b76501be 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -8,7 +8,7 @@ */ #include "debug.h" -#include "../perf.h" +#include "../perf-sys.h" #include <subcmd/parse-options.h> #include "../util/header.h" #include "../util/cloexec.h" @@ -20,6 +20,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <sys/time.h> #include <errno.h> #include <linux/time64.h> diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 513cb2f2fa32..62b8ef4bcb1f 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -9,7 +9,6 @@ /* For the CLR_() macros */ #include <pthread.h> -#include "../perf.h" #include "../builtin.h" #include <subcmd/parse-options.h> #include "../util/cloexec.h" diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index f9d7641ae833..c63eb9a46346 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c @@ -10,7 +10,6 @@ * */ -#include "../perf.h" #include "../util/util.h" #include <subcmd/parse-options.h> #include "../builtin.h" diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 0591be008f2a..35b07f197d48 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c @@ -9,7 +9,6 @@ * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> */ -#include "../perf.h" #include "../util/util.h" #include <subcmd/parse-options.h> #include "../builtin.h" diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e0aa14faf2b5..4e4d2e76232e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -24,15 +24,17 @@ #include "util/event.h" #include <subcmd/parse-options.h> #include "util/parse-events.h" -#include "util/thread.h" #include "util/sort.h" #include "util/hist.h" +#include "util/dso.h" #include "util/map.h" #include "util/session.h" #include "util/tool.h" #include "util/data.h" #include "arch/common.h" #include "util/block-range.h" +#include "util/map_symbol.h" +#include "util/branch.h" #include <dlfcn.h> #include <errno.h> @@ -156,7 +158,7 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, struct hist_entry *he = iter->he; struct branch_info *bi; struct perf_sample *sample = iter->sample; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; int err; bi = he->branch_info; @@ -171,7 +173,7 @@ out: return err; } -static int process_branch_callback(struct perf_evsel *evsel, +static int process_branch_callback(struct evsel *evsel, struct perf_sample *sample, struct addr_location *al __maybe_unused, struct perf_annotate *ann, @@ -208,7 +210,7 @@ static bool has_annotation(struct perf_annotate *ann) return ui__has_annotation() || ann->use_stdio2; } -static int perf_evsel__add_sample(struct perf_evsel *evsel, +static int perf_evsel__add_sample(struct evsel *evsel, struct perf_sample *sample, struct addr_location *al, struct perf_annotate *ann, @@ -257,7 +259,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); @@ -293,7 +295,7 @@ static int process_feature_event(struct perf_session *session, } static int hist_entry__tty_annotate(struct hist_entry *he, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_annotate *ann) { if (!ann->use_stdio2) @@ -303,7 +305,7 @@ static int hist_entry__tty_annotate(struct hist_entry *he, } static void hists__find_annotations(struct hists *hists, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_annotate *ann) { struct rb_node *nd = rb_first_cached(&hists->entries), *next; @@ -333,7 +335,7 @@ find_next: if (use_browser == 2) { int ret; int (*annotate)(struct hist_entry *he, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt); annotate = dlsym(perf_gtk_handle, @@ -387,7 +389,7 @@ static int __cmd_annotate(struct perf_annotate *ann) { int ret; struct perf_session *session = ann->session; - struct perf_evsel *pos; + struct evsel *pos; u64 total_nr_samples; if (ann->cpu_list) { diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index b8e7c38ef221..c06fe21c8613 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -16,7 +16,6 @@ * futex ... Futex performance * epoll ... Event poll performance */ -#include "perf.h" #include <subcmd/parse-options.h> #include "builtin.h" #include "bench/bench.h" diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 10457b10e568..1a69eb565dc0 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -14,18 +14,20 @@ #include <errno.h> #include <unistd.h> #include "builtin.h" -#include "perf.h" #include "namespaces.h" -#include "util/cache.h" #include "util/debug.h" #include "util/header.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/strlist.h" #include "util/build-id.h" #include "util/session.h" +#include "util/dso.h" #include "util/symbol.h" #include "util/time-utils.h" +#include "util/util.h" #include "util/probe-file.h" +#include <linux/string.h> static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid) { diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index f403e19488b5..5a0d8b378cb5 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0 /* * builtin-buildid-list.c * @@ -11,8 +10,9 @@ #include "builtin.h" #include "perf.h" #include "util/build-id.h" -#include "util/cache.h" #include "util/debug.h" +#include "util/dso.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/session.h" #include "util/symbol.h" diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index e3776f5c2e01..b09b12e0976b 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -20,12 +20,15 @@ #include <sys/param.h> #include "debug.h" #include "builtin.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> +#include "map_symbol.h" #include "mem-events.h" #include "session.h" #include "hist.h" #include "sort.h" #include "tool.h" +#include "cacheline.h" #include "data.h" #include "event.h" #include "evlist.h" @@ -34,6 +37,9 @@ #include "thread.h" #include "mem2node.h" #include "symbol.h" +#include "ui/ui.h" +#include "ui/progress.h" +#include "../perf.h" struct c2c_hists { struct hists hists; @@ -248,7 +254,7 @@ static void compute_stats(struct c2c_hist_entry *c2c_he, static int process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct c2c_hists *c2c_hists = &c2c.hists; @@ -1106,7 +1112,7 @@ node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, break; case 1: { - int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt); + int num = bitmap_weight(set, c2c.cpus_cnt); struct c2c_stats *stats = &c2c_he->node_stats[node]; ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num); @@ -2027,7 +2033,7 @@ static int setup_nodes(struct perf_session *session) c2c.node_info = 2; c2c.nodes_cnt = session->header.env.nr_numa_nodes; - c2c.cpus_cnt = session->header.env.nr_cpus_online; + c2c.cpus_cnt = session->header.env.nr_cpus_avail; n = session->header.env.numa_nodes; if (!n) @@ -2049,7 +2055,7 @@ static int setup_nodes(struct perf_session *session) c2c.cpu2node = cpu2node; for (node = 0; node < c2c.nodes_cnt; node++) { - struct cpu_map *map = n[node].map; + struct perf_cpu_map *map = n[node].map; unsigned long *set; set = bitmap_alloc(c2c.cpus_cnt); @@ -2059,7 +2065,7 @@ static int setup_nodes(struct perf_session *session) nodes[node] = set; /* empty node, skip */ - if (cpu_map__empty(map)) + if (perf_cpu_map__empty(map)) continue; for (cpu = 0; cpu < map->nr; cpu++) { @@ -2236,8 +2242,8 @@ static void print_pareto(FILE *out) static void print_c2c_info(FILE *out, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; bool first = true; fprintf(out, "=================================================\n"); @@ -2567,7 +2573,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) return parse_callchain_report_opt(arg); } -static int setup_callchain(struct perf_evlist *evlist) +static int setup_callchain(struct evlist *evlist) { u64 sample_type = perf_evlist__combined_sample_type(evlist); enum perf_call_graph_mode mode = CALLCHAIN_NONE; diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 6c1284c87aaa..42d8157e047a 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -7,14 +7,13 @@ */ #include "builtin.h" -#include "perf.h" - #include "util/cache.h" #include <subcmd/parse-options.h> #include "util/util.h" #include "util/debug.h" #include "util/config.h" #include <linux/string.h> +#include <stdio.h> #include <stdlib.h> static bool use_system_config, use_user_config; diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index dde25d4ca56d..ca2fb44874e4 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> +#include <stdio.h> +#include <string.h> #include "builtin.h" #include "perf.h" #include "debug.h" diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index f6f5dd15bea7..827e4800d862 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -6,6 +6,7 @@ * DSOs and symbol information, sort them and produce a diff. */ #include "builtin.h" +#include "perf.h" #include "util/debug.h" #include "util/event.h" @@ -15,6 +16,7 @@ #include "util/session.h" #include "util/tool.h" #include "util/sort.h" +#include "util/srcline.h" #include "util/symbol.h" #include "util/data.h" #include "util/config.h" @@ -22,6 +24,8 @@ #include "util/annotate.h" #include "util/map.h" #include <linux/zalloc.h> +#include <subcmd/pager.h> +#include <subcmd/parse-options.h> #include <errno.h> #include <inttypes.h> @@ -376,7 +380,7 @@ struct hist_entry_ops block_hist_ops = { static int diff__process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool); @@ -448,10 +452,10 @@ static struct perf_diff pdiff = { }, }; -static struct perf_evsel *evsel_match(struct perf_evsel *evsel, - struct perf_evlist *evlist) +static struct evsel *evsel_match(struct evsel *evsel, + struct evlist *evlist) { - struct perf_evsel *e; + struct evsel *e; evlist__for_each_entry(evlist, e) { if (perf_evsel__match2(evsel, e)) @@ -461,9 +465,9 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, return NULL; } -static void perf_evlist__collapse_resort(struct perf_evlist *evlist) +static void perf_evlist__collapse_resort(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); @@ -1009,8 +1013,8 @@ static void data__fprintf(void) static void data_process(void) { - struct perf_evlist *evlist_base = data__files[0].session->evlist; - struct perf_evsel *evsel_base; + struct evlist *evlist_base = data__files[0].session->evlist; + struct evsel *evsel_base; bool first = true; evlist__for_each_entry(evlist_base, evsel_base) { @@ -1019,8 +1023,8 @@ static void data_process(void) int i; data__for_each_file_new(i, d) { - struct perf_evlist *evlist = d->session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = d->session->evlist; + struct evsel *evsel; struct hists *hists; evsel = evsel_match(evsel_base, evlist); diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 6e4f63b0da4a..238fa3876805 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -21,7 +21,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) { struct perf_session *session; - struct perf_evsel *pos; + struct evsel *pos; struct perf_data data = { .path = file_name, .mode = PERF_DATA_MODE_READ, @@ -36,7 +36,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details evlist__for_each_entry(session->evlist, pos) { perf_evsel__fprintf(pos, details, stdout); - if (pos->attr.type == PERF_TYPE_TRACEPOINT) + if (pos->core.attr.type == PERF_TYPE_TRACEPOINT) has_tracepoint = true; } diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 019312810405..d5adc417a4ca 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -6,28 +6,31 @@ */ #include "builtin.h" -#include "perf.h" #include <errno.h> #include <unistd.h> #include <signal.h> +#include <stdlib.h> #include <fcntl.h> #include <poll.h> +#include <linux/capability.h> +#include <linux/string.h> #include "debug.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include <api/fs/tracing_path.h> #include "evlist.h" #include "target.h" #include "cpumap.h" #include "thread_map.h" +#include "util/cap.h" #include "util/config.h" - #define DEFAULT_TRACER "function_graph" struct perf_ftrace { - struct perf_evlist *evlist; + struct evlist *evlist; struct target target; const char *tracer; struct list_head filters; @@ -156,16 +159,16 @@ static int set_tracing_pid(struct perf_ftrace *ftrace) if (target__has_cpu(&ftrace->target)) return 0; - for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) { + for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) { scnprintf(buf, sizeof(buf), "%d", - ftrace->evlist->threads->map[i]); + ftrace->evlist->core.threads->map[i]); if (append_tracing_file("set_ftrace_pid", buf) < 0) return -1; } return 0; } -static int set_tracing_cpumask(struct cpu_map *cpumap) +static int set_tracing_cpumask(struct perf_cpu_map *cpumap) { char *cpumask; size_t mask_size; @@ -192,7 +195,7 @@ static int set_tracing_cpumask(struct cpu_map *cpumap) static int set_tracing_cpu(struct perf_ftrace *ftrace) { - struct cpu_map *cpumap = ftrace->evlist->cpus; + struct perf_cpu_map *cpumap = ftrace->evlist->core.cpus; if (!target__has_cpu(&ftrace->target)) return 0; @@ -202,11 +205,11 @@ static int set_tracing_cpu(struct perf_ftrace *ftrace) static int reset_tracing_cpu(void) { - struct cpu_map *cpumap = cpu_map__new(NULL); + struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL); int ret; ret = set_tracing_cpumask(cpumap); - cpu_map__put(cpumap); + perf_cpu_map__put(cpumap); return ret; } @@ -281,8 +284,14 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) .events = POLLIN, }; - if (geteuid() != 0) { - pr_err("ftrace only works for root!\n"); + if (!perf_cap__capable(CAP_SYS_ADMIN)) { + pr_err("ftrace only works for %s!\n", +#ifdef HAVE_LIBCAP_SUPPORT + "users with the SYS_ADMIN capability" +#else + "root" +#endif + ); return -1; } @@ -495,7 +504,7 @@ int cmd_ftrace(int argc, const char **argv) goto out_delete_filters; } - ftrace.evlist = perf_evlist__new(); + ftrace.evlist = evlist__new(); if (ftrace.evlist == NULL) { ret = -ENOMEM; goto out_delete_filters; @@ -508,7 +517,7 @@ int cmd_ftrace(int argc, const char **argv) ret = __cmd_ftrace(&ftrace, argc, argv); out_delete_evlist: - perf_evlist__delete(ftrace.evlist); + evlist__delete(ftrace.evlist); out_delete_filters: delete_filter_func(&ftrace.filters); diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index a83af92fb0d1..3976aebe3677 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -4,8 +4,9 @@ * * Builtin help command */ -#include "perf.h" +#include "util/cache.h" #include "util/config.h" +#include "util/strbuf.h" #include "builtin.h" #include <subcmd/exec-cmd.h> #include "common-cmds.h" @@ -14,10 +15,12 @@ #include <subcmd/help.h> #include "util/debug.h" #include <linux/kernel.h> +#include <linux/string.h> #include <linux/zalloc.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index f4591a1438b4..c14f40b858bc 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -8,8 +8,8 @@ */ #include "builtin.h" -#include "perf.h" #include "util/color.h" +#include "util/dso.h" #include "util/evlist.h" #include "util/evsel.h" #include "util/map.h" @@ -96,7 +96,7 @@ static int perf_event__repipe_op2_synth(struct perf_session *session, static int perf_event__repipe_attr(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist) + struct evlist **pevlist) { struct perf_inject *inject = container_of(tool, struct perf_inject, tool); @@ -215,13 +215,13 @@ static int perf_event__drop_aux(struct perf_tool *tool, typedef int (*inject_handler)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine); static int perf_event__repipe_sample(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { if (evsel && evsel->handler) { @@ -424,7 +424,7 @@ static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, static int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct machine *machine) { struct addr_location al; @@ -465,7 +465,7 @@ repipe: static int perf_inject__sched_process_exit(struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_sample *sample, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct machine *machine __maybe_unused) { struct perf_inject *inject = container_of(tool, struct perf_inject, tool); @@ -485,7 +485,7 @@ static int perf_inject__sched_process_exit(struct perf_tool *tool, static int perf_inject__sched_switch(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct perf_inject *inject = container_of(tool, struct perf_inject, tool); @@ -509,7 +509,7 @@ static int perf_inject__sched_switch(struct perf_tool *tool, static int perf_inject__sched_stat(struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct event_entry *ent; @@ -530,8 +530,8 @@ found: sample_sw.period = sample->period; sample_sw.time = sample->time; - perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, - evsel->attr.read_format, &sample_sw); + perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type, + evsel->core.attr.read_format, &sample_sw); build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); return perf_event__repipe(tool, event_sw, &sample_sw, machine); } @@ -541,10 +541,10 @@ static void sig_handler(int sig __maybe_unused) session_done = 1; } -static int perf_evsel__check_stype(struct perf_evsel *evsel, +static int perf_evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; const char *name = perf_evsel__name(evsel); if (!(attr->sample_type & sample_type)) { @@ -559,7 +559,7 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel, static int drop_sample(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 evsel *evsel __maybe_unused, struct machine *machine __maybe_unused) { return 0; @@ -567,8 +567,8 @@ static int drop_sample(struct perf_tool *tool __maybe_unused, static void strip_init(struct perf_inject *inject) { - struct perf_evlist *evlist = inject->session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = inject->session->evlist; + struct evsel *evsel; inject->tool.context_switch = perf_event__drop; @@ -576,10 +576,10 @@ static void strip_init(struct perf_inject *inject) evsel->handler = drop_sample; } -static bool has_tracking(struct perf_evsel *evsel) +static bool has_tracking(struct evsel *evsel) { - return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm || - evsel->attr.task; + return evsel->core.attr.mmap || evsel->core.attr.mmap2 || evsel->core.attr.comm || + evsel->core.attr.task; } #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \ @@ -590,10 +590,10 @@ static bool has_tracking(struct perf_evsel *evsel) * their selected event to exist, except if there is only 1 selected event left * and it has a compatible sample type. */ -static bool ok_to_remove(struct perf_evlist *evlist, - struct perf_evsel *evsel_to_remove) +static bool ok_to_remove(struct evlist *evlist, + struct evsel *evsel_to_remove) { - struct perf_evsel *evsel; + struct evsel *evsel; int cnt = 0; bool ok = false; @@ -603,8 +603,8 @@ static bool ok_to_remove(struct perf_evlist *evlist, evlist__for_each_entry(evlist, evsel) { if (evsel->handler != drop_sample) { cnt += 1; - if ((evsel->attr.sample_type & COMPAT_MASK) == - (evsel_to_remove->attr.sample_type & COMPAT_MASK)) + if ((evsel->core.attr.sample_type & COMPAT_MASK) == + (evsel_to_remove->core.attr.sample_type & COMPAT_MASK)) ok = true; } } @@ -614,16 +614,16 @@ static bool ok_to_remove(struct perf_evlist *evlist, static void strip_fini(struct perf_inject *inject) { - struct perf_evlist *evlist = inject->session->evlist; - struct perf_evsel *evsel, *tmp; + struct evlist *evlist = inject->session->evlist; + struct evsel *evsel, *tmp; /* Remove non-synthesized evsels if possible */ evlist__for_each_entry_safe(evlist, tmp, evsel) { if (evsel->handler == drop_sample && ok_to_remove(evlist, evsel)) { pr_debug("Deleting %s\n", perf_evsel__name(evsel)); - perf_evlist__remove(evlist, evsel); - perf_evsel__delete(evsel); + evlist__remove(evlist, evsel); + evsel__delete(evsel); } } } @@ -651,7 +651,7 @@ static int __cmd_inject(struct perf_inject *inject) if (inject->build_ids) { inject->tool.sample = perf_event__inject_buildid; } else if (inject->sched_stat) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(session->evlist, evsel) { const char *name = perf_evsel__name(evsel); @@ -712,7 +712,7 @@ static int __cmd_inject(struct perf_inject *inject) * remove the evsel. */ if (inject->itrace_synth_opts.set) { - struct perf_evsel *evsel; + struct evsel *evsel; perf_header__clear_feat(&session->header, HEADER_AUXTRACE); @@ -724,8 +724,8 @@ static int __cmd_inject(struct perf_inject *inject) if (evsel) { pr_debug("Deleting %s\n", perf_evsel__name(evsel)); - perf_evlist__remove(session->evlist, evsel); - perf_evsel__delete(evsel); + evlist__remove(session->evlist, evsel); + evsel__delete(evsel); } if (inject->strip) strip_fini(inject); diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c index c1a44671b0b5..c08ee81529e8 100644 --- a/tools/perf/builtin-kallsyms.c +++ b/tools/perf/builtin-kallsyms.c @@ -11,6 +11,7 @@ #include <linux/compiler.h> #include <subcmd/parse-options.h> #include "debug.h" +#include "dso.h" #include "machine.h" #include "map.h" #include "symbol.h" diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 9e5e60898083..b5682beaad72 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -2,6 +2,7 @@ #include "builtin.h" #include "perf.h" +#include "util/dso.h" #include "util/evlist.h" #include "util/evsel.h" #include "util/config.h" @@ -14,6 +15,7 @@ #include "util/callchain.h" #include "util/time-utils.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/trace-event.h" #include "util/data.h" @@ -166,7 +168,7 @@ static int insert_caller_stat(unsigned long call_site, return 0; } -static int perf_evsel__process_alloc_event(struct perf_evsel *evsel, +static int perf_evsel__process_alloc_event(struct evsel *evsel, struct perf_sample *sample) { unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"), @@ -185,7 +187,7 @@ static int perf_evsel__process_alloc_event(struct perf_evsel *evsel, return 0; } -static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel, +static int perf_evsel__process_alloc_node_event(struct evsel *evsel, struct perf_sample *sample) { int ret = perf_evsel__process_alloc_event(evsel, sample); @@ -229,7 +231,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr, return NULL; } -static int perf_evsel__process_free_event(struct perf_evsel *evsel, +static int perf_evsel__process_free_event(struct evsel *evsel, struct perf_sample *sample) { unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"); @@ -381,7 +383,7 @@ static int build_alloc_func_list(void) * Find first non-memory allocation function from callchain. * The allocation functions are in the 'alloc_func_list'. */ -static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample) +static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample) { struct addr_location al; struct machine *machine = &kmem_session->machines.host; @@ -728,7 +730,7 @@ static char *compact_gfp_string(unsigned long gfp_flags) return NULL; } -static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, +static int parse_gfp_flags(struct evsel *evsel, struct perf_sample *sample, unsigned int gfp_flags) { struct tep_record record = { @@ -749,7 +751,8 @@ static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, } trace_seq_init(&seq); - tep_event_info(&seq, evsel->tp_format, &record); + tep_print_event(evsel->tp_format->tep, + &seq, &record, "%s", TEP_PRINT_INFO); str = strtok_r(seq.buffer, " ", &pos); while (str) { @@ -779,7 +782,7 @@ static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, return 0; } -static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel, +static int perf_evsel__process_page_alloc_event(struct evsel *evsel, struct perf_sample *sample) { u64 page; @@ -852,7 +855,7 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel, return 0; } -static int perf_evsel__process_page_free_event(struct perf_evsel *evsel, +static int perf_evsel__process_page_free_event(struct evsel *evsel, struct perf_sample *sample) { u64 page; @@ -930,13 +933,13 @@ static bool perf_kmem__skip_sample(struct perf_sample *sample) return false; } -typedef int (*tracepoint_handler)(struct perf_evsel *evsel, +typedef int (*tracepoint_handler)(struct evsel *evsel, struct perf_sample *sample); static int process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { int err = 0; @@ -1363,8 +1366,8 @@ static void sort_result(void) static int __cmd_kmem(struct perf_session *session) { int err = -EINVAL; - struct perf_evsel *evsel; - const struct perf_evsel_str_handler kmem_tracepoints[] = { + struct evsel *evsel; + const struct evsel_str_handler kmem_tracepoints[] = { /* slab allocator */ { "kmem:kmalloc", perf_evsel__process_alloc_event, }, { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, }, @@ -1967,7 +1970,7 @@ int cmd_kmem(int argc, const char **argv) } if (kmem_page) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = perf_evlist__find_tracepoint_by_name(session->evlist, "kmem:mm_page_alloc"); diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index b33c83489120..0a4fcbe32bf6 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -2,15 +2,16 @@ #include "builtin.h" #include "perf.h" +#include "util/build-id.h" #include "util/evsel.h" #include "util/evlist.h" #include "util/term.h" -#include "util/cache.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" #include "util/session.h" #include "util/intlist.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/trace-event.h" #include "util/debug.h" @@ -19,6 +20,7 @@ #include "util/top.h" #include "util/data.h" #include "util/ordered-events.h" +#include "ui/ui.h" #include <sys/prctl.h> #ifdef HAVE_TIMERFD_SUPPORT @@ -30,6 +32,7 @@ #include <fcntl.h> #include <linux/kernel.h> +#include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> #include <errno.h> @@ -57,7 +60,7 @@ static const char *get_filename_for_perf_kvm(void) #ifdef HAVE_KVM_STAT_SUPPORT #include "util/kvm-stat.h" -void exit_event_get_key(struct perf_evsel *evsel, +void exit_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -65,12 +68,12 @@ void exit_event_get_key(struct perf_evsel *evsel, key->key = perf_evsel__intval(evsel, sample, kvm_exit_reason); } -bool kvm_exit_event(struct perf_evsel *evsel) +bool kvm_exit_event(struct evsel *evsel) { return !strcmp(evsel->name, kvm_exit_trace); } -bool exit_event_begin(struct perf_evsel *evsel, +bool exit_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { if (kvm_exit_event(evsel)) { @@ -81,12 +84,12 @@ bool exit_event_begin(struct perf_evsel *evsel, return false; } -bool kvm_entry_event(struct perf_evsel *evsel) +bool kvm_entry_event(struct evsel *evsel) { return !strcmp(evsel->name, kvm_entry_trace); } -bool exit_event_end(struct perf_evsel *evsel, +bool exit_event_end(struct evsel *evsel, struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) { @@ -286,7 +289,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, } static bool is_child_event(struct perf_kvm_stat *kvm, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -396,7 +399,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, static struct vcpu_event_record *per_vcpu_record(struct thread *thread, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { /* Only kvm_entry records vcpu id. */ @@ -419,7 +422,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread, static bool handle_kvm_event(struct perf_kvm_stat *kvm, struct thread *thread, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { struct vcpu_event_record *vcpu_record; @@ -672,7 +675,7 @@ static bool skip_sample(struct perf_kvm_stat *kvm, static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { int err = 0; @@ -743,7 +746,7 @@ static bool verify_vcpu(int vcpu) static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, u64 *mmap_time) { - struct perf_evlist *evlist = kvm->evlist; + struct evlist *evlist = kvm->evlist; union perf_event *event; struct perf_mmap *md; u64 timestamp; @@ -972,7 +975,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) goto out; /* everything is good - enable the events and process */ - perf_evlist__enable(kvm->evlist); + evlist__enable(kvm->evlist); while (!done) { struct fdarray *fda = &kvm->evlist->pollfd; @@ -993,7 +996,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) err = fdarray__poll(fda, 100); } - perf_evlist__disable(kvm->evlist); + evlist__disable(kvm->evlist); if (err == 0) { sort_result(kvm); @@ -1011,8 +1014,8 @@ out: static int kvm_live_open_events(struct perf_kvm_stat *kvm) { int err, rc = -1; - struct perf_evsel *pos; - struct perf_evlist *evlist = kvm->evlist; + struct evsel *pos; + struct evlist *evlist = kvm->evlist; char sbuf[STRERR_BUFSIZE]; perf_evlist__config(evlist, &kvm->opts, NULL); @@ -1022,7 +1025,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) * This command processes KVM tracepoints from host only */ evlist__for_each_entry(evlist, pos) { - struct perf_event_attr *attr = &pos->attr; + struct perf_event_attr *attr = &pos->core.attr; /* make sure these *are* set */ perf_evsel__set_sample_bit(pos, TID); @@ -1048,7 +1051,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) attr->disabled = 1; } - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { printf("Couldn't create the events: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -1058,7 +1061,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) { ui__error("Failed to mmap the events: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); - perf_evlist__close(evlist); + evlist__close(evlist); goto out; } @@ -1283,14 +1286,14 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) } #ifdef HAVE_TIMERFD_SUPPORT -static struct perf_evlist *kvm_live_event_list(void) +static struct evlist *kvm_live_event_list(void) { - struct perf_evlist *evlist; + struct evlist *evlist; char *tp, *name, *sys; int err = -1; const char * const *events_tp; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (evlist == NULL) return NULL; @@ -1325,7 +1328,7 @@ static struct perf_evlist *kvm_live_event_list(void) out: if (err) { - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; } @@ -1450,7 +1453,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, perf_session__set_id_hdr_size(kvm->session); ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true); machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, - kvm->evlist->threads, false, 1); + kvm->evlist->core.threads, false, 1); err = kvm_live_open_events(kvm); if (err) goto out; @@ -1460,7 +1463,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, out: perf_session__delete(kvm->session); kvm->session = NULL; - perf_evlist__delete(kvm->evlist); + evlist__delete(kvm->evlist); return err; } diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index e0312a1c4792..e290f6b348d8 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -10,14 +10,13 @@ */ #include "builtin.h" -#include "perf.h" - #include "util/parse-events.h" -#include "util/cache.h" #include "util/pmu.h" #include "util/debug.h" #include "util/metricgroup.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> +#include <stdio.h> static bool desc_flag = true; static bool details_flag; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 574e30ec6d7c..4c2b7f437cdf 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -4,13 +4,13 @@ #include "builtin.h" #include "perf.h" -#include "util/evlist.h" +#include "util/evlist.h" // for struct evsel_str_handler #include "util/evsel.h" -#include "util/cache.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/trace-event.h" @@ -347,16 +347,16 @@ alloc_failed: } struct trace_lock_handler { - int (*acquire_event)(struct perf_evsel *evsel, + int (*acquire_event)(struct evsel *evsel, struct perf_sample *sample); - int (*acquired_event)(struct perf_evsel *evsel, + int (*acquired_event)(struct evsel *evsel, struct perf_sample *sample); - int (*contended_event)(struct perf_evsel *evsel, + int (*contended_event)(struct evsel *evsel, struct perf_sample *sample); - int (*release_event)(struct perf_evsel *evsel, + int (*release_event)(struct evsel *evsel, struct perf_sample *sample); }; @@ -396,7 +396,7 @@ enum acquire_flags { READ_LOCK = 2, }; -static int report_lock_acquire_event(struct perf_evsel *evsel, +static int report_lock_acquire_event(struct evsel *evsel, struct perf_sample *sample) { void *addr; @@ -468,7 +468,7 @@ end: return 0; } -static int report_lock_acquired_event(struct perf_evsel *evsel, +static int report_lock_acquired_event(struct evsel *evsel, struct perf_sample *sample) { void *addr; @@ -531,7 +531,7 @@ end: return 0; } -static int report_lock_contended_event(struct perf_evsel *evsel, +static int report_lock_contended_event(struct evsel *evsel, struct perf_sample *sample) { void *addr; @@ -586,7 +586,7 @@ end: return 0; } -static int report_lock_release_event(struct perf_evsel *evsel, +static int report_lock_release_event(struct evsel *evsel, struct perf_sample *sample) { void *addr; @@ -656,7 +656,7 @@ static struct trace_lock_handler report_lock_ops = { static struct trace_lock_handler *trace_handler; -static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel, +static int perf_evsel__process_lock_acquire(struct evsel *evsel, struct perf_sample *sample) { if (trace_handler->acquire_event) @@ -664,7 +664,7 @@ static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel, return 0; } -static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel, +static int perf_evsel__process_lock_acquired(struct evsel *evsel, struct perf_sample *sample) { if (trace_handler->acquired_event) @@ -672,7 +672,7 @@ static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel, return 0; } -static int perf_evsel__process_lock_contended(struct perf_evsel *evsel, +static int perf_evsel__process_lock_contended(struct evsel *evsel, struct perf_sample *sample) { if (trace_handler->contended_event) @@ -680,7 +680,7 @@ static int perf_evsel__process_lock_contended(struct perf_evsel *evsel, return 0; } -static int perf_evsel__process_lock_release(struct perf_evsel *evsel, +static int perf_evsel__process_lock_release(struct evsel *evsel, struct perf_sample *sample) { if (trace_handler->release_event) @@ -806,13 +806,13 @@ static int dump_info(void) return rc; } -typedef int (*tracepoint_handler)(struct perf_evsel *evsel, +typedef int (*tracepoint_handler)(struct evsel *evsel, struct perf_sample *sample); static int process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { int err = 0; @@ -847,7 +847,7 @@ static void sort_result(void) } } -static const struct perf_evsel_str_handler lock_tracepoints[] = { +static const struct evsel_str_handler lock_tracepoints[] = { { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ { "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index f45c8b502f63..27d2bde943a8 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -11,8 +11,10 @@ #include "util/tool.h" #include "util/session.h" #include "util/data.h" +#include "util/map_symbol.h" #include "util/mem-events.h" #include "util/debug.h" +#include "util/dso.h" #include "util/map.h" #include "util/symbol.h" @@ -230,7 +232,7 @@ out_put: static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct machine *machine) { return dump_raw_samples(tool, event, sample, machine); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 3d0ffd41fb55..26bc5923e6b5 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -16,17 +16,18 @@ #include <stdlib.h> #include <string.h> -#include "perf.h" #include "builtin.h" #include "namespaces.h" +#include "util/build-id.h" #include "util/strlist.h" #include "util/strfilter.h" -#include "util/symbol.h" +#include "util/symbol_conf.h" #include "util/debug.h" #include <subcmd/parse-options.h> #include "util/probe-finder.h" #include "util/probe-event.h" #include "util/probe-file.h" +#include <linux/string.h> #include <linux/zalloc.h> #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8779cee58185..1447004eee8a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -8,8 +8,6 @@ */ #include "builtin.h" -#include "perf.h" - #include "util/build-id.h" #include <subcmd/parse-options.h> #include "util/parse-events.h" @@ -22,9 +20,11 @@ #include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" +#include "util/target.h" #include "util/session.h" #include "util/tool.h" #include "util/symbol.h" +#include "util/record.h" #include "util/cpumap.h" #include "util/thread_map.h" #include "util/data.h" @@ -42,6 +42,7 @@ #include "util/units.h" #include "util/bpf-event.h" #include "asm/bug.h" +#include "perf.h" #include <errno.h> #include <inttypes.h> @@ -52,6 +53,7 @@ #include <signal.h> #include <sys/mman.h> #include <sys/wait.h> +#include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> @@ -73,7 +75,7 @@ struct record { u64 bytes_written; struct perf_data data; struct auxtrace_record *itr; - struct perf_evlist *evlist; + struct evlist *evlist; struct perf_session *session; int realtime_prio; bool no_buildid; @@ -346,7 +348,7 @@ static void record__aio_set_pos(int trace_fd, off_t pos) static void record__aio_mmap_read_sync(struct record *rec) { int i; - struct perf_evlist *evlist = rec->evlist; + struct evlist *evlist = rec->evlist; struct perf_mmap *maps = evlist->mmap; if (!record__aio_enabled(rec)) @@ -613,19 +615,35 @@ out: return rc; } -static void record__read_auxtrace_snapshot(struct record *rec) +static void record__read_auxtrace_snapshot(struct record *rec, bool on_exit) { pr_debug("Recording AUX area tracing snapshot\n"); if (record__auxtrace_read_snapshot_all(rec) < 0) { trigger_error(&auxtrace_snapshot_trigger); } else { - if (auxtrace_record__snapshot_finish(rec->itr)) + if (auxtrace_record__snapshot_finish(rec->itr, on_exit)) trigger_error(&auxtrace_snapshot_trigger); else trigger_ready(&auxtrace_snapshot_trigger); } } +static int record__auxtrace_snapshot_exit(struct record *rec) +{ + if (trigger_is_error(&auxtrace_snapshot_trigger)) + return 0; + + if (!auxtrace_record__snapshot_started && + auxtrace_record__snapshot_start(rec->itr)) + return -1; + + record__read_auxtrace_snapshot(rec, true); + if (trigger_is_error(&auxtrace_snapshot_trigger)) + return -1; + + return 0; +} + static int record__auxtrace_init(struct record *rec) { int err; @@ -654,7 +672,8 @@ int record__auxtrace_mmap_read(struct record *rec __maybe_unused, } static inline -void record__read_auxtrace_snapshot(struct record *rec __maybe_unused) +void record__read_auxtrace_snapshot(struct record *rec __maybe_unused, + bool on_exit __maybe_unused) { } @@ -664,6 +683,12 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused) return 0; } +static inline +int record__auxtrace_snapshot_exit(struct record *rec __maybe_unused) +{ + return 0; +} + static int record__auxtrace_init(struct record *rec __maybe_unused) { return 0; @@ -672,7 +697,7 @@ static int record__auxtrace_init(struct record *rec __maybe_unused) #endif static int record__mmap_evlist(struct record *rec, - struct perf_evlist *evlist) + struct evlist *evlist) { struct record_opts *opts = &rec->opts; char msg[512]; @@ -713,8 +738,8 @@ static int record__mmap(struct record *rec) static int record__open(struct record *rec) { char msg[BUFSIZ]; - struct perf_evsel *pos; - struct perf_evlist *evlist = rec->evlist; + struct evsel *pos; + struct evlist *evlist = rec->evlist; struct perf_session *session = rec->session; struct record_opts *opts = &rec->opts; int rc = 0; @@ -732,14 +757,14 @@ static int record__open(struct record *rec) pos->tracking = 0; pos = perf_evlist__last(evlist); pos->tracking = 1; - pos->attr.enable_on_exec = 1; + pos->core.attr.enable_on_exec = 1; } perf_evlist__config(evlist, opts, &callchain_param); evlist__for_each_entry(evlist, pos) { try_again: - if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) { + if (evsel__open(pos, pos->core.cpus, pos->core.threads) < 0) { if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { if (verbose > 0) ui__warning("%s\n", msg); @@ -782,7 +807,7 @@ out: static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct record *rec = container_of(tool, struct record, tool); @@ -875,7 +900,7 @@ static void record__adjust_affinity(struct record *rec, struct perf_mmap *map) static size_t process_comp_header(void *record, size_t increment) { - struct compressed_event *event = record; + struct perf_record_compressed *event = record; size_t size = sizeof(*event); if (increment) { @@ -893,7 +918,7 @@ static size_t zstd_compress(struct perf_session *session, void *dst, size_t dst_ void *src, size_t src_size) { size_t compressed; - size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct compressed_event) - 1; + size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_record_compressed) - 1; compressed = zstd_compress_stream_to_records(&session->zstd_data, dst, dst_size, src, src_size, max_record_size, process_comp_header); @@ -904,7 +929,7 @@ static size_t zstd_compress(struct perf_session *session, void *dst, size_t dst_ return compressed; } -static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist, +static int record__mmap_read_evlist(struct record *rec, struct evlist *evlist, bool overwrite, bool synch) { u64 bytes_written = rec->bytes_written; @@ -1002,7 +1027,7 @@ static void record__init_features(struct record *rec) if (rec->no_buildid) perf_header__clear_feat(&session->header, HEADER_BUILD_ID); - if (!have_tracepoints(&rec->evlist->entries)) + if (!have_tracepoints(&rec->evlist->core.entries)) perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); if (!rec->opts.branch_stack) @@ -1047,7 +1072,7 @@ record__finish_output(struct record *rec) static int record__synthesize_workload(struct record *rec, bool tail) { int err; - struct thread_map *thread_map; + struct perf_thread_map *thread_map; if (rec->opts.tail_synthesize != tail) return 0; @@ -1060,7 +1085,7 @@ static int record__synthesize_workload(struct record *rec, bool tail) process_synthesized_event, &rec->session->machines.host, rec->opts.sample_address); - thread_map__put(thread_map); + perf_thread_map__put(thread_map); return err; } @@ -1165,7 +1190,7 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused } static const struct perf_event_mmap_page * -perf_evlist__pick_pc(struct perf_evlist *evlist) +perf_evlist__pick_pc(struct evlist *evlist) { if (evlist) { if (evlist->mmap && evlist->mmap[0].base) @@ -1218,7 +1243,7 @@ static int record__synthesize(struct record *rec, bool tail) return err; } - if (have_tracepoints(&rec->evlist->entries)) { + if (have_tracepoints(&rec->evlist->core.entries)) { /* * FIXME err <= 0 here actually means that * there were no tracepoints so its not really @@ -1275,7 +1300,7 @@ static int record__synthesize(struct record *rec, bool tail) if (err) goto out; - err = perf_event__synthesize_thread_map2(&rec->tool, rec->evlist->threads, + err = perf_event__synthesize_thread_map2(&rec->tool, rec->evlist->core.threads, process_synthesized_event, NULL); if (err < 0) { @@ -1283,7 +1308,7 @@ static int record__synthesize(struct record *rec, bool tail) return err; } - err = perf_event__synthesize_cpu_map(&rec->tool, rec->evlist->cpus, + err = perf_event__synthesize_cpu_map(&rec->tool, rec->evlist->core.cpus, process_synthesized_event, NULL); if (err < 0) { pr_err("Couldn't synthesize cpu map.\n"); @@ -1295,7 +1320,7 @@ static int record__synthesize(struct record *rec, bool tail) if (err < 0) pr_warning("Couldn't synthesize bpf events.\n"); - err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, + err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->core.threads, process_synthesized_event, opts->sample_address, 1); out: @@ -1313,7 +1338,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) struct perf_data *data = &rec->data; struct perf_session *session; bool disabled = false, draining = false; - struct perf_evlist *sb_evlist = NULL; + struct evlist *sb_evlist = NULL; int fd; float ratio = 0; @@ -1375,7 +1400,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * because we synthesize event name through the pipe * and need the id for that. */ - if (data->is_pipe && rec->evlist->nr_entries == 1) + if (data->is_pipe && rec->evlist->core.nr_entries == 1) rec->opts.sample_id = true; if (record__open(rec) != 0) { @@ -1453,7 +1478,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * so don't spoil it by prematurely enabling them. */ if (!target__none(&opts->target) && !opts->initial_delay) - perf_evlist__enable(rec->evlist); + evlist__enable(rec->evlist); /* * Let the child rip @@ -1506,7 +1531,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) if (opts->initial_delay) { usleep(opts->initial_delay * USEC_PER_MSEC); - perf_evlist__enable(rec->evlist); + evlist__enable(rec->evlist); } trigger_ready(&auxtrace_snapshot_trigger); @@ -1536,7 +1561,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) if (auxtrace_record__snapshot_started) { auxtrace_record__snapshot_started = 0; if (!trigger_is_error(&auxtrace_snapshot_trigger)) - record__read_auxtrace_snapshot(rec); + record__read_auxtrace_snapshot(rec, false); if (trigger_is_error(&auxtrace_snapshot_trigger)) { pr_err("AUX area tracing snapshot failed\n"); err = -1; @@ -1605,13 +1630,17 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) */ if (done && !disabled && !target__none(&opts->target)) { trigger_off(&auxtrace_snapshot_trigger); - perf_evlist__disable(rec->evlist); + evlist__disable(rec->evlist); disabled = true; } } + trigger_off(&auxtrace_snapshot_trigger); trigger_off(&switch_output_trigger); + if (opts->auxtrace_snapshot_on_exit) + record__auxtrace_snapshot_exit(rec); + if (forks && workload_exec_errno) { char msg[STRERR_BUFSIZE]; const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); @@ -2265,7 +2294,7 @@ int cmd_record(int argc, const char **argv) CPU_ZERO(&rec->affinity_mask); rec->opts.affinity = PERF_AFFINITY_SYS; - rec->evlist = perf_evlist__new(); + rec->evlist = evlist__new(); if (rec->evlist == NULL) return -ENOMEM; @@ -2345,7 +2374,7 @@ int cmd_record(int argc, const char **argv) if (symbol_conf.kptr_restrict && !perf_evlist__exclude_kernel(rec->evlist)) pr_warning( "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" -"check /proc/sys/kernel/kptr_restrict.\n\n" +"check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n" "Samples in kernel functions may not be resolved if a suitable vmlinux\n" "file is not found in the buildid cache or in the vmlinux path.\n\n" "Samples in kernel modules won't be resolved at all.\n\n" @@ -2386,7 +2415,7 @@ int cmd_record(int argc, const char **argv) if (record.opts.overwrite) record.opts.tail_synthesize = true; - if (rec->evlist->nr_entries == 0 && + if (rec->evlist->core.nr_entries == 0 && __perf_evlist__add_default(rec->evlist, !record.opts.no_samples) < 0) { pr_err("Not enough memory for event selector list\n"); goto out; @@ -2449,7 +2478,7 @@ int cmd_record(int argc, const char **argv) err = __cmd_record(&record, argc, argv); out: - perf_evlist__delete(rec->evlist); + evlist__delete(rec->evlist); symbol__exit(); auxtrace_record__free(rec->itr); return err; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index abf0b9b8f566..b18fab94d38d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -12,12 +12,16 @@ #include "util/annotate.h" #include "util/color.h" +#include "util/dso.h" #include <linux/list.h> #include <linux/rbtree.h> #include <linux/err.h> #include <linux/zalloc.h> #include "util/map.h" #include "util/symbol.h" +#include "util/map_symbol.h" +#include "util/mem-events.h" +#include "util/branch.h" #include "util/callchain.h" #include "util/values.h" @@ -25,8 +29,10 @@ #include "util/debug.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evswitch.h" #include "util/header.h" #include "util/session.h" +#include "util/srcline.h" #include "util/tool.h" #include <subcmd/parse-options.h> @@ -42,6 +48,9 @@ #include "util/auxtrace.h" #include "util/units.h" #include "util/branch.h" +#include "util/util.h" +#include "ui/ui.h" +#include "ui/progress.h" #include <dlfcn.h> #include <errno.h> @@ -50,6 +59,7 @@ #include <linux/ctype.h> #include <signal.h> #include <linux/bitmap.h> +#include <linux/string.h> #include <linux/stringify.h> #include <linux/time64.h> #include <sys/types.h> @@ -60,6 +70,7 @@ struct report { struct perf_tool tool; struct perf_session *session; + struct evswitch evswitch; bool use_tui, use_gtk, use_stdio; bool show_full_info; bool show_threads; @@ -128,7 +139,7 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, int err = 0; struct report *rep = arg; struct hist_entry *he = iter->he; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; struct mem_info *mi; struct branch_info *bi; @@ -172,7 +183,7 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, struct report *rep = arg; struct branch_info *bi; struct perf_sample *sample = iter->sample; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; int err; if (!ui__has_annotation() && !rep->symbol_ipc) @@ -193,7 +204,7 @@ out: } static void setup_forced_leader(struct report *report, - struct perf_evlist *evlist) + struct evlist *evlist) { if (report->group_set) perf_evlist__force_leader(evlist); @@ -208,7 +219,7 @@ static int process_feature_event(struct perf_session *session, return perf_event__process_feature(session, event); if (event->feat.feat_id != HEADER_LAST_FEATURE) { - pr_err("failed: wrong feature ID: %" PRIu64 "\n", + pr_err("failed: wrong feature ID: %" PRI_lu64 "\n", event->feat.feat_id); return -1; } @@ -225,7 +236,7 @@ static int process_feature_event(struct perf_session *session, static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct report *rep = container_of(tool, struct report, tool); @@ -243,6 +254,9 @@ static int process_sample_event(struct perf_tool *tool, return 0; } + if (evswitch__discard(&rep->evswitch, evsel)) + return 0; + if (machine__resolve(machine, &al, sample) < 0) { pr_debug("problem processing %d event, skipping it.\n", event->header.type); @@ -292,7 +306,7 @@ out_put: static int process_read_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __maybe_unused, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine __maybe_unused) { struct report *rep = container_of(tool, struct report, tool); @@ -400,7 +414,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report char unit; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); char buf[512]; size_t size = sizeof(buf); int socked_id = hists->socket_filter; @@ -414,7 +428,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report } if (perf_evsel__is_group_event(evsel)) { - struct perf_evsel *pos; + struct evsel *pos; perf_evsel__group_desc(evsel, buf, size); evname = buf; @@ -436,7 +450,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); if (evname != NULL) { ret += fprintf(fp, " of event%s '%s'", - evsel->nr_members > 1 ? "s" : "", evname); + evsel->core.nr_members > 1 ? "s" : "", evname); } if (rep->time_str) @@ -459,11 +473,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report return ret + fprintf(fp, "\n#\n"); } -static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, +static int perf_evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, const char *help) { - struct perf_evsel *pos; + struct evsel *pos; if (!quiet) { fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", @@ -532,7 +546,7 @@ static void report__warn_kptr_restrict(const struct report *rep) static int report__gtk_browse_hists(struct report *rep, const char *help) { - int (*hist_browser)(struct perf_evlist *evlist, const char *help, + int (*hist_browser)(struct evlist *evlist, const char *help, struct hist_browser_timer *timer, float min_pcnt); hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists"); @@ -549,7 +563,7 @@ static int report__browse_hists(struct report *rep) { int ret; struct perf_session *session = rep->session; - struct perf_evlist *evlist = session->evlist; + struct evlist *evlist = session->evlist; const char *help = perf_tip(system_path(TIPDIR)); if (help == NULL) { @@ -586,7 +600,7 @@ static int report__browse_hists(struct report *rep) static int report__collapse_hists(struct report *rep) { struct ui_progress prog; - struct perf_evsel *pos; + struct evsel *pos; int ret = 0; ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); @@ -623,7 +637,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) struct symbol *sym = he->ms.sym; if (rep->symbol_ipc && sym && !sym->annotate2) { - struct perf_evsel *evsel = hists_to_evsel(he->hists); + struct evsel *evsel = hists_to_evsel(he->hists); symbol__annotate2(sym, he->ms.map, evsel, &annotation__default_options, NULL); @@ -635,7 +649,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) static void report__output_resort(struct report *rep) { struct ui_progress prog; - struct perf_evsel *pos; + struct evsel *pos; ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); @@ -818,7 +832,7 @@ static int __cmd_report(struct report *rep) { int ret; struct perf_session *session = rep->session; - struct perf_evsel *pos; + struct evsel *pos; struct perf_data *data = session->data; signal(SIGINT, sig_handler); @@ -1189,6 +1203,7 @@ int cmd_report(int argc, const char **argv) OPT_CALLBACK(0, "time-quantum", &symbol_conf.time_quantum, "time (ms|us|ns|s)", "Set time quantum for time sort key (default 100ms)", parse_time_quantum), + OPTS_EVSWITCH(&report.evswitch), OPT_END() }; struct perf_data data = { @@ -1257,6 +1272,10 @@ repeat: if (session == NULL) return -1; + ret = evswitch__init(&report.evswitch, session->evlist, stderr); + if (ret) + return ret; + if (zstd_init(&(session->zstd_data), 0) < 0) pr_warning("Decompression initialization failed. Reported data may be incomplete.\n"); @@ -1271,6 +1290,8 @@ repeat: has_br_stack = perf_header__has_feat(&session->header, HEADER_BRANCH_STACK); + if (perf_evlist__combined_sample_type(session->evlist) & PERF_SAMPLE_STACK_USER) + has_br_stack = false; setup_forced_leader(&report, session->evlist); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 56d1907b1215..ec96d64aec69 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include "builtin.h" #include "perf.h" +#include "perf-sys.h" #include "util/evlist.h" -#include "util/cache.h" #include "util/evsel.h" #include "util/symbol.h" #include "util/thread.h" @@ -18,6 +18,7 @@ #include "util/callchain.h" #include "util/time-utils.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/trace-event.h" @@ -133,13 +134,13 @@ typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *); struct perf_sched; struct trace_sched_handler { - int (*switch_event)(struct perf_sched *sched, struct perf_evsel *evsel, + int (*switch_event)(struct perf_sched *sched, struct evsel *evsel, struct perf_sample *sample, struct machine *machine); - int (*runtime_event)(struct perf_sched *sched, struct perf_evsel *evsel, + int (*runtime_event)(struct perf_sched *sched, struct evsel *evsel, struct perf_sample *sample, struct machine *machine); - int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, + int (*wakeup_event)(struct perf_sched *sched, struct evsel *evsel, struct perf_sample *sample, struct machine *machine); /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */ @@ -147,7 +148,7 @@ struct trace_sched_handler { struct machine *machine); int (*migrate_task_event)(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine); }; @@ -159,11 +160,11 @@ struct perf_sched_map { DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS); int *comp_cpus; bool comp; - struct thread_map *color_pids; + struct perf_thread_map *color_pids; const char *color_pids_str; - struct cpu_map *color_cpus; + struct perf_cpu_map *color_cpus; const char *color_cpus_str; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; const char *cpus_str; }; @@ -799,7 +800,7 @@ static void test_calibrations(struct perf_sched *sched) static int replay_wakeup_event(struct perf_sched *sched, - struct perf_evsel *evsel, struct perf_sample *sample, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine __maybe_unused) { const char *comm = perf_evsel__strval(evsel, sample, "comm"); @@ -820,7 +821,7 @@ replay_wakeup_event(struct perf_sched *sched, } static int replay_switch_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine __maybe_unused) { @@ -1093,7 +1094,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) } static int latency_switch_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1163,7 +1164,7 @@ out_put: } static int latency_runtime_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1198,7 +1199,7 @@ out_put: } static int latency_wakeup_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1259,7 +1260,7 @@ out_put: } static int latency_migrate_task_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1470,7 +1471,7 @@ again: } static int process_sched_wakeup_event(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1514,7 +1515,7 @@ map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid return thread; } -static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, +static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid"); @@ -1655,7 +1656,7 @@ out: } static int process_sched_switch_event(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1681,7 +1682,7 @@ static int process_sched_switch_event(struct perf_tool *tool, } static int process_sched_runtime_event(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1711,7 +1712,7 @@ static int perf_sched__process_fork_event(struct perf_tool *tool, } static int process_sched_migrate_task_event(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -1724,14 +1725,14 @@ static int process_sched_migrate_task_event(struct perf_tool *tool, } typedef int (*tracepoint_handler)(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine); static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { int err = 0; @@ -1777,7 +1778,7 @@ static int perf_sched__process_comm(struct perf_tool *tool __maybe_unused, static int perf_sched__read_events(struct perf_sched *sched) { - const struct perf_evsel_str_handler handlers[] = { + const struct evsel_str_handler handlers[] = { { "sched:sched_switch", process_sched_switch_event, }, { "sched:sched_stat_runtime", process_sched_runtime_event, }, { "sched:sched_wakeup", process_sched_wakeup_event, }, @@ -1839,7 +1840,7 @@ static inline void print_sched_time(unsigned long long nsecs, int width) * returns runtime data for event, allocating memory for it the * first time it is used. */ -static struct evsel_runtime *perf_evsel__get_runtime(struct perf_evsel *evsel) +static struct evsel_runtime *perf_evsel__get_runtime(struct evsel *evsel) { struct evsel_runtime *r = evsel->priv; @@ -1854,7 +1855,7 @@ static struct evsel_runtime *perf_evsel__get_runtime(struct perf_evsel *evsel) /* * save last time event was seen per cpu */ -static void perf_evsel__save_time(struct perf_evsel *evsel, +static void perf_evsel__save_time(struct evsel *evsel, u64 timestamp, u32 cpu) { struct evsel_runtime *r = perf_evsel__get_runtime(evsel); @@ -1881,7 +1882,7 @@ static void perf_evsel__save_time(struct perf_evsel *evsel, } /* returns last time this event was seen on the given cpu */ -static u64 perf_evsel__get_time(struct perf_evsel *evsel, u32 cpu) +static u64 perf_evsel__get_time(struct evsel *evsel, u32 cpu) { struct evsel_runtime *r = perf_evsel__get_runtime(evsel); @@ -1988,7 +1989,7 @@ static char task_state_char(struct thread *thread, int state) } static void timehist_print_sample(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct addr_location *al, struct thread *thread, @@ -2121,7 +2122,7 @@ static void timehist_update_runtime_stats(struct thread_runtime *r, } static bool is_idle_sample(struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { /* pid 0 == swapper == idle task */ if (strcmp(perf_evsel__name(evsel), "sched:sched_switch") == 0) @@ -2132,7 +2133,7 @@ static bool is_idle_sample(struct perf_sample *sample, static void save_task_callchain(struct perf_sched *sched, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct callchain_cursor *cursor = &callchain_cursor; @@ -2286,7 +2287,7 @@ static void save_idle_callchain(struct perf_sched *sched, static struct thread *timehist_get_thread(struct perf_sched *sched, struct perf_sample *sample, struct machine *machine, - struct perf_evsel *evsel) + struct evsel *evsel) { struct thread *thread; @@ -2332,7 +2333,7 @@ static struct thread *timehist_get_thread(struct perf_sched *sched, static bool timehist_skip_sample(struct perf_sched *sched, struct thread *thread, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { bool rc = false; @@ -2354,7 +2355,7 @@ static bool timehist_skip_sample(struct perf_sched *sched, } static void timehist_print_wakeup_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine, struct thread *awakened) @@ -2389,7 +2390,7 @@ static void timehist_print_wakeup_event(struct perf_sched *sched, static int timehist_sched_wakeup_event(struct perf_tool *tool, union perf_event *event __maybe_unused, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -2419,7 +2420,7 @@ static int timehist_sched_wakeup_event(struct perf_tool *tool, } static void timehist_print_migration_event(struct perf_sched *sched, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine, struct thread *migrated) @@ -2473,7 +2474,7 @@ static void timehist_print_migration_event(struct perf_sched *sched, static int timehist_migrate_task_event(struct perf_tool *tool, union perf_event *event __maybe_unused, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -2501,7 +2502,7 @@ static int timehist_migrate_task_event(struct perf_tool *tool, static int timehist_sched_change_event(struct perf_tool *tool, union perf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -2627,7 +2628,7 @@ out: static int timehist_sched_switch_event(struct perf_tool *tool, union perf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine __maybe_unused) { @@ -2643,7 +2644,7 @@ static int process_lost(struct perf_tool *tool __maybe_unused, timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); printf("%15s ", tstr); - printf("lost %" PRIu64 " events on cpu %d\n", event->lost.lost, sample->cpu); + printf("lost %" PRI_lu64 " events on cpu %d\n", event->lost.lost, sample->cpu); return 0; } @@ -2897,14 +2898,14 @@ static void timehist_print_summary(struct perf_sched *sched, typedef int (*sched_handler)(struct perf_tool *tool, union perf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine); static int perf_timehist__process_sample(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct perf_sched *sched = container_of(tool, struct perf_sched, tool); @@ -2924,12 +2925,12 @@ static int perf_timehist__process_sample(struct perf_tool *tool, } static int timehist_check_attr(struct perf_sched *sched, - struct perf_evlist *evlist) + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; struct evsel_runtime *er; - list_for_each_entry(evsel, &evlist->entries, node) { + list_for_each_entry(evsel, &evlist->core.entries, core.node) { er = perf_evsel__get_runtime(evsel); if (er == NULL) { pr_err("Failed to allocate memory for evsel runtime data\n"); @@ -2948,12 +2949,12 @@ static int timehist_check_attr(struct perf_sched *sched, static int perf_sched__timehist(struct perf_sched *sched) { - const struct perf_evsel_str_handler handlers[] = { + const struct evsel_str_handler handlers[] = { { "sched:sched_switch", timehist_sched_switch_event, }, { "sched:sched_wakeup", timehist_sched_wakeup_event, }, { "sched:sched_wakeup_new", timehist_sched_wakeup_event, }, }; - const struct perf_evsel_str_handler migrate_handlers[] = { + const struct evsel_str_handler migrate_handlers[] = { { "sched:sched_migrate_task", timehist_migrate_task_event, }, }; struct perf_data data = { @@ -2963,7 +2964,7 @@ static int perf_sched__timehist(struct perf_sched *sched) }; struct perf_session *session; - struct perf_evlist *evlist; + struct evlist *evlist; int err = -1; /* @@ -3170,7 +3171,7 @@ static int perf_sched__lat(struct perf_sched *sched) static int setup_map_cpus(struct perf_sched *sched) { - struct cpu_map *map; + struct perf_cpu_map *map; sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); @@ -3183,7 +3184,7 @@ static int setup_map_cpus(struct perf_sched *sched) if (!sched->map.cpus_str) return 0; - map = cpu_map__new(sched->map.cpus_str); + map = perf_cpu_map__new(sched->map.cpus_str); if (!map) { pr_err("failed to get cpus map from %s\n", sched->map.cpus_str); return -1; @@ -3195,7 +3196,7 @@ static int setup_map_cpus(struct perf_sched *sched) static int setup_color_pids(struct perf_sched *sched) { - struct thread_map *map; + struct perf_thread_map *map; if (!sched->map.color_pids_str) return 0; @@ -3212,12 +3213,12 @@ static int setup_color_pids(struct perf_sched *sched) static int setup_color_cpus(struct perf_sched *sched) { - struct cpu_map *map; + struct perf_cpu_map *map; if (!sched->map.color_cpus_str) return 0; - map = cpu_map__new(sched->map.color_cpus_str); + map = perf_cpu_map__new(sched->map.color_cpus_str); if (!map) { pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str); return -1; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0140ddb8dd0b..e079b34201f2 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include "builtin.h" -#include "perf.h" -#include "util/cache.h" +#include "util/counts.h" #include "util/debug.h" +#include "util/dso.h" #include <subcmd/exec-cmd.h> #include "util/header.h" #include <subcmd/parse-options.h> @@ -11,11 +11,13 @@ #include "util/session.h" #include "util/tool.h" #include "util/map.h" +#include "util/srcline.h" #include "util/symbol.h" #include "util/thread.h" #include "util/trace-event.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evswitch.h" #include "util/sort.h" #include "util/data.h" #include "util/auxtrace.h" @@ -27,6 +29,7 @@ #include "util/thread-stack.h" #include "util/time-utils.h" #include "util/path.h" +#include "ui/ui.h" #include "print_binary.h" #include "archinsn.h" #include <linux/bitmap.h> @@ -48,6 +51,10 @@ #include <fcntl.h> #include <unistd.h> #include <subcmd/pager.h> +#include <perf/evlist.h> +#include "util/record.h" +#include "util/util.h" +#include "perf.h" #include <linux/ctype.h> @@ -242,7 +249,7 @@ static struct { }, }; -struct perf_evsel_script { +struct evsel_script { char *filename; FILE *fp; u64 samples; @@ -251,15 +258,15 @@ struct perf_evsel_script { int gnum; }; -static inline struct perf_evsel_script *evsel_script(struct perf_evsel *evsel) +static inline struct evsel_script *evsel_script(struct evsel *evsel) { - return (struct perf_evsel_script *)evsel->priv; + return (struct evsel_script *)evsel->priv; } -static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel, +static struct evsel_script *perf_evsel_script__new(struct evsel *evsel, struct perf_data *data) { - struct perf_evsel_script *es = zalloc(sizeof(*es)); + struct evsel_script *es = zalloc(sizeof(*es)); if (es != NULL) { if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0) @@ -277,7 +284,7 @@ out_free: return NULL; } -static void perf_evsel_script__delete(struct perf_evsel_script *es) +static void perf_evsel_script__delete(struct evsel_script *es) { zfree(&es->filename); fclose(es->fp); @@ -285,7 +292,7 @@ static void perf_evsel_script__delete(struct perf_evsel_script *es) free(es); } -static int perf_evsel_script__fprintf(struct perf_evsel_script *es, FILE *fp) +static int perf_evsel_script__fprintf(struct evsel_script *es, FILE *fp) { struct stat st; @@ -340,12 +347,12 @@ static const char *output_field2str(enum perf_output_field field) #define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) -static int perf_evsel__do_check_stype(struct perf_evsel *evsel, +static int perf_evsel__do_check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg, enum perf_output_field field, bool allow_user_set) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; int type = output_type(attr->type); const char *evname; @@ -372,7 +379,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel, return 0; } -static int perf_evsel__check_stype(struct perf_evsel *evsel, +static int perf_evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg, enum perf_output_field field) { @@ -380,10 +387,10 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel, false); } -static int perf_evsel__check_attr(struct perf_evsel *evsel, +static int perf_evsel__check_attr(struct evsel *evsel, struct perf_session *session) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; bool allow_user_set; if (perf_header__has_feat(&session->header, HEADER_STAT)) @@ -418,7 +425,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, return -EINVAL; if (PRINT_FIELD(SYM) && - !(evsel->attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { + !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { pr_err("Display of symbols requested but neither sample IP nor " "sample address\navailable. Hence, no addresses to convert " "to symbols.\n"); @@ -430,7 +437,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, return -EINVAL; } if (PRINT_FIELD(DSO) && - !(evsel->attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { + !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { pr_err("Display of DSO requested but no address to convert.\n"); return -EINVAL; } @@ -507,7 +514,7 @@ static void set_print_ip_opts(struct perf_event_attr *attr) static int perf_session__check_output_opt(struct perf_session *session) { unsigned int j; - struct perf_evsel *evsel; + struct evsel *evsel; for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { evsel = perf_session__find_first_evtype(session, attr_type(j)); @@ -531,7 +538,7 @@ static int perf_session__check_output_opt(struct perf_session *session) if (evsel == NULL) continue; - set_print_ip_opts(&evsel->attr); + set_print_ip_opts(&evsel->core.attr); } if (!no_callchain) { @@ -558,7 +565,7 @@ static int perf_session__check_output_opt(struct perf_session *session) j = PERF_TYPE_TRACEPOINT; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.type != j) + if (evsel->core.attr.type != j) continue; if (evsel__has_callchain(evsel)) { @@ -566,7 +573,7 @@ static int perf_session__check_output_opt(struct perf_session *session) output[j].fields |= PERF_OUTPUT_SYM; output[j].fields |= PERF_OUTPUT_SYMOFFSET; output[j].fields |= PERF_OUTPUT_DSO; - set_print_ip_opts(&evsel->attr); + set_print_ip_opts(&evsel->core.attr); goto out; } } @@ -614,10 +621,10 @@ static int perf_sample__fprintf_uregs(struct perf_sample *sample, static int perf_sample__fprintf_start(struct perf_sample *sample, struct thread *thread, - struct perf_evsel *evsel, + struct evsel *evsel, u32 type, FILE *fp) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; unsigned long secs; unsigned long long nsecs; int printed = 0; @@ -1162,13 +1169,13 @@ out: } static const char *resolve_branch_sym(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct thread *thread, struct addr_location *al, u64 *ip) { struct addr_location addr_al; - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; const char *name = NULL; if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { @@ -1191,11 +1198,11 @@ static const char *resolve_branch_sym(struct perf_sample *sample, } static int perf_sample__fprintf_callindent(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct thread *thread, struct addr_location *al, FILE *fp) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; size_t depth = thread_stack__depth(thread, sample->cpu); const char *name = NULL; static int spacing; @@ -1285,12 +1292,12 @@ static int perf_sample__fprintf_ipc(struct perf_sample *sample, } static int perf_sample__fprintf_bts(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct thread *thread, struct addr_location *al, struct machine *machine, FILE *fp) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; unsigned int type = output_type(attr->type); bool print_srcline_last = false; int printed = 0; @@ -1322,7 +1329,7 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample, /* print branch_to information */ if (PRINT_FIELD(ADDR) || - ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && + ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && !output[type].user_set)) { printed += fprintf(fp, " => "); printed += perf_sample__fprintf_addr(sample, thread, attr, fp); @@ -1593,9 +1600,9 @@ static int perf_sample__fprintf_synth_cbr(struct perf_sample *sample, FILE *fp) } static int perf_sample__fprintf_synth(struct perf_sample *sample, - struct perf_evsel *evsel, FILE *fp) + struct evsel *evsel, FILE *fp) { - switch (evsel->attr.config) { + switch (evsel->core.attr.config) { case PERF_SYNTH_INTEL_PTWRITE: return perf_sample__fprintf_synth_ptwrite(sample, fp); case PERF_SYNTH_INTEL_MWAIT: @@ -1627,8 +1634,9 @@ struct perf_script { bool show_bpf_events; bool allocated; bool per_event_dump; - struct cpu_map *cpus; - struct thread_map *threads; + struct evswitch evswitch; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; int name_width; const char *time_str; struct perf_time_interval *ptime_range; @@ -1636,9 +1644,9 @@ struct perf_script { int range_num; }; -static int perf_evlist__max_name_len(struct perf_evlist *evlist) +static int perf_evlist__max_name_len(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; int max = 0; evlist__for_each_entry(evlist, evsel) { @@ -1670,7 +1678,7 @@ static int data_src__fprintf(u64 data_src, FILE *fp) struct metric_ctx { struct perf_sample *sample; struct thread *thread; - struct perf_evsel *evsel; + struct evsel *evsel; FILE *fp; }; @@ -1705,7 +1713,7 @@ static void script_new_line(struct perf_stat_config *config __maybe_unused, static void perf_sample__fprint_metric(struct perf_script *script, struct thread *thread, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, FILE *fp) { @@ -1720,7 +1728,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, }, .force_header = false, }; - struct perf_evsel *ev2; + struct evsel *ev2; u64 val; if (!evsel->stats) @@ -1733,7 +1741,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, sample->cpu, &rt_stat); evsel_script(evsel)->val = val; - if (evsel_script(evsel->leader)->gnum == evsel->leader->nr_members) { + if (evsel_script(evsel->leader)->gnum == evsel->leader->core.nr_members) { for_each_group_member (ev2, evsel->leader) { perf_stat__print_shadow_stats(&stat_config, ev2, evsel_script(ev2)->val, @@ -1747,7 +1755,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, } static bool show_event(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct thread *thread, struct addr_location *al) { @@ -1788,14 +1796,14 @@ static bool show_event(struct perf_sample *sample, } static void process_event(struct perf_script *script, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct addr_location *al, struct machine *machine) { struct thread *thread = al->thread; - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; unsigned int type = output_type(attr->type); - struct perf_evsel_script *es = evsel->priv; + struct evsel_script *es = evsel->priv; FILE *fp = es->fp; if (output[type].fields == 0) @@ -1804,6 +1812,9 @@ static void process_event(struct perf_script *script, if (!show_event(sample, evsel, thread, al)) return; + if (evswitch__discard(&script->evswitch, evsel)) + return; + ++es->samples; perf_sample__fprintf_start(sample, thread, evsel, @@ -1897,9 +1908,9 @@ static void process_event(struct perf_script *script, static struct scripting_ops *scripting_ops; -static void __process_stat(struct perf_evsel *counter, u64 tstamp) +static void __process_stat(struct evsel *counter, u64 tstamp) { - int nthreads = thread_map__nr(counter->threads); + int nthreads = perf_thread_map__nr(counter->core.threads); int ncpus = perf_evsel__nr_cpus(counter); int cpu, thread; static int header_printed; @@ -1920,8 +1931,8 @@ static void __process_stat(struct perf_evsel *counter, u64 tstamp) counts = perf_counts(counter->counts, cpu, thread); printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n", - counter->cpus->map[cpu], - thread_map__pid(counter->threads, thread), + counter->core.cpus->map[cpu], + perf_thread_map__pid(counter->core.threads, thread), counts->val, counts->ena, counts->run, @@ -1931,7 +1942,7 @@ static void __process_stat(struct perf_evsel *counter, u64 tstamp) } } -static void process_stat(struct perf_evsel *counter, u64 tstamp) +static void process_stat(struct evsel *counter, u64 tstamp) { if (scripting_ops && scripting_ops->process_stat) scripting_ops->process_stat(&stat_config, counter, tstamp); @@ -1973,7 +1984,7 @@ static bool filter_cpu(struct perf_sample *sample) static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct perf_script *scr = container_of(tool, struct perf_script, tool); @@ -2018,13 +2029,13 @@ out_put: } static int process_attr(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist) + struct evlist **pevlist) { struct perf_script *scr = container_of(tool, struct perf_script, tool); - struct perf_evlist *evlist; - struct perf_evsel *evsel, *pos; + struct evlist *evlist; + struct evsel *evsel, *pos; int err; - static struct perf_evsel_script *es; + static struct evsel_script *es; err = perf_event__process_attr(tool, event, pevlist); if (err) @@ -2046,18 +2057,18 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, } } - if (evsel->attr.type >= PERF_TYPE_MAX && - evsel->attr.type != PERF_TYPE_SYNTH) + if (evsel->core.attr.type >= PERF_TYPE_MAX && + evsel->core.attr.type != PERF_TYPE_SYNTH) return 0; evlist__for_each_entry(evlist, pos) { - if (pos->attr.type == evsel->attr.type && pos != evsel) + if (pos->core.attr.type == evsel->core.attr.type && pos != evsel) return 0; } - set_print_ip_opts(&evsel->attr); + set_print_ip_opts(&evsel->core.attr); - if (evsel->attr.sample_type) + if (evsel->core.attr.sample_type) err = perf_evsel__check_attr(evsel, scr->session); return err; @@ -2071,7 +2082,7 @@ static int process_comm_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); int ret = -1; thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); @@ -2083,7 +2094,7 @@ static int process_comm_event(struct perf_tool *tool, if (perf_event__process_comm(tool, event, sample, machine) < 0) goto out; - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { sample->cpu = 0; sample->time = 0; sample->tid = event->comm.tid; @@ -2108,7 +2119,7 @@ static int process_namespaces_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); int ret = -1; thread = machine__findnew_thread(machine, event->namespaces.pid, @@ -2121,7 +2132,7 @@ static int process_namespaces_event(struct perf_tool *tool, if (perf_event__process_namespaces(tool, event, sample, machine) < 0) goto out; - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { sample->cpu = 0; sample->time = 0; sample->tid = event->namespaces.tid; @@ -2146,7 +2157,7 @@ static int process_fork_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); if (perf_event__process_fork(tool, event, sample, machine) < 0) return -1; @@ -2157,7 +2168,7 @@ static int process_fork_event(struct perf_tool *tool, return -1; } - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { sample->cpu = 0; sample->time = event->fork.time; sample->tid = event->fork.tid; @@ -2181,7 +2192,7 @@ static int process_exit_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid); if (thread == NULL) { @@ -2189,7 +2200,7 @@ static int process_exit_event(struct perf_tool *tool, return -1; } - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { sample->cpu = 0; sample->time = 0; sample->tid = event->fork.tid; @@ -2216,7 +2227,7 @@ static int process_mmap_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); if (perf_event__process_mmap(tool, event, sample, machine) < 0) return -1; @@ -2227,7 +2238,7 @@ static int process_mmap_event(struct perf_tool *tool, return -1; } - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { sample->cpu = 0; sample->time = 0; sample->tid = event->mmap.tid; @@ -2250,7 +2261,7 @@ static int process_mmap2_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); if (perf_event__process_mmap2(tool, event, sample, machine) < 0) return -1; @@ -2261,7 +2272,7 @@ static int process_mmap2_event(struct perf_tool *tool, return -1; } - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { sample->cpu = 0; sample->time = 0; sample->tid = event->mmap2.tid; @@ -2284,7 +2295,7 @@ static int process_switch_event(struct perf_tool *tool, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); if (perf_event__process_switch(tool, event, sample, machine) < 0) return -1; @@ -2319,7 +2330,7 @@ process_lost_event(struct perf_tool *tool, { struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); struct thread *thread; thread = machine__findnew_thread(machine, sample->pid, @@ -2355,12 +2366,12 @@ process_bpf_events(struct perf_tool *tool __maybe_unused, struct thread *thread; struct perf_script *script = container_of(tool, struct perf_script, tool); struct perf_session *session = script->session; - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); if (machine__process_ksymbol(machine, event, sample) < 0) return -1; - if (!evsel->attr.sample_id_all) { + if (!evsel->core.attr.sample_id_all) { perf_event__fprintf(event, stdout); return 0; } @@ -2388,8 +2399,8 @@ static void sig_handler(int sig __maybe_unused) static void perf_script__fclose_per_event_dump(struct perf_script *script) { - struct perf_evlist *evlist = script->session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = script->session->evlist; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (!evsel->priv) @@ -2401,7 +2412,7 @@ static void perf_script__fclose_per_event_dump(struct perf_script *script) static int perf_script__fopen_per_event_dump(struct perf_script *script) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(script->session->evlist, evsel) { /* @@ -2428,8 +2439,8 @@ out_err_fclose: static int perf_script__setup_per_event_dump(struct perf_script *script) { - struct perf_evsel *evsel; - static struct perf_evsel_script es_stdout; + struct evsel *evsel; + static struct evsel_script es_stdout; if (script->per_event_dump) return perf_script__fopen_per_event_dump(script); @@ -2444,10 +2455,10 @@ static int perf_script__setup_per_event_dump(struct perf_script *script) static void perf_script__exit_per_event_dump_stats(struct perf_script *script) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(script->session->evlist, evsel) { - struct perf_evsel_script *es = evsel->priv; + struct evsel_script *es = evsel->priv; perf_evsel_script__fprintf(es, stdout); perf_evsel_script__delete(es); @@ -2484,8 +2495,8 @@ static int __cmd_script(struct perf_script *script) script->tool.finished_round = process_finished_round_event; } if (script->show_bpf_events) { - script->tool.ksymbol = process_bpf_events; - script->tool.bpf_event = process_bpf_events; + script->tool.ksymbol = process_bpf_events; + script->tool.bpf = process_bpf_events; } if (perf_script__setup_per_event_dump(script)) { @@ -3003,7 +3014,7 @@ static int check_ev_match(char *dir_name, char *scriptname, { char filename[MAXPATHLEN], evname[128]; char line[BUFSIZ], *p; - struct perf_evsel *pos; + struct evsel *pos; int match, len; FILE *fp; @@ -3235,8 +3246,8 @@ static void script__setup_sample_type(struct perf_script *script) static int process_stat_round_event(struct perf_session *session, union perf_event *event) { - struct stat_round_event *round = &event->stat_round; - struct perf_evsel *counter; + struct perf_record_stat_round *round = &event->stat_round; + struct evsel *counter; evlist__for_each_entry(session->evlist, counter) { perf_stat_process_counter(&stat_config, counter); @@ -3256,7 +3267,7 @@ static int process_stat_config_event(struct perf_session *session __maybe_unused static int set_maps(struct perf_script *script) { - struct perf_evlist *evlist = script->session->evlist; + struct evlist *evlist = script->session->evlist; if (!script->cpus || !script->threads) return 0; @@ -3264,7 +3275,7 @@ static int set_maps(struct perf_script *script) if (WARN_ONCE(script->allocated, "stats double allocation\n")) return -EINVAL; - perf_evlist__set_maps(evlist, script->cpus, script->threads); + perf_evlist__set_maps(&evlist->core, script->cpus, script->threads); if (perf_evlist__alloc_stats(evlist, true)) return -ENOMEM; @@ -3537,6 +3548,7 @@ int cmd_script(int argc, const char **argv) "file", "file saving guest os /proc/kallsyms"), OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, "file", "file saving guest os /proc/modules"), + OPTS_EVSWITCH(&script.evswitch), OPT_END() }; const char * const script_subcommands[] = { "record", "report", NULL }; @@ -3861,6 +3873,10 @@ int cmd_script(int argc, const char **argv) script.range_num); } + err = evswitch__init(&script.evswitch, session->evlist, stderr); + if (err) + goto out_delete; + err = __cmd_script(&script); flush_scripting(); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 352cf39d7c2f..7e17bf9f700a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -40,8 +40,8 @@ * Jaswinder Singh Rajput <jaswinder@kernel.org> */ -#include "perf.h" #include "builtin.h" +#include "perf.h" #include "util/cgroup.h" #include <subcmd/parse-options.h> #include "util/parse-events.h" @@ -54,7 +54,6 @@ #include "util/stat.h" #include "util/header.h" #include "util/cpumap.h" -#include "util/thread.h" #include "util/thread_map.h" #include "util/counts.h" #include "util/group.h" @@ -62,6 +61,8 @@ #include "util/tool.h" #include "util/string2.h" #include "util/metricgroup.h" +#include "util/target.h" +#include "util/time-utils.h" #include "util/top.h" #include "asm/bug.h" @@ -83,6 +84,7 @@ #include <sys/resource.h> #include <linux/ctype.h> +#include <perf/evlist.h> #define DEFAULT_SEPARATOR " " #define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" @@ -130,7 +132,7 @@ static const char *smi_cost_attrs = { "}" }; -static struct perf_evlist *evsel_list; +static struct evlist *evsel_list; static struct target target = { .uid = UINT_MAX, @@ -164,8 +166,8 @@ struct perf_stat { u64 bytes_written; struct perf_tool tool; bool maps_allocated; - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; enum aggr_mode aggr_mode; }; @@ -234,7 +236,7 @@ static int write_stat_round_event(u64 tm, u64 type) #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) static int -perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread, +perf_evsel__write_stat_event(struct evsel *counter, u32 cpu, u32 thread, struct perf_counts_values *count) { struct perf_sample_id *sid = SID(counter, cpu, thread); @@ -243,7 +245,7 @@ perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread, process_synthesized_event, NULL); } -static int read_single_counter(struct perf_evsel *counter, int cpu, +static int read_single_counter(struct evsel *counter, int cpu, int thread, struct timespec *rs) { if (counter->tool_event == PERF_TOOL_DURATION_TIME) { @@ -261,9 +263,9 @@ static int read_single_counter(struct perf_evsel *counter, int cpu, * Read out the results of a single counter: * do not aggregate counts across CPUs in system-wide mode */ -static int read_counter(struct perf_evsel *counter, struct timespec *rs) +static int read_counter(struct evsel *counter, struct timespec *rs) { - int nthreads = thread_map__nr(evsel_list->threads); + int nthreads = perf_thread_map__nr(evsel_list->core.threads); int ncpus, cpu, thread; if (target__has_cpu(&target) && !target__has_per_thread(&target)) @@ -287,7 +289,7 @@ static int read_counter(struct perf_evsel *counter, struct timespec *rs) * The leader's group read loads data into its group members * (via perf_evsel__read_counter) and sets threir count->loaded. */ - if (!count->loaded && + if (!perf_counts__is_loaded(counter->counts, cpu, thread) && read_single_counter(counter, cpu, thread, rs)) { counter->counts->scaled = -1; perf_counts(counter->counts, cpu, thread)->ena = 0; @@ -295,7 +297,7 @@ static int read_counter(struct perf_evsel *counter, struct timespec *rs) return -1; } - count->loaded = false; + perf_counts__set_loaded(counter->counts, cpu, thread, false); if (STAT_RECORD) { if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { @@ -319,7 +321,7 @@ static int read_counter(struct perf_evsel *counter, struct timespec *rs) static void read_counters(struct timespec *rs) { - struct perf_evsel *counter; + struct evsel *counter; int ret; evlist__for_each_entry(evsel_list, counter) { @@ -362,7 +364,7 @@ static void enable_counters(void) * - we have initial delay configured */ if (!target__none(&target) || stat_config.initial_delay) - perf_evlist__enable(evsel_list); + evlist__enable(evsel_list); } static void disable_counters(void) @@ -373,7 +375,7 @@ static void disable_counters(void) * from counting before reading their constituent counters. */ if (!target__none(&target)) - perf_evlist__disable(evsel_list); + evlist__disable(evsel_list); } static volatile int workload_exec_errno; @@ -389,13 +391,13 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf workload_exec_errno = info->si_value.sival_int; } -static bool perf_evsel__should_store_id(struct perf_evsel *counter) +static bool perf_evsel__should_store_id(struct evsel *counter) { - return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; + return STAT_RECORD || counter->core.attr.read_format & PERF_FORMAT_ID; } static bool is_target_alive(struct target *_target, - struct thread_map *threads) + struct perf_thread_map *threads) { struct stat st; int i; @@ -423,7 +425,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) int timeout = stat_config.timeout; char msg[BUFSIZ]; unsigned long long t0, t1; - struct perf_evsel *counter; + struct evsel *counter; struct timespec ts; size_t l; int status = 0; @@ -478,22 +480,22 @@ try_again: counter->supported = false; if ((counter->leader != counter) || - !(counter->leader->nr_members > 1)) + !(counter->leader->core.nr_members > 1)) continue; } else if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { if (verbose > 0) ui__warning("%s\n", msg); goto try_again; } else if (target__has_per_thread(&target) && - evsel_list->threads && - evsel_list->threads->err_thread != -1) { + evsel_list->core.threads && + evsel_list->core.threads->err_thread != -1) { /* * For global --per-thread case, skip current * error thread. */ - if (!thread_map__remove(evsel_list->threads, - evsel_list->threads->err_thread)) { - evsel_list->threads->err_thread = -1; + if (!thread_map__remove(evsel_list->core.threads, + evsel_list->core.threads->err_thread)) { + evsel_list->core.threads->err_thread = -1; goto try_again; } } @@ -579,7 +581,7 @@ try_again: enable_counters(); while (!done) { nanosleep(&ts, NULL); - if (!is_target_alive(&target, evsel_list->threads)) + if (!is_target_alive(&target, evsel_list->core.threads)) break; if (timeout) break; @@ -613,7 +615,7 @@ try_again: * later the evsel_list will be closed after. */ if (!STAT_RECORD) - perf_evlist__close(evsel_list); + evlist__close(evsel_list); return WEXITSTATUS(status); } @@ -803,24 +805,24 @@ static struct option stat_options[] = { }; static int perf_stat__get_socket(struct perf_stat_config *config __maybe_unused, - struct cpu_map *map, int cpu) + struct perf_cpu_map *map, int cpu) { return cpu_map__get_socket(map, cpu, NULL); } static int perf_stat__get_die(struct perf_stat_config *config __maybe_unused, - struct cpu_map *map, int cpu) + struct perf_cpu_map *map, int cpu) { return cpu_map__get_die(map, cpu, NULL); } static int perf_stat__get_core(struct perf_stat_config *config __maybe_unused, - struct cpu_map *map, int cpu) + struct perf_cpu_map *map, int cpu) { return cpu_map__get_core(map, cpu, NULL); } -static int cpu_map__get_max(struct cpu_map *map) +static int cpu_map__get_max(struct perf_cpu_map *map) { int i, max = -1; @@ -833,7 +835,7 @@ static int cpu_map__get_max(struct cpu_map *map) } static int perf_stat__get_aggr(struct perf_stat_config *config, - aggr_get_id_t get_id, struct cpu_map *map, int idx) + aggr_get_id_t get_id, struct perf_cpu_map *map, int idx) { int cpu; @@ -849,26 +851,26 @@ static int perf_stat__get_aggr(struct perf_stat_config *config, } static int perf_stat__get_socket_cached(struct perf_stat_config *config, - struct cpu_map *map, int idx) + struct perf_cpu_map *map, int idx) { return perf_stat__get_aggr(config, perf_stat__get_socket, map, idx); } static int perf_stat__get_die_cached(struct perf_stat_config *config, - struct cpu_map *map, int idx) + struct perf_cpu_map *map, int idx) { return perf_stat__get_aggr(config, perf_stat__get_die, map, idx); } static int perf_stat__get_core_cached(struct perf_stat_config *config, - struct cpu_map *map, int idx) + struct perf_cpu_map *map, int idx) { return perf_stat__get_aggr(config, perf_stat__get_core, map, idx); } static bool term_percore_set(void) { - struct perf_evsel *counter; + struct evsel *counter; evlist__for_each_entry(evsel_list, counter) { if (counter->percore) @@ -884,21 +886,21 @@ static int perf_stat_init_aggr_mode(void) switch (stat_config.aggr_mode) { case AGGR_SOCKET: - if (cpu_map__build_socket_map(evsel_list->cpus, &stat_config.aggr_map)) { + if (cpu_map__build_socket_map(evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build socket map"); return -1; } stat_config.aggr_get_id = perf_stat__get_socket_cached; break; case AGGR_DIE: - if (cpu_map__build_die_map(evsel_list->cpus, &stat_config.aggr_map)) { + if (cpu_map__build_die_map(evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build die map"); return -1; } stat_config.aggr_get_id = perf_stat__get_die_cached; break; case AGGR_CORE: - if (cpu_map__build_core_map(evsel_list->cpus, &stat_config.aggr_map)) { + if (cpu_map__build_core_map(evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build core map"); return -1; } @@ -906,7 +908,7 @@ static int perf_stat_init_aggr_mode(void) break; case AGGR_NONE: if (term_percore_set()) { - if (cpu_map__build_core_map(evsel_list->cpus, + if (cpu_map__build_core_map(evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build core map"); return -1; @@ -926,20 +928,20 @@ static int perf_stat_init_aggr_mode(void) * taking the highest cpu number to be the size of * the aggregation translate cpumap. */ - nr = cpu_map__get_max(evsel_list->cpus); - stat_config.cpus_aggr_map = cpu_map__empty_new(nr + 1); + nr = cpu_map__get_max(evsel_list->core.cpus); + stat_config.cpus_aggr_map = perf_cpu_map__empty_new(nr + 1); return stat_config.cpus_aggr_map ? 0 : -ENOMEM; } static void perf_stat__exit_aggr_mode(void) { - cpu_map__put(stat_config.aggr_map); - cpu_map__put(stat_config.cpus_aggr_map); + perf_cpu_map__put(stat_config.aggr_map); + perf_cpu_map__put(stat_config.cpus_aggr_map); stat_config.aggr_map = NULL; stat_config.cpus_aggr_map = NULL; } -static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx) +static inline int perf_env__get_cpu(struct perf_env *env, struct perf_cpu_map *map, int idx) { int cpu; @@ -954,7 +956,7 @@ static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, i return cpu; } -static int perf_env__get_socket(struct cpu_map *map, int idx, void *data) +static int perf_env__get_socket(struct perf_cpu_map *map, int idx, void *data) { struct perf_env *env = data; int cpu = perf_env__get_cpu(env, map, idx); @@ -962,7 +964,7 @@ static int perf_env__get_socket(struct cpu_map *map, int idx, void *data) return cpu == -1 ? -1 : env->cpu[cpu].socket_id; } -static int perf_env__get_die(struct cpu_map *map, int idx, void *data) +static int perf_env__get_die(struct perf_cpu_map *map, int idx, void *data) { struct perf_env *env = data; int die_id = -1, cpu = perf_env__get_cpu(env, map, idx); @@ -986,7 +988,7 @@ static int perf_env__get_die(struct cpu_map *map, int idx, void *data) return die_id; } -static int perf_env__get_core(struct cpu_map *map, int idx, void *data) +static int perf_env__get_core(struct perf_cpu_map *map, int idx, void *data) { struct perf_env *env = data; int core = -1, cpu = perf_env__get_cpu(env, map, idx); @@ -1016,37 +1018,37 @@ static int perf_env__get_core(struct cpu_map *map, int idx, void *data) return core; } -static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus, - struct cpu_map **sockp) +static int perf_env__build_socket_map(struct perf_env *env, struct perf_cpu_map *cpus, + struct perf_cpu_map **sockp) { return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env); } -static int perf_env__build_die_map(struct perf_env *env, struct cpu_map *cpus, - struct cpu_map **diep) +static int perf_env__build_die_map(struct perf_env *env, struct perf_cpu_map *cpus, + struct perf_cpu_map **diep) { return cpu_map__build_map(cpus, diep, perf_env__get_die, env); } -static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus, - struct cpu_map **corep) +static int perf_env__build_core_map(struct perf_env *env, struct perf_cpu_map *cpus, + struct perf_cpu_map **corep) { return cpu_map__build_map(cpus, corep, perf_env__get_core, env); } static int perf_stat__get_socket_file(struct perf_stat_config *config __maybe_unused, - struct cpu_map *map, int idx) + struct perf_cpu_map *map, int idx) { return perf_env__get_socket(map, idx, &perf_stat.session->header.env); } static int perf_stat__get_die_file(struct perf_stat_config *config __maybe_unused, - struct cpu_map *map, int idx) + struct perf_cpu_map *map, int idx) { return perf_env__get_die(map, idx, &perf_stat.session->header.env); } static int perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused, - struct cpu_map *map, int idx) + struct perf_cpu_map *map, int idx) { return perf_env__get_core(map, idx, &perf_stat.session->header.env); } @@ -1057,21 +1059,21 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st) switch (stat_config.aggr_mode) { case AGGR_SOCKET: - if (perf_env__build_socket_map(env, evsel_list->cpus, &stat_config.aggr_map)) { + if (perf_env__build_socket_map(env, evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build socket map"); return -1; } stat_config.aggr_get_id = perf_stat__get_socket_file; break; case AGGR_DIE: - if (perf_env__build_die_map(env, evsel_list->cpus, &stat_config.aggr_map)) { + if (perf_env__build_die_map(env, evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build die map"); return -1; } stat_config.aggr_get_id = perf_stat__get_die_file; break; case AGGR_CORE: - if (perf_env__build_core_map(env, evsel_list->cpus, &stat_config.aggr_map)) { + if (perf_env__build_core_map(env, evsel_list->core.cpus, &stat_config.aggr_map)) { perror("cannot build core map"); return -1; } @@ -1366,7 +1368,7 @@ static int add_default_attributes(void) free(str); } - if (!evsel_list->nr_entries) { + if (!evsel_list->core.nr_entries) { if (target__has_cpu(&target)) default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK; @@ -1461,8 +1463,8 @@ static int __cmd_record(int argc, const char **argv) static int process_stat_round_event(struct perf_session *session, union perf_event *event) { - struct stat_round_event *stat_round = &event->stat_round; - struct perf_evsel *counter; + struct perf_record_stat_round *stat_round = &event->stat_round; + struct evsel *counter; struct timespec tsh, *ts = NULL; const char **argv = session->header.env.cmdline_argv; int argc = session->header.env.nr_cmdline; @@ -1492,7 +1494,7 @@ int process_stat_config_event(struct perf_session *session, perf_event__read_stat_config(&stat_config, &event->stat_config); - if (cpu_map__empty(st->cpus)) { + if (perf_cpu_map__empty(st->cpus)) { if (st->aggr_mode != AGGR_UNSET) pr_warning("warning: processing task data, aggregation mode not set\n"); return 0; @@ -1517,7 +1519,7 @@ static int set_maps(struct perf_stat *st) if (WARN_ONCE(st->maps_allocated, "stats double allocation\n")) return -EINVAL; - perf_evlist__set_maps(evsel_list, st->cpus, st->threads); + perf_evlist__set_maps(&evsel_list->core, st->cpus, st->threads); if (perf_evlist__alloc_stats(evsel_list, true)) return -ENOMEM; @@ -1551,7 +1553,7 @@ int process_cpu_map_event(struct perf_session *session, { struct perf_tool *tool = session->tool; struct perf_stat *st = container_of(tool, struct perf_stat, tool); - struct cpu_map *cpus; + struct perf_cpu_map *cpus; if (st->cpus) { pr_warning("Extra cpu map event, ignoring.\n"); @@ -1676,14 +1678,14 @@ static void setup_system_wide(int forks) if (!forks) target.system_wide = true; else { - struct perf_evsel *counter; + struct evsel *counter; evlist__for_each_entry(evsel_list, counter) { if (!counter->system_wide) return; } - if (evsel_list->nr_entries) + if (evsel_list->core.nr_entries) target.system_wide = true; } } @@ -1702,7 +1704,7 @@ int cmd_stat(int argc, const char **argv) setlocale(LC_ALL, ""); - evsel_list = perf_evlist__new(); + evsel_list = evlist__new(); if (evsel_list == NULL) return -ENOMEM; @@ -1889,10 +1891,10 @@ int cmd_stat(int argc, const char **argv) * so we could print it out on output. */ if (stat_config.aggr_mode == AGGR_THREAD) { - thread_map__read_comms(evsel_list->threads); + thread_map__read_comms(evsel_list->core.threads); if (target.system_wide) { if (runtime_stat_new(&stat_config, - thread_map__nr(evsel_list->threads))) { + perf_thread_map__nr(evsel_list->core.threads))) { goto out; } } @@ -2003,7 +2005,7 @@ int cmd_stat(int argc, const char **argv) perf_session__write_header(perf_stat.session, evsel_list, fd, true); } - perf_evlist__close(evsel_list); + evlist__close(evsel_list); perf_session__delete(perf_stat.session); } @@ -2015,7 +2017,7 @@ out: if (smi_cost && smi_reset) sysfs__write_int(FREEZE_ON_SMI_PATH, 0); - perf_evlist__delete(evsel_list); + evlist__delete(evsel_list); runtime_stat_delete(&stat_config); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4bde3fa245d1..e0e822695a29 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -10,13 +10,11 @@ #include <errno.h> #include <inttypes.h> -#include <traceevent/event-parse.h> #include "builtin.h" #include "util/color.h" #include <linux/list.h> -#include "util/cache.h" -#include "util/evlist.h" +#include "util/evlist.h" // for struct evsel_str_handler #include "util/evsel.h" #include <linux/kernel.h> #include <linux/rbtree.h> @@ -28,6 +26,7 @@ #include "perf.h" #include "util/header.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "util/parse-events.h" #include "util/event.h" @@ -545,19 +544,19 @@ exit: } typedef int (*tracepoint_handler)(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace); static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct timechart *tchart = container_of(tool, struct timechart, tool); - if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { + if (evsel->core.attr.sample_type & PERF_SAMPLE_TIME) { if (!tchart->first_time || tchart->first_time > sample->time) tchart->first_time = sample->time; if (tchart->last_time < sample->time) @@ -575,7 +574,7 @@ static int process_sample_event(struct perf_tool *tool, static int process_sample_cpu_idle(struct timechart *tchart __maybe_unused, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace __maybe_unused) { @@ -591,7 +590,7 @@ process_sample_cpu_idle(struct timechart *tchart __maybe_unused, static int process_sample_cpu_frequency(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace __maybe_unused) { @@ -604,7 +603,7 @@ process_sample_cpu_frequency(struct timechart *tchart, static int process_sample_sched_wakeup(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace) { @@ -618,7 +617,7 @@ process_sample_sched_wakeup(struct timechart *tchart, static int process_sample_sched_switch(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace) { @@ -634,7 +633,7 @@ process_sample_sched_switch(struct timechart *tchart, #ifdef SUPPORT_OLD_POWER_EVENTS static int process_sample_power_start(struct timechart *tchart __maybe_unused, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace __maybe_unused) { @@ -647,7 +646,7 @@ process_sample_power_start(struct timechart *tchart __maybe_unused, static int process_sample_power_end(struct timechart *tchart, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct perf_sample *sample, const char *backtrace __maybe_unused) { @@ -657,7 +656,7 @@ process_sample_power_end(struct timechart *tchart, static int process_sample_power_frequency(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, const char *backtrace __maybe_unused) { @@ -840,7 +839,7 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, static int process_enter_read(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long fd = perf_evsel__intval(evsel, sample, "fd"); @@ -850,7 +849,7 @@ process_enter_read(struct timechart *tchart, static int process_exit_read(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long ret = perf_evsel__intval(evsel, sample, "ret"); @@ -860,7 +859,7 @@ process_exit_read(struct timechart *tchart, static int process_enter_write(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long fd = perf_evsel__intval(evsel, sample, "fd"); @@ -870,7 +869,7 @@ process_enter_write(struct timechart *tchart, static int process_exit_write(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long ret = perf_evsel__intval(evsel, sample, "ret"); @@ -880,7 +879,7 @@ process_exit_write(struct timechart *tchart, static int process_enter_sync(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long fd = perf_evsel__intval(evsel, sample, "fd"); @@ -890,7 +889,7 @@ process_enter_sync(struct timechart *tchart, static int process_exit_sync(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long ret = perf_evsel__intval(evsel, sample, "ret"); @@ -900,7 +899,7 @@ process_exit_sync(struct timechart *tchart, static int process_enter_tx(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long fd = perf_evsel__intval(evsel, sample, "fd"); @@ -910,7 +909,7 @@ process_enter_tx(struct timechart *tchart, static int process_exit_tx(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long ret = perf_evsel__intval(evsel, sample, "ret"); @@ -920,7 +919,7 @@ process_exit_tx(struct timechart *tchart, static int process_enter_rx(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long fd = perf_evsel__intval(evsel, sample, "fd"); @@ -930,7 +929,7 @@ process_enter_rx(struct timechart *tchart, static int process_exit_rx(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long ret = perf_evsel__intval(evsel, sample, "ret"); @@ -940,7 +939,7 @@ process_exit_rx(struct timechart *tchart, static int process_enter_poll(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long fd = perf_evsel__intval(evsel, sample, "fd"); @@ -950,7 +949,7 @@ process_enter_poll(struct timechart *tchart, static int process_exit_poll(struct timechart *tchart, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { long ret = perf_evsel__intval(evsel, sample, "ret"); @@ -1518,10 +1517,7 @@ static int process_header(struct perf_file_section *section __maybe_unused, if (!tchart->topology) break; - if (svg_build_topology_map(ph->env.sibling_cores, - ph->env.nr_sibling_cores, - ph->env.sibling_threads, - ph->env.nr_sibling_threads)) + if (svg_build_topology_map(&ph->env)) fprintf(stderr, "problem building topology\n"); break; @@ -1534,7 +1530,7 @@ static int process_header(struct perf_file_section *section __maybe_unused, static int __cmd_timechart(struct timechart *tchart, const char *output_name) { - const struct perf_evsel_str_handler power_tracepoints[] = { + const struct evsel_str_handler power_tracepoints[] = { { "power:cpu_idle", process_sample_cpu_idle }, { "power:cpu_frequency", process_sample_cpu_frequency }, { "sched:sched_wakeup", process_sample_sched_wakeup }, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b46b3c9f57a0..726e3f2dd8c7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -24,6 +24,7 @@ #include "util/bpf-event.h" #include "util/config.h" #include "util/color.h" +#include "util/dso.h" #include "util/evlist.h" #include "util/evsel.h" #include "util/event.h" @@ -31,20 +32,20 @@ #include "util/map.h" #include "util/session.h" #include "util/symbol.h" -#include "util/thread.h" -#include "util/thread_map.h" #include "util/top.h" +#include "util/util.h" #include <linux/rbtree.h> #include <subcmd/parse-options.h> #include "util/parse-events.h" +#include "util/callchain.h" #include "util/cpumap.h" -#include "util/xyarray.h" #include "util/sort.h" #include "util/string2.h" #include "util/term.h" #include "util/intlist.h" #include "util/parse-branch-options.h" #include "arch/common.h" +#include "ui/ui.h" #include "util/debug.h" #include "util/ordered-events.h" @@ -101,7 +102,7 @@ static void perf_top__resize(struct perf_top *top) static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) { - struct perf_evsel *evsel; + struct evsel *evsel; struct symbol *sym; struct annotation *notes; struct map *map; @@ -129,7 +130,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) notes = symbol__annotation(sym); pthread_mutex_lock(¬es->lock); - if (!symbol__hists(sym, top->evlist->nr_entries)) { + if (!symbol__hists(sym, top->evlist->core.nr_entries)) { pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -186,7 +187,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) static void perf_top__record_precise_ip(struct perf_top *top, struct hist_entry *he, struct perf_sample *sample, - struct perf_evsel *evsel, u64 ip) + struct evsel *evsel, u64 ip) { struct annotation *notes; struct symbol *sym = he->ms.sym; @@ -228,7 +229,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, static void perf_top__show_details(struct perf_top *top) { struct hist_entry *he = top->sym_filter_entry; - struct perf_evsel *evsel; + struct evsel *evsel; struct annotation *notes; struct symbol *symbol; int more; @@ -265,12 +266,52 @@ out_unlock: pthread_mutex_unlock(¬es->lock); } +static void perf_top__resort_hists(struct perf_top *t) +{ + struct evlist *evlist = t->evlist; + struct evsel *pos; + + evlist__for_each_entry(evlist, pos) { + struct hists *hists = evsel__hists(pos); + + /* + * unlink existing entries so that they can be linked + * in a correct order in hists__match() below. + */ + hists__unlink(hists); + + if (evlist->enabled) { + if (t->zero) { + hists__delete_entries(hists); + } else { + hists__decay_entries(hists, t->hide_user_symbols, + t->hide_kernel_symbols); + } + } + + hists__collapse_resort(hists, NULL); + + /* Non-group events are considered as leader */ + if (symbol_conf.event_group && + !perf_evsel__is_group_leader(pos)) { + struct hists *leader_hists = evsel__hists(pos->leader); + + hists__match(leader_hists, hists); + hists__link(leader_hists, hists); + } + } + + evlist__for_each_entry(evlist, pos) { + perf_evsel__output_resort(pos, NULL); + } +} + static void perf_top__print_sym_table(struct perf_top *top) { char bf[160]; int printed = 0; const int win_width = top->winsize.ws_col - 1; - struct perf_evsel *evsel = top->sym_evsel; + struct evsel *evsel = top->sym_evsel; struct hists *hists = evsel__hists(evsel); puts(CONSOLE_CLEAR); @@ -296,17 +337,7 @@ static void perf_top__print_sym_table(struct perf_top *top) return; } - if (top->evlist->enabled) { - if (top->zero) { - hists__delete_entries(hists); - } else { - hists__decay_entries(hists, top->hide_user_symbols, - top->hide_kernel_symbols); - } - } - - hists__collapse_resort(hists, NULL); - perf_evsel__output_resort(evsel, NULL); + perf_top__resort_hists(top); hists__output_recalc_col_len(hists, top->print_entries - printed); putchar('\n'); @@ -404,7 +435,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); - if (top->evlist->nr_entries > 1) + if (top->evlist->core.nr_entries > 1) fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel)); fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); @@ -439,7 +470,7 @@ static int perf_top__key_mapped(struct perf_top *top, int c) case 'S': return 1; case 'E': - return top->evlist->nr_entries > 1 ? 1 : 0; + return top->evlist->core.nr_entries > 1 ? 1 : 0; default: break; } @@ -485,7 +516,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) } break; case 'E': - if (top->evlist->nr_entries > 1) { + if (top->evlist->core.nr_entries > 1) { /* Select 0 as the default event: */ int counter = 0; @@ -496,7 +527,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) prompt_integer(&counter, "Enter details event counter"); - if (counter >= top->evlist->nr_entries) { + if (counter >= top->evlist->core.nr_entries) { top->sym_evsel = perf_evlist__first(top->evlist); fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel)); sleep(1); @@ -554,25 +585,11 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) static void perf_top__sort_new_samples(void *arg) { struct perf_top *t = arg; - struct perf_evsel *evsel = t->sym_evsel; - struct hists *hists; if (t->evlist->selected != NULL) t->sym_evsel = t->evlist->selected; - hists = evsel__hists(evsel); - - if (t->evlist->enabled) { - if (t->zero) { - hists__delete_entries(hists); - } else { - hists__decay_entries(hists, t->hide_user_symbols, - t->hide_kernel_symbols); - } - } - - hists__collapse_resort(hists, NULL); - perf_evsel__output_resort(evsel, NULL); + perf_top__resort_hists(t); if (t->lost || t->drop) pr_warning("Too slow to read ring buffer (change period (-c/-F) or limit CPUs (-C)\n"); @@ -586,7 +603,7 @@ static void stop_top(void) static void *display_thread_tui(void *arg) { - struct perf_evsel *pos; + struct evsel *pos; struct perf_top *top = arg; const char *help = "For a higher level overview, try: perf top --sort comm,dso"; struct hist_browser_timer hbt = { @@ -602,6 +619,8 @@ static void *display_thread_tui(void *arg) */ unshare(CLONE_FS); + prctl(PR_SET_NAME, "perf-top-UI", 0, 0, 0); + perf_top__sort_new_samples(top); /* @@ -652,6 +671,8 @@ static void *display_thread(void *arg) */ unshare(CLONE_FS); + prctl(PR_SET_NAME, "perf-top-UI", 0, 0, 0); + display_setup_sig(); pthread__unblock_sigwinch(); repeat: @@ -693,7 +714,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, { struct perf_top *top = arg; struct hist_entry *he = iter->he; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; if (perf_hpp_list.sym && single) perf_top__record_precise_ip(top, he, iter->sample, evsel, al->addr); @@ -705,7 +726,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, static void perf_event__process_sample(struct perf_tool *tool, const union perf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { @@ -745,7 +766,7 @@ static void perf_event__process_sample(struct perf_tool *tool, if (!perf_evlist__exclude_kernel(top->session->evlist)) { ui__warning( "Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" -"Check /proc/sys/kernel/kptr_restrict.\n\n" +"Check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n" "Kernel%s samples will not be resolved.\n", al.map && map__has_symbols(al.map) ? " modules" : ""); @@ -813,7 +834,7 @@ static void perf_event__process_sample(struct perf_tool *tool, static void perf_top__process_lost(struct perf_top *top, union perf_event *event, - struct perf_evsel *evsel) + struct evsel *evsel) { struct hists *hists = evsel__hists(evsel); @@ -825,7 +846,7 @@ perf_top__process_lost(struct perf_top *top, union perf_event *event, static void perf_top__process_lost_samples(struct perf_top *top, union perf_event *event, - struct perf_evsel *evsel) + struct evsel *evsel) { struct hists *hists = evsel__hists(evsel); @@ -839,7 +860,7 @@ static u64 last_timestamp; static void perf_top__mmap_read_idx(struct perf_top *top, int idx) { struct record_opts *opts = &top->record_opts; - struct perf_evlist *evlist = top->evlist; + struct evlist *evlist = top->evlist; struct perf_mmap *md; union perf_event *event; @@ -874,7 +895,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) static void perf_top__mmap_read(struct perf_top *top) { bool overwrite = top->record_opts.overwrite; - struct perf_evlist *evlist = top->evlist; + struct evlist *evlist = top->evlist; int i; if (overwrite) @@ -909,10 +930,10 @@ static void perf_top__mmap_read(struct perf_top *top) static int perf_top__overwrite_check(struct perf_top *top) { struct record_opts *opts = &top->record_opts; - struct perf_evlist *evlist = top->evlist; + struct evlist *evlist = top->evlist; struct perf_evsel_config_term *term; struct list_head *config_terms; - struct perf_evsel *evsel; + struct evsel *evsel; int set, overwrite = -1; evlist__for_each_entry(evlist, evsel) { @@ -952,11 +973,11 @@ static int perf_top__overwrite_check(struct perf_top *top) } static int perf_top_overwrite_fallback(struct perf_top *top, - struct perf_evsel *evsel) + struct evsel *evsel) { struct record_opts *opts = &top->record_opts; - struct perf_evlist *evlist = top->evlist; - struct perf_evsel *counter; + struct evlist *evlist = top->evlist; + struct evsel *counter; if (!opts->overwrite) return 0; @@ -966,7 +987,7 @@ static int perf_top_overwrite_fallback(struct perf_top *top, return 0; evlist__for_each_entry(evlist, counter) - counter->attr.write_backward = false; + counter->core.attr.write_backward = false; opts->overwrite = false; pr_debug2("fall back to non-overwrite mode\n"); return 1; @@ -975,8 +996,8 @@ static int perf_top_overwrite_fallback(struct perf_top *top, static int perf_top__start_counters(struct perf_top *top) { char msg[BUFSIZ]; - struct perf_evsel *counter; - struct perf_evlist *evlist = top->evlist; + struct evsel *counter; + struct evlist *evlist = top->evlist; struct record_opts *opts = &top->record_opts; if (perf_top__overwrite_check(top)) { @@ -989,8 +1010,8 @@ static int perf_top__start_counters(struct perf_top *top) evlist__for_each_entry(evlist, counter) { try_again: - if (perf_evsel__open(counter, top->evlist->cpus, - top->evlist->threads) < 0) { + if (evsel__open(counter, top->evlist->core.cpus, + top->evlist->core.threads) < 0) { /* * Specially handle overwrite fall back. @@ -1100,11 +1121,11 @@ static int deliver_event(struct ordered_events *qe, struct ordered_event *qevent) { struct perf_top *top = qe->data; - struct perf_evlist *evlist = top->evlist; + struct evlist *evlist = top->evlist; struct perf_session *session = top->session; union perf_event *event = qevent->event; struct perf_sample sample; - struct perf_evsel *evsel; + struct evsel *evsel; struct machine *machine; int ret = -1; @@ -1123,8 +1144,11 @@ static int deliver_event(struct ordered_events *qe, evsel = perf_evlist__id2evsel(session->evlist, sample.id); assert(evsel != NULL); - if (event->header.type == PERF_RECORD_SAMPLE) + if (event->header.type == PERF_RECORD_SAMPLE) { + if (evswitch__discard(&top->evswitch, evsel)) + return 0; ++top->samples; + } switch (sample.cpumode) { case PERF_RECORD_MISC_USER: @@ -1222,7 +1246,7 @@ static int __cmd_top(struct perf_top *top) pr_debug("Couldn't synthesize BPF events: Pre-existing BPF programs won't have symbols resolved.\n"); machine__synthesize_threads(&top->session->machines.host, &opts->target, - top->evlist->threads, false, + top->evlist->core.threads, false, top->nr_threads_synthesize); if (top->nr_threads_synthesize > 1) @@ -1255,7 +1279,7 @@ static int __cmd_top(struct perf_top *top) * so leave the check here. */ if (!target__none(&opts->target)) - perf_evlist__enable(top->evlist); + evlist__enable(top->evlist); ret = -1; if (pthread_create(&thread_process, NULL, process_thread, top)) { @@ -1509,9 +1533,10 @@ int cmd_top(int argc, const char **argv) "number of thread to run event synthesize"), OPT_BOOLEAN(0, "namespaces", &opts->record_namespaces, "Record namespaces events"), + OPTS_EVSWITCH(&top.evswitch), OPT_END() }; - struct perf_evlist *sb_evlist = NULL; + struct evlist *sb_evlist = NULL; const char * const top_usage[] = { "perf top [<options>]", NULL @@ -1524,7 +1549,7 @@ int cmd_top(int argc, const char **argv) top.annotation_opts.min_pcnt = 5; top.annotation_opts.context = 4; - top.evlist = perf_evlist__new(); + top.evlist = evlist__new(); if (top.evlist == NULL) return -ENOMEM; @@ -1536,12 +1561,16 @@ int cmd_top(int argc, const char **argv) if (argc) usage_with_options(top_usage, options); - if (!top.evlist->nr_entries && + if (!top.evlist->core.nr_entries && perf_evlist__add_default(top.evlist) < 0) { pr_err("Not enough memory for event selector list\n"); goto out_delete_evlist; } + status = evswitch__init(&top.evswitch, top.evlist, stderr); + if (status) + goto out_delete_evlist; + if (symbol_conf.report_hierarchy) { /* disable incompatible options */ symbol_conf.event_group = false; @@ -1661,7 +1690,7 @@ int cmd_top(int argc, const char **argv) perf_evlist__stop_sb_thread(sb_evlist); out_delete_evlist: - perf_evlist__delete(top.evlist); + evlist__delete(top.evlist); perf_session__delete(top.session); return status; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 4f0bbffee05f..0f633f0d6be8 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0-only /* * builtin-trace.c * @@ -15,6 +14,7 @@ * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'") */ +#include "util/record.h" #include <traceevent/event-parse.h> #include <api/fs/tracing_path.h> #include <bpf/bpf.h> @@ -25,9 +25,12 @@ #include "util/color.h" #include "util/config.h" #include "util/debug.h" +#include "util/dso.h" #include "util/env.h" #include "util/event.h" #include "util/evlist.h" +#include "util/evswitch.h" +#include <subcmd/pager.h> #include <subcmd/exec-cmd.h> #include "util/machine.h" #include "util/map.h" @@ -40,6 +43,8 @@ #include "util/intlist.h" #include "util/thread_map.h" #include "util/stat.h" +#include "util/tool.h" +#include "util/util.h" #include "trace/beauty/beauty.h" #include "trace-event.h" #include "util/parse-events.h" @@ -49,6 +54,7 @@ #include "string2.h" #include "syscalltbl.h" #include "rb_resort.h" +#include "../perf.h" #include <errno.h> #include <inttypes.h> @@ -80,28 +86,34 @@ struct trace { struct perf_tool tool; struct syscalltbl *sctbl; struct { - int max; struct syscall *table; struct bpf_map *map; + struct { // per syscall BPF_MAP_TYPE_PROG_ARRAY + struct bpf_map *sys_enter, + *sys_exit; + } prog_array; struct { - struct perf_evsel *sys_enter, + struct evsel *sys_enter, *sys_exit, *augmented; } events; + struct bpf_program *unaugmented_prog; } syscalls; struct { struct bpf_map *map; } dump; struct record_opts opts; - struct perf_evlist *evlist; + struct evlist *evlist; struct machine *host; struct thread *current; + struct bpf_object *bpf_obj; struct cgroup *cgroup; u64 base_time; FILE *output; unsigned long nr_events; unsigned long nr_events_printed; unsigned long max_events; + struct evswitch evswitch; struct strlist *ev_qualifier; struct { size_t nr; @@ -122,6 +134,7 @@ struct trace { unsigned int min_stack; int raw_augmented_syscalls_args_size; bool raw_augmented_syscalls; + bool fd_path_disabled; bool sort_events; bool not_ev_qualifier; bool live; @@ -237,7 +250,7 @@ struct syscall_tp { }; }; -static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel, +static int perf_evsel__init_tp_uint_field(struct evsel *evsel, struct tp_field *field, const char *name) { @@ -253,7 +266,7 @@ static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel, ({ struct syscall_tp *sc = evsel->priv;\ perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); }) -static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, +static int perf_evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field, const char *name) { @@ -269,13 +282,13 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, ({ struct syscall_tp *sc = evsel->priv;\ perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); }) -static void perf_evsel__delete_priv(struct perf_evsel *evsel) +static void evsel__delete_priv(struct evsel *evsel) { zfree(&evsel->priv); - perf_evsel__delete(evsel); + evsel__delete(evsel); } -static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel) +static int perf_evsel__init_syscall_tp(struct evsel *evsel) { struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); @@ -292,7 +305,7 @@ out_delete: return -ENOENT; } -static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel, struct perf_evsel *tp) +static int perf_evsel__init_augmented_syscall_tp(struct evsel *evsel, struct evsel *tp) { struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); @@ -314,21 +327,21 @@ out_delete: return -EINVAL; } -static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel) +static int perf_evsel__init_augmented_syscall_tp_args(struct evsel *evsel) { struct syscall_tp *sc = evsel->priv; return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)); } -static int perf_evsel__init_augmented_syscall_tp_ret(struct perf_evsel *evsel) +static int perf_evsel__init_augmented_syscall_tp_ret(struct evsel *evsel) { struct syscall_tp *sc = evsel->priv; return __tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap); } -static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler) +static int perf_evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler) { evsel->priv = malloc(sizeof(struct syscall_tp)); if (evsel->priv != NULL) { @@ -346,9 +359,9 @@ out_delete: return -ENOENT; } -static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler) +static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler) { - struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); + struct evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */ if (IS_ERR(evsel)) @@ -363,7 +376,7 @@ static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, v return evsel; out_delete: - perf_evsel__delete_priv(evsel); + evsel__delete_priv(evsel); return NULL; } @@ -688,6 +701,10 @@ struct syscall_arg_fmt { static struct syscall_fmt { const char *name; const char *alias; + struct { + const char *sys_enter, + *sys_exit; + } bpf_prog_name; struct syscall_arg_fmt arg[6]; u8 nr_args; bool errpid; @@ -700,7 +717,9 @@ static struct syscall_fmt { .arg = { [0] = { .scnprintf = SCA_X86_ARCH_PRCTL_CODE, /* code */ }, [1] = { .scnprintf = SCA_PTR, /* arg2 */ }, }, }, { .name = "bind", - .arg = { [1] = { .scnprintf = SCA_SOCKADDR, /* umyaddr */ }, }, }, + .arg = { [0] = { .scnprintf = SCA_INT, /* fd */ }, + [1] = { .scnprintf = SCA_SOCKADDR, /* umyaddr */ }, + [2] = { .scnprintf = SCA_INT, /* addrlen */ }, }, }, { .name = "bpf", .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, }, { .name = "brk", .hexret = true, @@ -716,7 +735,9 @@ static struct syscall_fmt { { .name = "close", .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, }, { .name = "connect", - .arg = { [1] = { .scnprintf = SCA_SOCKADDR, /* servaddr */ }, }, }, + .arg = { [0] = { .scnprintf = SCA_INT, /* fd */ }, + [1] = { .scnprintf = SCA_SOCKADDR, /* servaddr */ }, + [2] = { .scnprintf = SCA_INT, /* addrlen */ }, }, }, { .name = "epoll_ctl", .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, }, { .name = "eventfd2", @@ -882,6 +903,7 @@ static struct syscall_fmt { .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ }, [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, }, { .name = "select", .timeout = true, }, + { .name = "sendfile", .alias = "sendfile64", }, { .name = "sendmmsg", .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "sendmsg", @@ -960,13 +982,19 @@ static struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias) * is_exit: is this "exit" or "exit_group"? * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. * args_size: sum of the sizes of the syscall arguments, anything after that is augmented stuff: pathname for openat, etc. + * nonexistent: Just a hole in the syscall table, syscall id not allocated */ struct syscall { struct tep_event *tp_format; int nr_args; int args_size; + struct { + struct bpf_program *sys_enter, + *sys_exit; + } bpf_prog; bool is_exit; bool is_open; + bool nonexistent; struct tep_format_field *args; const char *name; struct syscall_fmt *fmt; @@ -1163,7 +1191,7 @@ static const char *thread__fd_path(struct thread *thread, int fd, { struct thread_trace *ttrace = thread__priv(thread); - if (ttrace == NULL) + if (ttrace == NULL || trace->fd_path_disabled) return NULL; if (fd < 0) @@ -1359,7 +1387,7 @@ static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long l if (symbol_conf.kptr_restrict) { pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" - "Check /proc/sys/kernel/kptr_restrict.\n\n" + "Check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n" "Kernel samples will not be resolved.\n"); machine->kptr_restrict_warned = true; return NULL; @@ -1368,7 +1396,7 @@ static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long l return machine__resolve_kernel_addr(vmachine, addrp, modp); } -static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) +static int trace__symbols_init(struct trace *trace, struct evlist *evlist) { int err = symbol__init(NULL); @@ -1384,7 +1412,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) goto out; err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, - evlist->threads, trace__tool_process, false, + evlist->core.threads, trace__tool_process, false, 1); out: if (err) @@ -1471,29 +1499,22 @@ static int trace__read_syscall_info(struct trace *trace, int id) struct syscall *sc; const char *name = syscalltbl__name(trace->sctbl, id); - if (name == NULL) - return -1; - - if (id > trace->syscalls.max) { - struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); - - if (nsyscalls == NULL) - return -1; + if (trace->syscalls.table == NULL) { + trace->syscalls.table = calloc(trace->sctbl->syscalls.max_id + 1, sizeof(*sc)); + if (trace->syscalls.table == NULL) + return -ENOMEM; + } - if (trace->syscalls.max != -1) { - memset(nsyscalls + trace->syscalls.max + 1, 0, - (id - trace->syscalls.max) * sizeof(*sc)); - } else { - memset(nsyscalls, 0, (id + 1) * sizeof(*sc)); - } + sc = trace->syscalls.table + id; + if (sc->nonexistent) + return 0; - trace->syscalls.table = nsyscalls; - trace->syscalls.max = id; + if (name == NULL) { + sc->nonexistent = true; + return 0; } - sc = trace->syscalls.table + id; sc->name = name; - sc->fmt = syscall_fmt__find(sc->name); snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); @@ -1505,10 +1526,10 @@ static int trace__read_syscall_info(struct trace *trace, int id) } if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields)) - return -1; + return -ENOMEM; if (IS_ERR(sc->tp_format)) - return -1; + return PTR_ERR(sc->tp_format); sc->args = sc->tp_format->format.fields; /* @@ -1527,6 +1548,13 @@ static int trace__read_syscall_info(struct trace *trace, int id) return syscall__set_arg_fmts(sc); } +static int intcmp(const void *a, const void *b) +{ + const int *one = a, *another = b; + + return *one - *another; +} + static int trace__validate_ev_qualifier(struct trace *trace) { int err = 0; @@ -1590,6 +1618,7 @@ matches: } trace->ev_qualifier_ids.nr = nr_used; + qsort(trace->ev_qualifier_ids.entries, nr_used, sizeof(int), intcmp); out: if (printed_invalid_prefix) pr_debug("\n"); @@ -1600,6 +1629,22 @@ out_free: goto out; } +static __maybe_unused bool trace__syscall_enabled(struct trace *trace, int id) +{ + bool in_ev_qualifier; + + if (trace->ev_qualifier_ids.nr == 0) + return true; + + in_ev_qualifier = bsearch(&id, trace->ev_qualifier_ids.entries, + trace->ev_qualifier_ids.nr, sizeof(int), intcmp) != NULL; + + if (in_ev_qualifier) + return !trace->not_ev_qualifier; + + return trace->not_ev_qualifier; +} + /* * args is to be interpreted as a series of longs but we need to handle * 8-byte unaligned accesses. args points to raw_data within the event @@ -1738,13 +1783,14 @@ next_arg: return printed; } -typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, +typedef int (*tracepoint_handler)(struct trace *trace, struct evsel *evsel, union perf_event *event, struct perf_sample *sample); static struct syscall *trace__syscall_info(struct trace *trace, - struct perf_evsel *evsel, int id) + struct evsel *evsel, int id) { + int err = 0; if (id < 0) { @@ -1766,19 +1812,28 @@ static struct syscall *trace__syscall_info(struct trace *trace, return NULL; } - if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && - trace__read_syscall_info(trace, id)) + err = -EINVAL; + + if (id > trace->sctbl->syscalls.max_id) + goto out_cant_read; + + if ((trace->syscalls.table == NULL || trace->syscalls.table[id].name == NULL) && + (err = trace__read_syscall_info(trace, id)) != 0) goto out_cant_read; - if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) + if (trace->syscalls.table[id].name == NULL) { + if (trace->syscalls.table[id].nonexistent) + return NULL; goto out_cant_read; + } return &trace->syscalls.table[id]; out_cant_read: if (verbose > 0) { - fprintf(trace->output, "Problems reading syscall %d", id); - if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL) + char sbuf[STRERR_BUFSIZE]; + fprintf(trace->output, "Problems reading syscall %d: %d (%s)", id, -err, str_error_r(-err, sbuf, sizeof(sbuf))); + if (id <= trace->sctbl->syscalls.max_id && trace->syscalls.table[id].name != NULL) fprintf(trace->output, "(%s)", trace->syscalls.table[id].name); fputs(" information\n", trace->output); } @@ -1839,7 +1894,7 @@ static int trace__printf_interrupted_entry(struct trace *trace) return printed; } -static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel, +static int trace__fprintf_sample(struct trace *trace, struct evsel *evsel, struct perf_sample *sample, struct thread *thread) { int printed = 0; @@ -1882,7 +1937,7 @@ static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sam return augmented_args; } -static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, +static int trace__sys_enter(struct trace *trace, struct evsel *evsel, union perf_event *event __maybe_unused, struct perf_sample *sample) { @@ -1961,7 +2016,7 @@ out_put: return err; } -static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel, +static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel, struct perf_sample *sample) { struct thread_trace *ttrace; @@ -1994,13 +2049,13 @@ out_put: return err; } -static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, +static int trace__resolve_callchain(struct trace *trace, struct evsel *evsel, struct perf_sample *sample, struct callchain_cursor *cursor) { struct addr_location al; - int max_stack = evsel->attr.sample_max_stack ? - evsel->attr.sample_max_stack : + int max_stack = evsel->core.attr.sample_max_stack ? + evsel->core.attr.sample_max_stack : trace->max_stack; int err; @@ -2022,7 +2077,7 @@ static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sam return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output); } -static const char *errno_to_name(struct perf_evsel *evsel, int err) +static const char *errno_to_name(struct evsel *evsel, int err) { struct perf_env *env = perf_evsel__env(evsel); const char *arch_name = perf_env__arch(env); @@ -2030,7 +2085,7 @@ static const char *errno_to_name(struct perf_evsel *evsel, int err) return arch_syscalls__strerrno(arch_name, err); } -static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, +static int trace__sys_exit(struct trace *trace, struct evsel *evsel, union perf_event *event __maybe_unused, struct perf_sample *sample) { @@ -2058,7 +2113,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ret = perf_evsel__sc_tp_uint(evsel, ret, sample); - if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) { + if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) { trace__set_fd_pathname(thread, ret, ttrace->filename.name); ttrace->filename.pending_open = false; ++trace->stats.vfs_getname; @@ -2164,7 +2219,7 @@ out_put: return err; } -static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, +static int trace__vfs_getname(struct trace *trace, struct evsel *evsel, union perf_event *event __maybe_unused, struct perf_sample *sample) { @@ -2225,7 +2280,7 @@ out: return 0; } -static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, +static int trace__sched_stat_runtime(struct trace *trace, struct evsel *evsel, union perf_event *event __maybe_unused, struct perf_sample *sample) { @@ -2287,7 +2342,7 @@ static void bpf_output__fprintf(struct trace *trace, ++trace->nr_events_printed; } -static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, +static int trace__event_handler(struct trace *trace, struct evsel *evsel, union perf_event *event __maybe_unused, struct perf_sample *sample) { @@ -2353,8 +2408,8 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, ++trace->nr_events_printed; if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) { - perf_evsel__disable(evsel); - perf_evsel__close(evsel); + evsel__disable(evsel); + evsel__close(evsel); } } } @@ -2389,7 +2444,7 @@ static void print_location(FILE *f, struct perf_sample *sample, } static int trace__pgfault(struct trace *trace, - struct perf_evsel *evsel, + struct evsel *evsel, union perf_event *event __maybe_unused, struct perf_sample *sample) { @@ -2415,7 +2470,7 @@ static int trace__pgfault(struct trace *trace, if (ttrace == NULL) goto out_put; - if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ) + if (evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ) ttrace->pfmaj++; else ttrace->pfmin++; @@ -2428,7 +2483,7 @@ static int trace__pgfault(struct trace *trace, trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output); fprintf(trace->output, "%sfault [", - evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ? + evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ? "maj" : "min"); print_location(trace->output, sample, &al, false, true); @@ -2464,7 +2519,7 @@ out_put: } static void trace__set_base_time(struct trace *trace, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { /* @@ -2476,14 +2531,14 @@ static void trace__set_base_time(struct trace *trace, * appears in our event stream (vfs_getname comes to mind). */ if (trace->base_time == 0 && !trace->full_time && - (evsel->attr.sample_type & PERF_SAMPLE_TIME)) + (evsel->core.attr.sample_type & PERF_SAMPLE_TIME)) trace->base_time = sample->time; } static int trace__process_sample(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine __maybe_unused) { struct trace *trace = container_of(tool, struct trace, tool); @@ -2569,10 +2624,10 @@ static int trace__record(struct trace *trace, int argc, const char **argv) static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); -static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist) +static bool evlist__add_vfs_getname(struct evlist *evlist) { bool found = false; - struct perf_evsel *evsel, *tmp; + struct evsel *evsel, *tmp; struct parse_events_error err = { .idx = 0, }; int ret = parse_events(evlist, "probe:vfs_getname*", &err); @@ -2589,17 +2644,17 @@ static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist) continue; } - list_del_init(&evsel->node); + list_del_init(&evsel->core.node); evsel->evlist = NULL; - perf_evsel__delete(evsel); + evsel__delete(evsel); } return found; } -static struct perf_evsel *perf_evsel__new_pgfault(u64 config) +static struct evsel *perf_evsel__new_pgfault(u64 config) { - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .mmap_data = 1, @@ -2610,7 +2665,7 @@ static struct perf_evsel *perf_evsel__new_pgfault(u64 config) event_attr_init(&attr); - evsel = perf_evsel__new(&attr); + evsel = evsel__new(&attr); if (evsel) evsel->handler = trace__pgfault; @@ -2620,7 +2675,7 @@ static struct perf_evsel *perf_evsel__new_pgfault(u64 config) static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) { const u32 type = event->header.type; - struct perf_evsel *evsel; + struct evsel *evsel; if (type != PERF_RECORD_SAMPLE) { trace__process_event(trace, trace->host, event, sample); @@ -2633,9 +2688,12 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st return; } + if (evswitch__discard(&trace->evswitch, evsel)) + return; + trace__set_base_time(trace, evsel, sample); - if (evsel->attr.type == PERF_TYPE_TRACEPOINT && + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT && sample->raw_data == NULL) { fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", perf_evsel__name(evsel), sample->tid, @@ -2652,8 +2710,8 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st static int trace__add_syscall_newtp(struct trace *trace) { int ret = -1; - struct perf_evlist *evlist = trace->evlist; - struct perf_evsel *sys_enter, *sys_exit; + struct evlist *evlist = trace->evlist; + struct evsel *sys_enter, *sys_exit; sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter); if (sys_enter == NULL) @@ -2672,8 +2730,8 @@ static int trace__add_syscall_newtp(struct trace *trace) perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param); perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param); - perf_evlist__add(evlist, sys_enter); - perf_evlist__add(evlist, sys_exit); + evlist__add(evlist, sys_enter); + evlist__add(evlist, sys_exit); if (callchain_param.enabled && !trace->kernel_syscallchains) { /* @@ -2681,7 +2739,7 @@ static int trace__add_syscall_newtp(struct trace *trace) * leading to the syscall, allow overriding that for * debugging reasons using --kernel_syscall_callchains */ - sys_exit->attr.exclude_callchain_kernel = 1; + sys_exit->core.attr.exclude_callchain_kernel = 1; } trace->syscalls.events.sys_enter = sys_enter; @@ -2692,16 +2750,16 @@ out: return ret; out_delete_sys_exit: - perf_evsel__delete_priv(sys_exit); + evsel__delete_priv(sys_exit); out_delete_sys_enter: - perf_evsel__delete_priv(sys_enter); + evsel__delete_priv(sys_enter); goto out; } static int trace__set_ev_qualifier_tp_filter(struct trace *trace) { int err = -1; - struct perf_evsel *sys_exit; + struct evsel *sys_exit; char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier, trace->ev_qualifier_ids.nr, trace->ev_qualifier_ids.entries); @@ -2724,6 +2782,70 @@ out_enomem: } #ifdef HAVE_LIBBPF_SUPPORT +static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace, const char *name) +{ + if (trace->bpf_obj == NULL) + return NULL; + + return bpf_object__find_program_by_title(trace->bpf_obj, name); +} + +static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace, struct syscall *sc, + const char *prog_name, const char *type) +{ + struct bpf_program *prog; + + if (prog_name == NULL) { + char default_prog_name[256]; + scnprintf(default_prog_name, sizeof(default_prog_name), "!syscalls:sys_%s_%s", type, sc->name); + prog = trace__find_bpf_program_by_title(trace, default_prog_name); + if (prog != NULL) + goto out_found; + if (sc->fmt && sc->fmt->alias) { + scnprintf(default_prog_name, sizeof(default_prog_name), "!syscalls:sys_%s_%s", type, sc->fmt->alias); + prog = trace__find_bpf_program_by_title(trace, default_prog_name); + if (prog != NULL) + goto out_found; + } + goto out_unaugmented; + } + + prog = trace__find_bpf_program_by_title(trace, prog_name); + + if (prog != NULL) { +out_found: + return prog; + } + + pr_debug("Couldn't find BPF prog \"%s\" to associate with syscalls:sys_%s_%s, not augmenting it\n", + prog_name, type, sc->name); +out_unaugmented: + return trace->syscalls.unaugmented_prog; +} + +static void trace__init_syscall_bpf_progs(struct trace *trace, int id) +{ + struct syscall *sc = trace__syscall_info(trace, NULL, id); + + if (sc == NULL) + return; + + sc->bpf_prog.sys_enter = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_enter : NULL, "enter"); + sc->bpf_prog.sys_exit = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_exit : NULL, "exit"); +} + +static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int id) +{ + struct syscall *sc = trace__syscall_info(trace, NULL, id); + return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(trace->syscalls.unaugmented_prog); +} + +static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int id) +{ + struct syscall *sc = trace__syscall_info(trace, NULL, id); + return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(trace->syscalls.unaugmented_prog); +} + static void trace__init_bpf_map_syscall_args(struct trace *trace, int id, struct bpf_map_syscall_entry *entry) { struct syscall *sc = trace__syscall_info(trace, NULL, id); @@ -2755,8 +2877,10 @@ static int trace__set_ev_qualifier_bpf_filter(struct trace *trace) for (i = 0; i < trace->ev_qualifier_ids.nr; ++i) { int key = trace->ev_qualifier_ids.entries[i]; - if (value.enabled) + if (value.enabled) { trace__init_bpf_map_syscall_args(trace, key, &value); + trace__init_syscall_bpf_progs(trace, key); + } err = bpf_map_update_elem(fd, &key, &value, BPF_EXIST); if (err) @@ -2795,6 +2919,186 @@ static int trace__init_syscalls_bpf_map(struct trace *trace) return __trace__init_syscalls_bpf_map(trace, enabled); } + +static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, struct syscall *sc) +{ + struct tep_format_field *field, *candidate_field; + int id; + + /* + * We're only interested in syscalls that have a pointer: + */ + for (field = sc->args; field; field = field->next) { + if (field->flags & TEP_FIELD_IS_POINTER) + goto try_to_find_pair; + } + + return NULL; + +try_to_find_pair: + for (id = 0; id < trace->sctbl->syscalls.nr_entries; ++id) { + struct syscall *pair = trace__syscall_info(trace, NULL, id); + struct bpf_program *pair_prog; + bool is_candidate = false; + + if (pair == NULL || pair == sc || + pair->bpf_prog.sys_enter == trace->syscalls.unaugmented_prog) + continue; + + for (field = sc->args, candidate_field = pair->args; + field && candidate_field; field = field->next, candidate_field = candidate_field->next) { + bool is_pointer = field->flags & TEP_FIELD_IS_POINTER, + candidate_is_pointer = candidate_field->flags & TEP_FIELD_IS_POINTER; + + if (is_pointer) { + if (!candidate_is_pointer) { + // The candidate just doesn't copies our pointer arg, might copy other pointers we want. + continue; + } + } else { + if (candidate_is_pointer) { + // The candidate might copy a pointer we don't have, skip it. + goto next_candidate; + } + continue; + } + + if (strcmp(field->type, candidate_field->type)) + goto next_candidate; + + is_candidate = true; + } + + if (!is_candidate) + goto next_candidate; + + /* + * Check if the tentative pair syscall augmenter has more pointers, if it has, + * then it may be collecting that and we then can't use it, as it would collect + * more than what is common to the two syscalls. + */ + if (candidate_field) { + for (candidate_field = candidate_field->next; candidate_field; candidate_field = candidate_field->next) + if (candidate_field->flags & TEP_FIELD_IS_POINTER) + goto next_candidate; + } + + pair_prog = pair->bpf_prog.sys_enter; + /* + * If the pair isn't enabled, then its bpf_prog.sys_enter will not + * have been searched for, so search it here and if it returns the + * unaugmented one, then ignore it, otherwise we'll reuse that BPF + * program for a filtered syscall on a non-filtered one. + * + * For instance, we have "!syscalls:sys_enter_renameat" and that is + * useful for "renameat2". + */ + if (pair_prog == NULL) { + pair_prog = trace__find_syscall_bpf_prog(trace, pair, pair->fmt ? pair->fmt->bpf_prog_name.sys_enter : NULL, "enter"); + if (pair_prog == trace->syscalls.unaugmented_prog) + goto next_candidate; + } + + pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name, sc->name); + return pair_prog; + next_candidate: + continue; + } + + return NULL; +} + +static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) +{ + int map_enter_fd = bpf_map__fd(trace->syscalls.prog_array.sys_enter), + map_exit_fd = bpf_map__fd(trace->syscalls.prog_array.sys_exit); + int err = 0, key; + + for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) { + int prog_fd; + + if (!trace__syscall_enabled(trace, key)) + continue; + + trace__init_syscall_bpf_progs(trace, key); + + // It'll get at least the "!raw_syscalls:unaugmented" + prog_fd = trace__bpf_prog_sys_enter_fd(trace, key); + err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY); + if (err) + break; + prog_fd = trace__bpf_prog_sys_exit_fd(trace, key); + err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY); + if (err) + break; + } + + /* + * Now lets do a second pass looking for enabled syscalls without + * an augmenter that have a signature that is a superset of another + * syscall with an augmenter so that we can auto-reuse it. + * + * I.e. if we have an augmenter for the "open" syscall that has + * this signature: + * + * int open(const char *pathname, int flags, mode_t mode); + * + * I.e. that will collect just the first string argument, then we + * can reuse it for the 'creat' syscall, that has this signature: + * + * int creat(const char *pathname, mode_t mode); + * + * and for: + * + * int stat(const char *pathname, struct stat *statbuf); + * int lstat(const char *pathname, struct stat *statbuf); + * + * Because the 'open' augmenter will collect the first arg as a string, + * and leave alone all the other args, which already helps with + * beautifying 'stat' and 'lstat''s pathname arg. + * + * Then, in time, when 'stat' gets an augmenter that collects both + * first and second arg (this one on the raw_syscalls:sys_exit prog + * array tail call, then that one will be used. + */ + for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) { + struct syscall *sc = trace__syscall_info(trace, NULL, key); + struct bpf_program *pair_prog; + int prog_fd; + + if (sc == NULL || sc->bpf_prog.sys_enter == NULL) + continue; + + /* + * For now we're just reusing the sys_enter prog, and if it + * already has an augmenter, we don't need to find one. + */ + if (sc->bpf_prog.sys_enter != trace->syscalls.unaugmented_prog) + continue; + + /* + * Look at all the other syscalls for one that has a signature + * that is close enough that we can share: + */ + pair_prog = trace__find_usable_bpf_prog_entry(trace, sc); + if (pair_prog == NULL) + continue; + + sc->bpf_prog.sys_enter = pair_prog; + + /* + * Update the BPF_MAP_TYPE_PROG_SHARED for raw_syscalls:sys_enter + * with the fd for the program we're reusing: + */ + prog_fd = bpf_program__fd(sc->bpf_prog.sys_enter); + err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY); + if (err) + break; + } + + + return err; +} #else static int trace__set_ev_qualifier_bpf_filter(struct trace *trace __maybe_unused) { @@ -2805,6 +3109,17 @@ static int trace__init_syscalls_bpf_map(struct trace *trace __maybe_unused) { return 0; } + +static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace __maybe_unused, + const char *name __maybe_unused) +{ + return NULL; +} + +static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace __maybe_unused) +{ + return 0; +} #endif // HAVE_LIBBPF_SUPPORT static int trace__set_ev_qualifier_filter(struct trace *trace) @@ -2879,7 +3194,7 @@ static int trace__set_filter_pids(struct trace *trace) err = bpf_map__set_filter_pids(trace->filter_pids.map, trace->filter_pids.nr, trace->filter_pids.entries); } - } else if (thread_map__pid(trace->evlist->threads, 0) == -1) { + } else if (perf_thread_map__pid(trace->evlist->core.threads, 0) == -1) { err = trace__set_filter_loop_pids(trace); } @@ -2888,7 +3203,7 @@ static int trace__set_filter_pids(struct trace *trace) static int __trace__deliver_event(struct trace *trace, union perf_event *event) { - struct perf_evlist *evlist = trace->evlist; + struct evlist *evlist = trace->evlist; struct perf_sample sample; int err; @@ -2946,8 +3261,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe, static int trace__run(struct trace *trace, int argc, const char **argv) { - struct perf_evlist *evlist = trace->evlist; - struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL; + struct evlist *evlist = trace->evlist; + struct evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL; int err = -1, i; unsigned long before; const bool forks = argc > 0; @@ -2960,7 +3275,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) goto out_error_raw_syscalls; if (trace->trace_syscalls) - trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); + trace->vfs_getname = evlist__add_vfs_getname(evlist); } if ((trace->trace_pgfaults & TRACE_PFMAJ)) { @@ -2968,7 +3283,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (pgfault_maj == NULL) goto out_error_mem; perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param); - perf_evlist__add(evlist, pgfault_maj); + evlist__add(evlist, pgfault_maj); } if ((trace->trace_pgfaults & TRACE_PFMIN)) { @@ -2976,7 +3291,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (pgfault_min == NULL) goto out_error_mem; perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param); - perf_evlist__add(evlist, pgfault_min); + evlist__add(evlist, pgfault_min); } if (trace->sched && @@ -3038,7 +3353,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) } } - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) goto out_error_open; @@ -3059,6 +3374,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (trace->syscalls.map) trace__init_syscalls_bpf_map(trace); + if (trace->syscalls.prog_array.sys_enter) + trace__init_syscalls_bpf_prog_array_maps(trace); + if (trace->ev_qualifier_ids.nr > 0) { err = trace__set_ev_qualifier_filter(trace); if (err < 0) @@ -3070,6 +3388,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv) } } + /* + * If the "close" syscall is not traced, then we will not have the + * opportunity to, in syscall_arg__scnprintf_close_fd() invalidate the + * fd->pathname table and were ending up showing the last value set by + * syscalls opening a pathname and associating it with a descriptor or + * reading it from /proc/pid/fd/ in cases where that doesn't make + * sense. + * + * So just disable this beautifier (SCA_FD, SCA_FDAT) when 'close' is + * not in use. + */ + trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(trace->sctbl, "close")); + err = perf_evlist__apply_filters(evlist, &evsel); if (err < 0) goto out_error_apply_filters; @@ -3082,30 +3413,30 @@ static int trace__run(struct trace *trace, int argc, const char **argv) goto out_error_mmap; if (!target__none(&trace->opts.target) && !trace->opts.initial_delay) - perf_evlist__enable(evlist); + evlist__enable(evlist); if (forks) perf_evlist__start_workload(evlist); if (trace->opts.initial_delay) { usleep(trace->opts.initial_delay * 1000); - perf_evlist__enable(evlist); + evlist__enable(evlist); } - trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 || - evlist->threads->nr > 1 || - perf_evlist__first(evlist)->attr.inherit; + trace->multiple_threads = perf_thread_map__pid(evlist->core.threads, 0) == -1 || + evlist->core.threads->nr > 1 || + perf_evlist__first(evlist)->core.attr.inherit; /* - * Now that we already used evsel->attr to ask the kernel to setup the - * events, lets reuse evsel->attr.sample_max_stack as the limit in + * Now that we already used evsel->core.attr to ask the kernel to setup the + * events, lets reuse evsel->core.attr.sample_max_stack as the limit in * trace__resolve_callchain(), allowing per-event max-stack settings * to override an explicitly set --max-stack global setting. */ evlist__for_each_entry(evlist, evsel) { if (evsel__has_callchain(evsel) && - evsel->attr.sample_max_stack == 0) - evsel->attr.sample_max_stack = trace->max_stack; + evsel->core.attr.sample_max_stack == 0) + evsel->core.attr.sample_max_stack = trace->max_stack; } again: before = trace->nr_events; @@ -3131,7 +3462,7 @@ again: goto out_disable; if (done && !draining) { - perf_evlist__disable(evlist); + evlist__disable(evlist); draining = true; } } @@ -3157,7 +3488,7 @@ again: out_disable: thread__zput(trace->current); - perf_evlist__disable(evlist); + evlist__disable(evlist); if (trace->sort_events) ordered_events__flush(&trace->oe.data, OE_FLUSH__FINAL); @@ -3178,7 +3509,7 @@ out_disable: out_delete_evlist: trace__symbols__exit(trace); - perf_evlist__delete(evlist); + evlist__delete(evlist); cgroup__put(trace->cgroup); trace->evlist = NULL; trace->live = false; @@ -3223,7 +3554,7 @@ out_errno: static int trace__replay(struct trace *trace) { - const struct perf_evsel_str_handler handlers[] = { + const struct evsel_str_handler handlers[] = { { "probe:vfs_getname", trace__vfs_getname, }, }; struct perf_data data = { @@ -3232,7 +3563,7 @@ static int trace__replay(struct trace *trace) .force = trace->force, }; struct perf_session *session; - struct perf_evsel *evsel; + struct evsel *evsel; int err = -1; trace->tool.sample = trace__process_sample; @@ -3298,10 +3629,10 @@ static int trace__replay(struct trace *trace) } evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.type == PERF_TYPE_SOFTWARE && - (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ || - evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN || - evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS)) + if (evsel->core.attr.type == PERF_TYPE_SOFTWARE && + (evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ || + evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN || + evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS)) evsel->handler = trace__pgfault; } @@ -3523,17 +3854,17 @@ static int parse_pagefaults(const struct option *opt, const char *str, return 0; } -static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler) +static void evlist__set_evsel_handler(struct evlist *evlist, void *handler) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel->handler = handler; } -static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist) +static int evlist__set_syscall_tp_fields(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->priv || !evsel->tp_format) @@ -3660,7 +3991,7 @@ static int trace__parse_cgroups(const struct option *opt, const char *str, int u { struct trace *trace = opt->value; - if (!list_empty(&trace->evlist->entries)) + if (!list_empty(&trace->evlist->core.entries)) return parse_cgroups(opt, str, unset); trace->cgroup = evlist__findnew_cgroup(trace->evlist, str); @@ -3668,28 +3999,24 @@ static int trace__parse_cgroups(const struct option *opt, const char *str, int u return 0; } -static struct bpf_map *bpf__find_map_by_name(const char *name) +static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace, const char *name) { - struct bpf_object *obj, *tmp; - - bpf_object__for_each_safe(obj, tmp) { - struct bpf_map *map = bpf_object__find_map_by_name(obj, name); - if (map) - return map; - - } + if (trace->bpf_obj == NULL) + return NULL; - return NULL; + return bpf_object__find_map_by_name(trace->bpf_obj, name); } static void trace__set_bpf_map_filtered_pids(struct trace *trace) { - trace->filter_pids.map = bpf__find_map_by_name("pids_filtered"); + trace->filter_pids.map = trace__find_bpf_map_by_name(trace, "pids_filtered"); } static void trace__set_bpf_map_syscalls(struct trace *trace) { - trace->syscalls.map = bpf__find_map_by_name("syscalls"); + trace->syscalls.map = trace__find_bpf_map_by_name(trace, "syscalls"); + trace->syscalls.prog_array.sys_enter = trace__find_bpf_map_by_name(trace, "syscalls_sys_enter"); + trace->syscalls.prog_array.sys_exit = trace__find_bpf_map_by_name(trace, "syscalls_sys_exit"); } static int trace__config(const char *var, const char *value, void *arg) @@ -3745,9 +4072,6 @@ int cmd_trace(int argc, const char **argv) NULL }; struct trace trace = { - .syscalls = { - . max = -1, - }, .opts = { .target = { .uid = UINT_MAX, @@ -3844,11 +4168,12 @@ int cmd_trace(int argc, const char **argv) OPT_UINTEGER('D', "delay", &trace.opts.initial_delay, "ms to wait before starting measurement after program " "start"), + OPTS_EVSWITCH(&trace.evswitch), OPT_END() }; bool __maybe_unused max_stack_user_set = true; bool mmap_pages_user_set = true; - struct perf_evsel *evsel; + struct evsel *evsel; const char * const trace_subcommands[] = { "record", NULL }; int err = -1; char bf[BUFSIZ]; @@ -3856,7 +4181,7 @@ int cmd_trace(int argc, const char **argv) signal(SIGSEGV, sighandler_dump_stack); signal(SIGFPE, sighandler_dump_stack); - trace.evlist = perf_evlist__new(); + trace.evlist = evlist__new(); trace.sctbl = syscalltbl__new(); if (trace.evlist == NULL || trace.sctbl == NULL) { @@ -3895,8 +4220,23 @@ int cmd_trace(int argc, const char **argv) if (evsel) { trace.syscalls.events.augmented = evsel; + + evsel = perf_evlist__find_tracepoint_by_name(trace.evlist, "raw_syscalls:sys_enter"); + if (evsel == NULL) { + pr_err("ERROR: raw_syscalls:sys_enter not found in the augmented BPF object\n"); + goto out; + } + + if (evsel->bpf_obj == NULL) { + pr_err("ERROR: raw_syscalls:sys_enter not associated to a BPF object\n"); + goto out; + } + + trace.bpf_obj = evsel->bpf_obj; + trace__set_bpf_map_filtered_pids(&trace); trace__set_bpf_map_syscalls(&trace); + trace.syscalls.unaugmented_prog = trace__find_bpf_program_by_title(&trace, "!raw_syscalls:unaugmented"); } err = bpf__setup_stdout(trace.evlist); @@ -3909,7 +4249,7 @@ int cmd_trace(int argc, const char **argv) err = -1; if (map_dump_str) { - trace.dump.map = bpf__find_map_by_name(map_dump_str); + trace.dump.map = trace__find_bpf_map_by_name(&trace, map_dump_str); if (trace.dump.map == NULL) { pr_err("ERROR: BPF map \"%s\" not found\n", map_dump_str); goto out; @@ -3942,7 +4282,7 @@ int cmd_trace(int argc, const char **argv) symbol_conf.use_callchain = true; } - if (trace.evlist->nr_entries > 0) { + if (trace.evlist->core.nr_entries > 0) { evlist__set_evsel_handler(trace.evlist, trace__event_handler); if (evlist__set_syscall_tp_fields(trace.evlist)) { perror("failed to set syscalls:* tracepoint fields"); @@ -3977,11 +4317,26 @@ int cmd_trace(int argc, const char **argv) if (trace.syscalls.events.augmented->priv == NULL && strstr(perf_evsel__name(evsel), "syscalls:sys_enter")) { - struct perf_evsel *augmented = trace.syscalls.events.augmented; + struct evsel *augmented = trace.syscalls.events.augmented; if (perf_evsel__init_augmented_syscall_tp(augmented, evsel) || perf_evsel__init_augmented_syscall_tp_args(augmented)) goto out; + /* + * Augmented is __augmented_syscalls__ BPF_OUTPUT event + * Above we made sure we can get from the payload the tp fields + * that we get from syscalls:sys_enter tracefs format file. + */ augmented->handler = trace__sys_enter; + /* + * Now we do the same for the *syscalls:sys_enter event so that + * if we handle it directly, i.e. if the BPF prog returns 0 so + * as not to filter it, then we'll handle it just like we would + * for the BPF_OUTPUT one: + */ + if (perf_evsel__init_augmented_syscall_tp(evsel, evsel) || + perf_evsel__init_augmented_syscall_tp_args(evsel)) + goto out; + evsel->handler = trace__sys_enter; } if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) { @@ -4025,7 +4380,7 @@ init_augmented_syscall_tp: trace.summary = trace.summary_only; if (!trace.trace_syscalls && !trace.trace_pgfaults && - trace.evlist->nr_entries == 0 /* Was --events used? */) { + trace.evlist->core.nr_entries == 0 /* Was --events used? */) { trace.trace_syscalls = true; } @@ -4037,6 +4392,10 @@ init_augmented_syscall_tp: } } + err = evswitch__init(&trace.evswitch, trace.evlist, stderr); + if (err) + goto out_close; + err = target__validate(&trace.opts.target); if (err) { target__strerror(&trace.opts.target, err, bf, sizeof(bf)); diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c index bf114ca9ca87..05cf2af9e2c2 100644 --- a/tools/perf/builtin-version.c +++ b/tools/perf/builtin-version.c @@ -2,8 +2,8 @@ #include "builtin.h" #include "perf.h" #include "color.h" -#include <linux/compiler.h> #include <tools/config.h> +#include <stdbool.h> #include <stdio.h> #include <string.h> #include <subcmd/parse-options.h> diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 999fe9170122..14a2db622a7b 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -2,8 +2,6 @@ #ifndef BUILTIN_H #define BUILTIN_H -#include "util/util.h" - extern const char perf_usage_string[]; extern const char perf_more_info_string[]; diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index f211c015cb76..e2e0f06c97d0 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -1,7 +1,8 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -HEADERS=' +FILES=' +include/uapi/linux/const.h include/uapi/drm/drm.h include/uapi/drm/i915_drm.h include/uapi/linux/fadvise.h @@ -19,12 +20,16 @@ include/uapi/linux/usbdevice_fs.h include/uapi/linux/vhost.h include/uapi/sound/asound.h include/linux/bits.h +include/linux/const.h include/linux/hash.h include/uapi/linux/hw_breakpoint.h arch/x86/include/asm/disabled-features.h arch/x86/include/asm/required-features.h arch/x86/include/asm/cpufeatures.h +arch/x86/include/asm/inat_types.h arch/x86/include/uapi/asm/prctl.h +arch/x86/lib/x86-opcode-map.txt +arch/x86/tools/gen-insn-attr-x86.awk arch/arm/include/uapi/asm/perf_regs.h arch/arm64/include/uapi/asm/perf_regs.h arch/powerpc/include/uapi/asm/perf_regs.h @@ -96,7 +101,7 @@ test -d ../../include || exit 0 cd ../.. # simple diff check -for i in $HEADERS; do +for i in $FILES; do check $i -B done @@ -107,6 +112,10 @@ check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"' check include/linux/ctype.h '-I "isdigit("' check lib/ctype.c '-I "^EXPORT_SYMBOL" -I "^#include <linux/export.h>" -B' +check arch/x86/include/asm/inat.h '-I "^#include [\"<]\(asm/\)*inat_types.h[\">]"' +check arch/x86/include/asm/insn.h '-I "^#include [\"<]\(asm/\)*inat.h[\">]"' +check arch/x86/lib/inat.c '-I "^#include [\"<]\(../include/\)*asm/insn.h[\">]"' +check arch/x86/lib/insn.c '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]"' # diff non-symmetric files check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl diff --git a/tools/perf/examples/bpf/augmented_raw_syscalls.c b/tools/perf/examples/bpf/augmented_raw_syscalls.c index 2f822bb51717..b80437971d80 100644 --- a/tools/perf/examples/bpf/augmented_raw_syscalls.c +++ b/tools/perf/examples/bpf/augmented_raw_syscalls.c @@ -16,6 +16,7 @@ #include <unistd.h> #include <linux/limits.h> +#include <linux/socket.h> #include <pid_filter.h> /* bpf-output associated map */ @@ -33,6 +34,20 @@ struct syscall { bpf_map(syscalls, ARRAY, int, struct syscall, 512); +/* + * What to augment at entry? + * + * Pointer arg payloads (filenames, etc) passed from userspace to the kernel + */ +bpf_map(syscalls_sys_enter, PROG_ARRAY, u32, u32, 512); + +/* + * What to augment at exit? + * + * Pointer arg payloads returned from the kernel (struct stat, etc) to userspace. + */ +bpf_map(syscalls_sys_exit, PROG_ARRAY, u32, u32, 512); + struct syscall_enter_args { unsigned long long common_tp_fields; long syscall_nr; @@ -45,7 +60,7 @@ struct syscall_exit_args { long ret; }; -struct augmented_filename { +struct augmented_arg { unsigned int size; int err; char value[PATH_MAX]; @@ -53,45 +68,176 @@ struct augmented_filename { pid_filter(pids_filtered); -struct augmented_args_filename { +struct augmented_args_payload { struct syscall_enter_args args; - struct augmented_filename filename; + union { + struct { + struct augmented_arg arg, arg2; + }; + struct sockaddr_storage saddr; + }; }; -bpf_map(augmented_filename_map, PERCPU_ARRAY, int, struct augmented_args_filename, 1); +// We need more tmp space than the BPF stack can give us +bpf_map(augmented_args_tmp, PERCPU_ARRAY, int, struct augmented_args_payload, 1); + +static inline struct augmented_args_payload *augmented_args_payload(void) +{ + int key = 0; + return bpf_map_lookup_elem(&augmented_args_tmp, &key); +} + +static inline int augmented__output(void *ctx, struct augmented_args_payload *args, int len) +{ + /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ + return perf_event_output(ctx, &__augmented_syscalls__, BPF_F_CURRENT_CPU, args, len); +} static inline -unsigned int augmented_filename__read(struct augmented_filename *augmented_filename, - const void *filename_arg, unsigned int filename_len) +unsigned int augmented_arg__read_str(struct augmented_arg *augmented_arg, const void *arg, unsigned int arg_len) { - unsigned int len = sizeof(*augmented_filename); - int size = probe_read_str(&augmented_filename->value, filename_len, filename_arg); + unsigned int augmented_len = sizeof(*augmented_arg); + int string_len = probe_read_str(&augmented_arg->value, arg_len, arg); - augmented_filename->size = augmented_filename->err = 0; + augmented_arg->size = augmented_arg->err = 0; /* * probe_read_str may return < 0, e.g. -EFAULT - * So we leave that in the augmented_filename->size that userspace will + * So we leave that in the augmented_arg->size that userspace will */ - if (size > 0) { - len -= sizeof(augmented_filename->value) - size; - len &= sizeof(augmented_filename->value) - 1; - augmented_filename->size = size; + if (string_len > 0) { + augmented_len -= sizeof(augmented_arg->value) - string_len; + augmented_len &= sizeof(augmented_arg->value) - 1; + augmented_arg->size = string_len; } else { /* * So that username notice the error while still being able * to skip this augmented arg record */ - augmented_filename->err = size; - len = offsetof(struct augmented_filename, value); + augmented_arg->err = string_len; + augmented_len = offsetof(struct augmented_arg, value); } - return len; + return augmented_len; +} + +SEC("!raw_syscalls:unaugmented") +int syscall_unaugmented(struct syscall_enter_args *args) +{ + return 1; +} + +/* + * These will be tail_called from SEC("raw_syscalls:sys_enter"), so will find in + * augmented_args_tmp what was read by that raw_syscalls:sys_enter and go + * on from there, reading the first syscall arg as a string, i.e. open's + * filename. + */ +SEC("!syscalls:sys_enter_connect") +int sys_enter_connect(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *sockaddr_arg = (const void *)args->args[1]; + unsigned int socklen = args->args[2]; + unsigned int len = sizeof(augmented_args->args); + + if (augmented_args == NULL) + return 1; /* Failure: don't filter */ + + if (socklen > sizeof(augmented_args->saddr)) + socklen = sizeof(augmented_args->saddr); + + probe_read(&augmented_args->saddr, socklen, sockaddr_arg); + + return augmented__output(args, augmented_args, len + socklen); +} + +SEC("!syscalls:sys_enter_sendto") +int sys_enter_sendto(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *sockaddr_arg = (const void *)args->args[4]; + unsigned int socklen = args->args[5]; + unsigned int len = sizeof(augmented_args->args); + + if (augmented_args == NULL) + return 1; /* Failure: don't filter */ + + if (socklen > sizeof(augmented_args->saddr)) + socklen = sizeof(augmented_args->saddr); + + probe_read(&augmented_args->saddr, socklen, sockaddr_arg); + + return augmented__output(args, augmented_args, len + socklen); +} + +SEC("!syscalls:sys_enter_open") +int sys_enter_open(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *filename_arg = (const void *)args->args[0]; + unsigned int len = sizeof(augmented_args->args); + + if (augmented_args == NULL) + return 1; /* Failure: don't filter */ + + len += augmented_arg__read_str(&augmented_args->arg, filename_arg, sizeof(augmented_args->arg.value)); + + return augmented__output(args, augmented_args, len); +} + +SEC("!syscalls:sys_enter_openat") +int sys_enter_openat(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *filename_arg = (const void *)args->args[1]; + unsigned int len = sizeof(augmented_args->args); + + if (augmented_args == NULL) + return 1; /* Failure: don't filter */ + + len += augmented_arg__read_str(&augmented_args->arg, filename_arg, sizeof(augmented_args->arg.value)); + + return augmented__output(args, augmented_args, len); +} + +SEC("!syscalls:sys_enter_rename") +int sys_enter_rename(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *oldpath_arg = (const void *)args->args[0], + *newpath_arg = (const void *)args->args[1]; + unsigned int len = sizeof(augmented_args->args), oldpath_len; + + if (augmented_args == NULL) + return 1; /* Failure: don't filter */ + + oldpath_len = augmented_arg__read_str(&augmented_args->arg, oldpath_arg, sizeof(augmented_args->arg.value)); + len += oldpath_len + augmented_arg__read_str((void *)(&augmented_args->arg) + oldpath_len, newpath_arg, sizeof(augmented_args->arg.value)); + + return augmented__output(args, augmented_args, len); +} + +SEC("!syscalls:sys_enter_renameat") +int sys_enter_renameat(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *oldpath_arg = (const void *)args->args[1], + *newpath_arg = (const void *)args->args[3]; + unsigned int len = sizeof(augmented_args->args), oldpath_len; + + if (augmented_args == NULL) + return 1; /* Failure: don't filter */ + + oldpath_len = augmented_arg__read_str(&augmented_args->arg, oldpath_arg, sizeof(augmented_args->arg.value)); + len += oldpath_len + augmented_arg__read_str((void *)(&augmented_args->arg) + oldpath_len, newpath_arg, sizeof(augmented_args->arg.value)); + + return augmented__output(args, augmented_args, len); } SEC("raw_syscalls:sys_enter") int sys_enter(struct syscall_enter_args *args) { - struct augmented_args_filename *augmented_args; + struct augmented_args_payload *augmented_args; /* * We start len, the amount of data that will be in the perf ring * buffer, if this is not filtered out by one of pid_filter__has(), @@ -103,142 +249,46 @@ int sys_enter(struct syscall_enter_args *args) */ unsigned int len = sizeof(augmented_args->args); struct syscall *syscall; - int key = 0; - - augmented_args = bpf_map_lookup_elem(&augmented_filename_map, &key); - if (augmented_args == NULL) - return 1; if (pid_filter__has(&pids_filtered, getpid())) return 0; + augmented_args = augmented_args_payload(); + if (augmented_args == NULL) + return 1; + probe_read(&augmented_args->args, sizeof(augmented_args->args), args); - syscall = bpf_map_lookup_elem(&syscalls, &augmented_args->args.syscall_nr); - if (syscall == NULL || !syscall->enabled) - return 0; /* - * Yonghong and Edward Cree sayz: - * - * https://www.spinics.net/lists/netdev/msg531645.html - * - * >> R0=inv(id=0) R1=inv2 R6=ctx(id=0,off=0,imm=0) R7=inv64 R10=fp0,call_-1 - * >> 10: (bf) r1 = r6 - * >> 11: (07) r1 += 16 - * >> 12: (05) goto pc+2 - * >> 15: (79) r3 = *(u64 *)(r1 +0) - * >> dereference of modified ctx ptr R1 off=16 disallowed - * > Aha, we at least got a different error message this time. - * > And indeed llvm has done that optimisation, rather than the more obvious - * > 11: r3 = *(u64 *)(r1 +16) - * > because it wants to have lots of reads share a single insn. You may be able - * > to defeat that optimisation by adding compiler barriers, idk. Maybe someone - * > with llvm knowledge can figure out how to stop it (ideally, llvm would know - * > when it's generating for bpf backend and not do that). -O0? ¯\_(ツ)_/¯ - * - * The optimization mostly likes below: - * - * br1: - * ... - * r1 += 16 - * goto merge - * br2: - * ... - * r1 += 20 - * goto merge - * merge: - * *(u64 *)(r1 + 0) - * - * The compiler tries to merge common loads. There is no easy way to - * stop this compiler optimization without turning off a lot of other - * optimizations. The easiest way is to add barriers: - * - * __asm__ __volatile__("": : :"memory") - * - * after the ctx memory access to prevent their down stream merging. + * Jump to syscall specific augmenter, even if the default one, + * "!raw_syscalls:unaugmented" that will just return 1 to return the + * unagmented tracepoint payload. */ - /* - * For now copy just the first string arg, we need to improve the protocol - * and have more than one. - * - * Using the unrolled loop is not working, only when we do it manually, - * check this out later... - - u8 arg; -#pragma clang loop unroll(full) - for (arg = 0; arg < 6; ++arg) { - if (syscall->string_args_len[arg] != 0) { - filename_len = syscall->string_args_len[arg]; - filename_arg = (const void *)args->args[arg]; - __asm__ __volatile__("": : :"memory"); - break; - } - } - - verifier log: - -; if (syscall->string_args_len[arg] != 0) { -37: (69) r3 = *(u16 *)(r0 +2) - R0=map_value(id=0,off=0,ks=4,vs=14,imm=0) R1_w=inv0 R2_w=map_value(id=0,off=2,ks=4,vs=14,imm=0) R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=4168,imm=0) R10=fp0,call_-1 fp-8=mmmmmmmm -; if (syscall->string_args_len[arg] != 0) { -38: (55) if r3 != 0x0 goto pc+5 - R0=map_value(id=0,off=0,ks=4,vs=14,imm=0) R1=inv0 R2=map_value(id=0,off=2,ks=4,vs=14,imm=0) R3=inv0 R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=4168,imm=0) R10=fp0,call_-1 fp-8=mmmmmmmm -39: (b7) r1 = 1 -; if (syscall->string_args_len[arg] != 0) { -40: (bf) r2 = r0 -41: (07) r2 += 4 -42: (69) r3 = *(u16 *)(r0 +4) - R0=map_value(id=0,off=0,ks=4,vs=14,imm=0) R1_w=inv1 R2_w=map_value(id=0,off=4,ks=4,vs=14,imm=0) R3_w=inv0 R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=4168,imm=0) R10=fp0,call_-1 fp-8=mmmmmmmm -; if (syscall->string_args_len[arg] != 0) { -43: (15) if r3 == 0x0 goto pc+32 - R0=map_value(id=0,off=0,ks=4,vs=14,imm=0) R1=inv1 R2=map_value(id=0,off=4,ks=4,vs=14,imm=0) R3=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=4168,imm=0) R10=fp0,call_-1 fp-8=mmmmmmmm -; filename_arg = (const void *)args->args[arg]; -44: (67) r1 <<= 3 -45: (bf) r3 = r6 -46: (0f) r3 += r1 -47: (b7) r5 = 64 -48: (79) r3 = *(u64 *)(r3 +16) -dereference of modified ctx ptr R3 off=8 disallowed -processed 46 insns (limit 1000000) max_states_per_insn 0 total_states 12 peak_states 12 mark_read 7 - */ - -#define __loop_iter(arg) \ - if (syscall->string_args_len[arg] != 0) { \ - unsigned int filename_len = syscall->string_args_len[arg]; \ - const void *filename_arg = (const void *)args->args[arg]; \ - if (filename_len <= sizeof(augmented_args->filename.value)) \ - len += augmented_filename__read(&augmented_args->filename, filename_arg, filename_len); -#define loop_iter_first() __loop_iter(0); } -#define loop_iter(arg) else __loop_iter(arg); } -#define loop_iter_last(arg) else __loop_iter(arg); __asm__ __volatile__("": : :"memory"); } - - loop_iter_first() - loop_iter(1) - loop_iter(2) - loop_iter(3) - loop_iter(4) - loop_iter_last(5) + bpf_tail_call(args, &syscalls_sys_enter, augmented_args->args.syscall_nr); - /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ - return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, augmented_args, len); + // If not found on the PROG_ARRAY syscalls map, then we're filtering it: + return 0; } SEC("raw_syscalls:sys_exit") int sys_exit(struct syscall_exit_args *args) { struct syscall_exit_args exit_args; - struct syscall *syscall; if (pid_filter__has(&pids_filtered, getpid())) return 0; probe_read(&exit_args, sizeof(exit_args), args); - - syscall = bpf_map_lookup_elem(&syscalls, &exit_args.syscall_nr); - if (syscall == NULL || !syscall->enabled) - return 0; - - return 1; + /* + * Jump to syscall specific return augmenter, even if the default one, + * "!raw_syscalls:unaugmented" that will just return 1 to return the + * unagmented tracepoint payload. + */ + bpf_tail_call(args, &syscalls_sys_exit, exit_args.syscall_nr); + /* + * If not found on the PROG_ARRAY syscalls map, then we're filtering it: + */ + return 0; } license(GPL); diff --git a/tools/perf/include/bpf/bpf.h b/tools/perf/include/bpf/bpf.h index 2eac6d804b2d..b422aeef5339 100644 --- a/tools/perf/include/bpf/bpf.h +++ b/tools/perf/include/bpf/bpf.h @@ -45,6 +45,8 @@ struct ____btf_map_##name __attribute__((section(".maps." #name), used)) \ static int (*bpf_map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags) = (void *)BPF_FUNC_map_update_elem; static void *(*bpf_map_lookup_elem)(struct bpf_map *map, void *key) = (void *)BPF_FUNC_map_lookup_elem; +static void (*bpf_tail_call)(void *ctx, void *map, int index) = (void *)BPF_FUNC_tail_call; + #define SEC(NAME) __attribute__((section(NAME), used)) #define probe(function, vars) \ diff --git a/tools/perf/lib/Build b/tools/perf/lib/Build new file mode 100644 index 000000000000..c31f1c111f8f --- /dev/null +++ b/tools/perf/lib/Build @@ -0,0 +1,12 @@ +libperf-y += core.o +libperf-y += cpumap.o +libperf-y += threadmap.o +libperf-y += evsel.o +libperf-y += evlist.o +libperf-y += zalloc.o +libperf-y += xyarray.o +libperf-y += lib.o + +$(OUTPUT)zalloc.o: ../../lib/zalloc.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/lib/Documentation/Makefile b/tools/perf/lib/Documentation/Makefile new file mode 100644 index 000000000000..586425a88795 --- /dev/null +++ b/tools/perf/lib/Documentation/Makefile @@ -0,0 +1,7 @@ +all: + rst2man man/libperf.rst > man/libperf.7 + rst2pdf tutorial/tutorial.rst + +clean: + rm -f man/libperf.7 + rm -f tutorial/tutorial.pdf diff --git a/tools/perf/lib/Documentation/man/libperf.rst b/tools/perf/lib/Documentation/man/libperf.rst new file mode 100644 index 000000000000..09a270fccb9c --- /dev/null +++ b/tools/perf/lib/Documentation/man/libperf.rst @@ -0,0 +1,100 @@ +.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +libperf + +The libperf library provides an API to access the linux kernel perf +events subsystem. It provides the following high level objects: + + - struct perf_cpu_map + - struct perf_thread_map + - struct perf_evlist + - struct perf_evsel + +reference +========= +Function reference by header files: + +perf/core.h +----------- +.. code-block:: c + + typedef int (\*libperf_print_fn_t)(enum libperf_print_level level, + const char \*, va_list ap); + + void libperf_set_print(libperf_print_fn_t fn); + +perf/cpumap.h +------------- +.. code-block:: c + + struct perf_cpu_map \*perf_cpu_map__dummy_new(void); + struct perf_cpu_map \*perf_cpu_map__new(const char \*cpu_list); + struct perf_cpu_map \*perf_cpu_map__read(FILE \*file); + struct perf_cpu_map \*perf_cpu_map__get(struct perf_cpu_map \*map); + void perf_cpu_map__put(struct perf_cpu_map \*map); + int perf_cpu_map__cpu(const struct perf_cpu_map \*cpus, int idx); + int perf_cpu_map__nr(const struct perf_cpu_map \*cpus); + perf_cpu_map__for_each_cpu(cpu, idx, cpus) + +perf/threadmap.h +---------------- +.. code-block:: c + + struct perf_thread_map \*perf_thread_map__new_dummy(void); + void perf_thread_map__set_pid(struct perf_thread_map \*map, int thread, pid_t pid); + char \*perf_thread_map__comm(struct perf_thread_map \*map, int thread); + struct perf_thread_map \*perf_thread_map__get(struct perf_thread_map \*map); + void perf_thread_map__put(struct perf_thread_map \*map); + +perf/evlist.h +------------- +.. code-block:: + + void perf_evlist__init(struct perf_evlist \*evlist); + void perf_evlist__add(struct perf_evlist \*evlist, + struct perf_evsel \*evsel); + void perf_evlist__remove(struct perf_evlist \*evlist, + struct perf_evsel \*evsel); + struct perf_evlist \*perf_evlist__new(void); + void perf_evlist__delete(struct perf_evlist \*evlist); + struct perf_evsel\* perf_evlist__next(struct perf_evlist \*evlist, + struct perf_evsel \*evsel); + int perf_evlist__open(struct perf_evlist \*evlist); + void perf_evlist__close(struct perf_evlist \*evlist); + void perf_evlist__enable(struct perf_evlist \*evlist); + void perf_evlist__disable(struct perf_evlist \*evlist); + perf_evlist__for_each_evsel(evlist, pos) + void perf_evlist__set_maps(struct perf_evlist \*evlist, + struct perf_cpu_map \*cpus, + struct perf_thread_map \*threads); + +perf/evsel.h +------------ +.. code-block:: c + + struct perf_counts_values { + union { + struct { + uint64_t val; + uint64_t ena; + uint64_t run; + }; + uint64_t values[3]; + }; + }; + + void perf_evsel__init(struct perf_evsel \*evsel, + struct perf_event_attr \*attr); + struct perf_evsel \*perf_evsel__new(struct perf_event_attr \*attr); + void perf_evsel__delete(struct perf_evsel \*evsel); + int perf_evsel__open(struct perf_evsel \*evsel, struct perf_cpu_map \*cpus, + struct perf_thread_map \*threads); + void perf_evsel__close(struct perf_evsel \*evsel); + int perf_evsel__read(struct perf_evsel \*evsel, int cpu, int thread, + struct perf_counts_values \*count); + int perf_evsel__enable(struct perf_evsel \*evsel); + int perf_evsel__disable(struct perf_evsel \*evsel); + int perf_evsel__apply_filter(struct perf_evsel \*evsel, const char \*filter); + struct perf_cpu_map \*perf_evsel__cpus(struct perf_evsel \*evsel); + struct perf_thread_map \*perf_evsel__threads(struct perf_evsel \*evsel); + struct perf_event_attr \*perf_evsel__attr(struct perf_evsel \*evsel); diff --git a/tools/perf/lib/Documentation/tutorial/tutorial.rst b/tools/perf/lib/Documentation/tutorial/tutorial.rst new file mode 100644 index 000000000000..7be7bc27b385 --- /dev/null +++ b/tools/perf/lib/Documentation/tutorial/tutorial.rst @@ -0,0 +1,123 @@ +.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +libperf tutorial +================ + +Compile and install libperf from kernel sources +=============================================== +.. code-block:: bash + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + cd linux/tools/perf/lib + make + sudo make install prefix=/usr + +Libperf object +============== +The libperf library provides several high level objects: + +struct perf_cpu_map + Provides a cpu list abstraction. + +struct perf_thread_map + Provides a thread list abstraction. + +struct perf_evsel + Provides an abstraction for single a perf event. + +struct perf_evlist + Gathers several struct perf_evsel object and performs functions on all of them. + +The exported API binds these objects together, +for full reference see the libperf.7 man page. + +Examples +======== +Examples aim to explain libperf functionality on simple use cases. +They are based in on a checked out linux kernel git tree: + +.. code-block:: bash + + $ cd tools/perf/lib/Documentation/tutorial/ + $ ls -d ex-* + ex-1-compile ex-2-evsel-stat ex-3-evlist-stat + +ex-1-compile example +==================== +This example shows the basic usage of *struct perf_cpu_map*, +how to create it and display its cpus: + +.. code-block:: bash + + $ cd ex-1-compile/ + $ make + gcc -o test test.c -lperf + $ ./test + 0 1 2 3 4 5 6 7 + + +The full code listing is here: + +.. code-block:: c + + 1 #include <perf/cpumap.h> + 2 + 3 int main(int argc, char **Argv) + 4 { + 5 struct perf_cpu_map *cpus; + 6 int cpu, tmp; + 7 + 8 cpus = perf_cpu_map__new(NULL); + 9 + 10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) + 11 fprintf(stdout, "%d ", cpu); + 12 + 13 fprintf(stdout, "\n"); + 14 + 15 perf_cpu_map__put(cpus); + 16 return 0; + 17 } + + +First you need to include the proper header to have *struct perf_cpumap* +declaration and functions: + +.. code-block:: c + + 1 #include <perf/cpumap.h> + + +The *struct perf_cpumap* object is created by *perf_cpu_map__new* call. +The *NULL* argument asks it to populate the object with the current online CPUs list: + +.. code-block:: c + + 8 cpus = perf_cpu_map__new(NULL); + +This is paired with a *perf_cpu_map__put*, that drops its reference at the end, possibly deleting it. + +.. code-block:: c + + 15 perf_cpu_map__put(cpus); + +The iteration through the *struct perf_cpumap* CPUs is done using the *perf_cpu_map__for_each_cpu* +macro which requires 3 arguments: + +- cpu - the cpu numer +- tmp - iteration helper variable +- cpus - the *struct perf_cpumap* object + +.. code-block:: c + + 10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) + 11 fprintf(stdout, "%d ", cpu); + +ex-2-evsel-stat example +======================= + +TBD + +ex-3-evlist-stat example +======================== + +TBD diff --git a/tools/perf/lib/Makefile b/tools/perf/lib/Makefile new file mode 100644 index 000000000000..a67efb8d9d39 --- /dev/null +++ b/tools/perf/lib/Makefile @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +# Most of this file is copied from tools/lib/bpf/Makefile + +LIBPERF_VERSION = 0 +LIBPERF_PATCHLEVEL = 0 +LIBPERF_EXTRAVERSION = 1 + +MAKEFLAGS += --no-print-directory + +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(CURDIR))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +#$(info Determined 'srctree' to be $(srctree)) +endif + +INSTALL = install + +# Use DESTDIR for installing into a different root directory. +# This is useful for building a package. The program will be +# installed in this directory as if it was the root directory. +# Then the build tool can move it later. +DESTDIR ?= +DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' + +include $(srctree)/tools/scripts/Makefile.include +include $(srctree)/tools/scripts/Makefile.arch + +ifeq ($(LP64), 1) + libdir_relative = lib64 +else + libdir_relative = lib +endif + +prefix ?= +libdir = $(prefix)/$(libdir_relative) + +# Shell quotes +libdir_SQ = $(subst ','\'',$(libdir)) +libdir_relative_SQ = $(subst ','\'',$(libdir_relative)) + +ifeq ("$(origin V)", "command line") + VERBOSE = $(V) +endif +ifndef VERBOSE + VERBOSE = 0 +endif + +ifeq ($(VERBOSE),1) + Q = +else + Q = @ +endif + +# Set compile option CFLAGS +ifdef EXTRA_CFLAGS + CFLAGS := $(EXTRA_CFLAGS) +else + CFLAGS := -g -Wall +endif + +INCLUDES = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(SRCARCH)/include/ -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi -I$(srctree)/tools/include/uapi + +# Append required CFLAGS +override CFLAGS += $(EXTRA_WARNINGS) +override CFLAGS += -Werror -Wall +override CFLAGS += -fPIC +override CFLAGS += $(INCLUDES) +override CFLAGS += -fvisibility=hidden + +all: + +export srctree OUTPUT CC LD CFLAGS V +export DESTDIR DESTDIR_SQ + +include $(srctree)/tools/build/Makefile.include + +VERSION_SCRIPT := libperf.map + +PATCHLEVEL = $(LIBPERF_PATCHLEVEL) +EXTRAVERSION = $(LIBPERF_EXTRAVERSION) +VERSION = $(LIBPERF_VERSION).$(LIBPERF_PATCHLEVEL).$(LIBPERF_EXTRAVERSION) + +LIBPERF_SO := $(OUTPUT)libperf.so.$(VERSION) +LIBPERF_A := $(OUTPUT)libperf.a +LIBPERF_IN := $(OUTPUT)libperf-in.o +LIBPERF_PC := $(OUTPUT)libperf.pc + +LIBPERF_ALL := $(LIBPERF_A) $(OUTPUT)libperf.so* + +$(LIBPERF_IN): FORCE + $(Q)$(MAKE) $(build)=libperf + +$(LIBPERF_A): $(LIBPERF_IN) + $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) + +$(LIBPERF_SO): $(LIBPERF_IN) + $(QUIET_LINK)$(CC) --shared -Wl,-soname,libperf.so \ + -Wl,--version-script=$(VERSION_SCRIPT) $^ -o $@ + @ln -sf $(@F) $(OUTPUT)libperf.so + @ln -sf $(@F) $(OUTPUT)libperf.so.$(LIBPERF_VERSION) + + +libs: $(LIBPERF_A) $(LIBPERF_SO) $(LIBPERF_PC) + +all: fixdep + $(Q)$(MAKE) libs + +clean: + $(call QUIET_CLEAN, libperf) $(RM) $(LIBPERF_A) \ + *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBPERF_VERSION) .*.d .*.cmd LIBPERF-CFLAGS $(LIBPERF_PC) + $(Q)$(MAKE) -C tests clean + +tests: + $(Q)$(MAKE) -C tests + $(Q)$(MAKE) -C tests run + +$(LIBPERF_PC): + $(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \ + -e "s|@LIBDIR@|$(libdir_SQ)|" \ + -e "s|@VERSION@|$(VERSION)|" \ + < libperf.pc.template > $@ + +define do_install_mkdir + if [ ! -d '$(DESTDIR_SQ)$1' ]; then \ + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \ + fi +endef + +define do_install + if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ + fi; \ + $(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR_SQ)$2' +endef + +install_lib: libs + $(call QUIET_INSTALL, $(LIBPERF_ALL)) \ + $(call do_install_mkdir,$(libdir_SQ)); \ + cp -fpR $(LIBPERF_ALL) $(DESTDIR)$(libdir_SQ) + +install_headers: + $(call QUIET_INSTALL, headers) \ + $(call do_install,include/perf/core.h,$(prefix)/include/perf,644); \ + $(call do_install,include/perf/cpumap.h,$(prefix)/include/perf,644); \ + $(call do_install,include/perf/threadmap.h,$(prefix)/include/perf,644); \ + $(call do_install,include/perf/evlist.h,$(prefix)/include/perf,644); \ + $(call do_install,include/perf/evsel.h,$(prefix)/include/perf,644); + +install_pkgconfig: $(LIBPERF_PC) + $(call QUIET_INSTALL, $(LIBPERF_PC)) \ + $(call do_install,$(LIBPERF_PC),$(libdir_SQ)/pkgconfig,644) + +install: install_lib install_headers install_pkgconfig + +FORCE: + +.PHONY: all install clean tests FORCE diff --git a/tools/perf/lib/core.c b/tools/perf/lib/core.c new file mode 100644 index 000000000000..29d5e3348718 --- /dev/null +++ b/tools/perf/lib/core.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define __printf(a, b) __attribute__((format(printf, a, b))) + +#include <stdio.h> +#include <stdarg.h> +#include <perf/core.h> +#include "internal.h" + +static int __base_pr(enum libperf_print_level level, const char *format, + va_list args) +{ + return vfprintf(stderr, format, args); +} + +static libperf_print_fn_t __libperf_pr = __base_pr; + +void libperf_set_print(libperf_print_fn_t fn) +{ + __libperf_pr = fn; +} + +__printf(2, 3) +void libperf_print(enum libperf_print_level level, const char *format, ...) +{ + va_list args; + + if (!__libperf_pr) + return; + + va_start(args, format); + __libperf_pr(level, format, args); + va_end(args); +} diff --git a/tools/perf/lib/cpumap.c b/tools/perf/lib/cpumap.c new file mode 100644 index 000000000000..1f0e6f334237 --- /dev/null +++ b/tools/perf/lib/cpumap.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <perf/cpumap.h> +#include <stdlib.h> +#include <linux/refcount.h> +#include <internal/cpumap.h> +#include <asm/bug.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <limits.h> + +struct perf_cpu_map *perf_cpu_map__dummy_new(void) +{ + struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); + + if (cpus != NULL) { + cpus->nr = 1; + cpus->map[0] = -1; + refcount_set(&cpus->refcnt, 1); + } + + return cpus; +} + +static void cpu_map__delete(struct perf_cpu_map *map) +{ + if (map) { + WARN_ONCE(refcount_read(&map->refcnt) != 0, + "cpu_map refcnt unbalanced\n"); + free(map); + } +} + +struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map) +{ + if (map) + refcount_inc(&map->refcnt); + return map; +} + +void perf_cpu_map__put(struct perf_cpu_map *map) +{ + if (map && refcount_dec_and_test(&map->refcnt)) + cpu_map__delete(map); +} + +static struct perf_cpu_map *cpu_map__default_new(void) +{ + struct perf_cpu_map *cpus; + int nr_cpus; + + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + if (nr_cpus < 0) + return NULL; + + cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int)); + if (cpus != NULL) { + int i; + + for (i = 0; i < nr_cpus; ++i) + cpus->map[i] = i; + + cpus->nr = nr_cpus; + refcount_set(&cpus->refcnt, 1); + } + + return cpus; +} + +static struct perf_cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) +{ + size_t payload_size = nr_cpus * sizeof(int); + struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + payload_size); + + if (cpus != NULL) { + cpus->nr = nr_cpus; + memcpy(cpus->map, tmp_cpus, payload_size); + refcount_set(&cpus->refcnt, 1); + } + + return cpus; +} + +struct perf_cpu_map *perf_cpu_map__read(FILE *file) +{ + struct perf_cpu_map *cpus = NULL; + int nr_cpus = 0; + int *tmp_cpus = NULL, *tmp; + int max_entries = 0; + int n, cpu, prev; + char sep; + + sep = 0; + prev = -1; + for (;;) { + n = fscanf(file, "%u%c", &cpu, &sep); + if (n <= 0) + break; + if (prev >= 0) { + int new_max = nr_cpus + cpu - prev - 1; + + WARN_ONCE(new_max >= MAX_NR_CPUS, "Perf can support %d CPUs. " + "Consider raising MAX_NR_CPUS\n", MAX_NR_CPUS); + + if (new_max >= max_entries) { + max_entries = new_max + MAX_NR_CPUS / 2; + tmp = realloc(tmp_cpus, max_entries * sizeof(int)); + if (tmp == NULL) + goto out_free_tmp; + tmp_cpus = tmp; + } + + while (++prev < cpu) + tmp_cpus[nr_cpus++] = prev; + } + if (nr_cpus == max_entries) { + max_entries += MAX_NR_CPUS; + tmp = realloc(tmp_cpus, max_entries * sizeof(int)); + if (tmp == NULL) + goto out_free_tmp; + tmp_cpus = tmp; + } + + tmp_cpus[nr_cpus++] = cpu; + if (n == 2 && sep == '-') + prev = cpu; + else + prev = -1; + if (n == 1 || sep == '\n') + break; + } + + if (nr_cpus > 0) + cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); + else + cpus = cpu_map__default_new(); +out_free_tmp: + free(tmp_cpus); + return cpus; +} + +static struct perf_cpu_map *cpu_map__read_all_cpu_map(void) +{ + struct perf_cpu_map *cpus = NULL; + FILE *onlnf; + + onlnf = fopen("/sys/devices/system/cpu/online", "r"); + if (!onlnf) + return cpu_map__default_new(); + + cpus = perf_cpu_map__read(onlnf); + fclose(onlnf); + return cpus; +} + +struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) +{ + struct perf_cpu_map *cpus = NULL; + unsigned long start_cpu, end_cpu = 0; + char *p = NULL; + int i, nr_cpus = 0; + int *tmp_cpus = NULL, *tmp; + int max_entries = 0; + + if (!cpu_list) + return cpu_map__read_all_cpu_map(); + + /* + * must handle the case of empty cpumap to cover + * TOPOLOGY header for NUMA nodes with no CPU + * ( e.g., because of CPU hotplug) + */ + if (!isdigit(*cpu_list) && *cpu_list != '\0') + goto out; + + while (isdigit(*cpu_list)) { + p = NULL; + start_cpu = strtoul(cpu_list, &p, 0); + if (start_cpu >= INT_MAX + || (*p != '\0' && *p != ',' && *p != '-')) + goto invalid; + + if (*p == '-') { + cpu_list = ++p; + p = NULL; + end_cpu = strtoul(cpu_list, &p, 0); + + if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) + goto invalid; + + if (end_cpu < start_cpu) + goto invalid; + } else { + end_cpu = start_cpu; + } + + WARN_ONCE(end_cpu >= MAX_NR_CPUS, "Perf can support %d CPUs. " + "Consider raising MAX_NR_CPUS\n", MAX_NR_CPUS); + + for (; start_cpu <= end_cpu; start_cpu++) { + /* check for duplicates */ + for (i = 0; i < nr_cpus; i++) + if (tmp_cpus[i] == (int)start_cpu) + goto invalid; + + if (nr_cpus == max_entries) { + max_entries += MAX_NR_CPUS; + tmp = realloc(tmp_cpus, max_entries * sizeof(int)); + if (tmp == NULL) + goto invalid; + tmp_cpus = tmp; + } + tmp_cpus[nr_cpus++] = (int)start_cpu; + } + if (*p) + ++p; + + cpu_list = p; + } + + if (nr_cpus > 0) + cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); + else if (*cpu_list != '\0') + cpus = cpu_map__default_new(); + else + cpus = perf_cpu_map__dummy_new(); +invalid: + free(tmp_cpus); +out: + return cpus; +} + +int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx) +{ + if (idx < cpus->nr) + return cpus->map[idx]; + + return -1; +} + +int perf_cpu_map__nr(const struct perf_cpu_map *cpus) +{ + return cpus ? cpus->nr : 1; +} + +bool perf_cpu_map__empty(const struct perf_cpu_map *map) +{ + return map ? map->map[0] == -1 : true; +} + +int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu) +{ + int i; + + for (i = 0; i < cpus->nr; ++i) { + if (cpus->map[i] == cpu) + return i; + } + + return -1; +} diff --git a/tools/perf/lib/evlist.c b/tools/perf/lib/evlist.c new file mode 100644 index 000000000000..f4dc9a208332 --- /dev/null +++ b/tools/perf/lib/evlist.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <perf/evlist.h> +#include <perf/evsel.h> +#include <linux/list.h> +#include <internal/evlist.h> +#include <internal/evsel.h> +#include <linux/zalloc.h> +#include <stdlib.h> +#include <perf/cpumap.h> +#include <perf/threadmap.h> + +void perf_evlist__init(struct perf_evlist *evlist) +{ + INIT_LIST_HEAD(&evlist->entries); + evlist->nr_entries = 0; +} + +static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, + struct perf_evsel *evsel) +{ + /* + * We already have cpus for evsel (via PMU sysfs) so + * keep it, if there's no target cpu list defined. + */ + if (!evsel->own_cpus || evlist->has_user_cpus) { + perf_cpu_map__put(evsel->cpus); + evsel->cpus = perf_cpu_map__get(evlist->cpus); + } else if (evsel->cpus != evsel->own_cpus) { + perf_cpu_map__put(evsel->cpus); + evsel->cpus = perf_cpu_map__get(evsel->own_cpus); + } + + perf_thread_map__put(evsel->threads); + evsel->threads = perf_thread_map__get(evlist->threads); +} + +static void perf_evlist__propagate_maps(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + perf_evlist__for_each_evsel(evlist, evsel) + __perf_evlist__propagate_maps(evlist, evsel); +} + +void perf_evlist__add(struct perf_evlist *evlist, + struct perf_evsel *evsel) +{ + list_add_tail(&evsel->node, &evlist->entries); + evlist->nr_entries += 1; + __perf_evlist__propagate_maps(evlist, evsel); +} + +void perf_evlist__remove(struct perf_evlist *evlist, + struct perf_evsel *evsel) +{ + list_del_init(&evsel->node); + evlist->nr_entries -= 1; +} + +struct perf_evlist *perf_evlist__new(void) +{ + struct perf_evlist *evlist = zalloc(sizeof(*evlist)); + + if (evlist != NULL) + perf_evlist__init(evlist); + + return evlist; +} + +struct perf_evsel * +perf_evlist__next(struct perf_evlist *evlist, struct perf_evsel *prev) +{ + struct perf_evsel *next; + + if (!prev) { + next = list_first_entry(&evlist->entries, + struct perf_evsel, + node); + } else { + next = list_next_entry(prev, node); + } + + /* Empty list is noticed here so don't need checking on entry. */ + if (&next->node == &evlist->entries) + return NULL; + + return next; +} + +void perf_evlist__delete(struct perf_evlist *evlist) +{ + free(evlist); +} + +void perf_evlist__set_maps(struct perf_evlist *evlist, + struct perf_cpu_map *cpus, + struct perf_thread_map *threads) +{ + /* + * Allow for the possibility that one or another of the maps isn't being + * changed i.e. don't put it. Note we are assuming the maps that are + * being applied are brand new and evlist is taking ownership of the + * original reference count of 1. If that is not the case it is up to + * the caller to increase the reference count. + */ + if (cpus != evlist->cpus) { + perf_cpu_map__put(evlist->cpus); + evlist->cpus = perf_cpu_map__get(cpus); + } + + if (threads != evlist->threads) { + perf_thread_map__put(evlist->threads); + evlist->threads = perf_thread_map__get(threads); + } + + perf_evlist__propagate_maps(evlist); +} + +int perf_evlist__open(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + int err; + + perf_evlist__for_each_entry(evlist, evsel) { + err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); + if (err < 0) + goto out_err; + } + + return 0; + +out_err: + perf_evlist__close(evlist); + return err; +} + +void perf_evlist__close(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + perf_evlist__for_each_entry_reverse(evlist, evsel) + perf_evsel__close(evsel); +} + +void perf_evlist__enable(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + perf_evlist__for_each_entry(evlist, evsel) + perf_evsel__enable(evsel); +} + +void perf_evlist__disable(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + perf_evlist__for_each_entry(evlist, evsel) + perf_evsel__disable(evsel); +} diff --git a/tools/perf/lib/evsel.c b/tools/perf/lib/evsel.c new file mode 100644 index 000000000000..24abc80dd767 --- /dev/null +++ b/tools/perf/lib/evsel.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <perf/evsel.h> +#include <perf/cpumap.h> +#include <perf/threadmap.h> +#include <linux/list.h> +#include <internal/evsel.h> +#include <linux/zalloc.h> +#include <stdlib.h> +#include <internal/xyarray.h> +#include <internal/cpumap.h> +#include <internal/threadmap.h> +#include <internal/lib.h> +#include <linux/string.h> +#include <sys/ioctl.h> + +void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr) +{ + INIT_LIST_HEAD(&evsel->node); + evsel->attr = *attr; +} + +struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) +{ + struct perf_evsel *evsel = zalloc(sizeof(*evsel)); + + if (evsel != NULL) + perf_evsel__init(evsel, attr); + + return evsel; +} + +void perf_evsel__delete(struct perf_evsel *evsel) +{ + free(evsel); +} + +#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y)) + +int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) +{ + evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); + + if (evsel->fd) { + int cpu, thread; + for (cpu = 0; cpu < ncpus; cpu++) { + for (thread = 0; thread < nthreads; thread++) { + FD(evsel, cpu, thread) = -1; + } + } + } + + return evsel->fd != NULL ? 0 : -ENOMEM; +} + +static int +sys_perf_event_open(struct perf_event_attr *attr, + pid_t pid, int cpu, int group_fd, + unsigned long flags) +{ + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); +} + +int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) +{ + int cpu, thread, err = 0; + + if (cpus == NULL) { + static struct perf_cpu_map *empty_cpu_map; + + if (empty_cpu_map == NULL) { + empty_cpu_map = perf_cpu_map__dummy_new(); + if (empty_cpu_map == NULL) + return -ENOMEM; + } + + cpus = empty_cpu_map; + } + + if (threads == NULL) { + static struct perf_thread_map *empty_thread_map; + + if (empty_thread_map == NULL) { + empty_thread_map = perf_thread_map__new_dummy(); + if (empty_thread_map == NULL) + return -ENOMEM; + } + + threads = empty_thread_map; + } + + if (evsel->fd == NULL && + perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) + return -ENOMEM; + + for (cpu = 0; cpu < cpus->nr; cpu++) { + for (thread = 0; thread < threads->nr; thread++) { + int fd; + + fd = sys_perf_event_open(&evsel->attr, + threads->map[thread].pid, + cpus->map[cpu], -1, 0); + + if (fd < 0) + return -errno; + + FD(evsel, cpu, thread) = fd; + } + } + + return err; +} + +void perf_evsel__close_fd(struct perf_evsel *evsel) +{ + int cpu, thread; + + for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) + for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) { + close(FD(evsel, cpu, thread)); + FD(evsel, cpu, thread) = -1; + } +} + +void perf_evsel__free_fd(struct perf_evsel *evsel) +{ + xyarray__delete(evsel->fd); + evsel->fd = NULL; +} + +void perf_evsel__close(struct perf_evsel *evsel) +{ + if (evsel->fd == NULL) + return; + + perf_evsel__close_fd(evsel); + perf_evsel__free_fd(evsel); +} + +int perf_evsel__read_size(struct perf_evsel *evsel) +{ + u64 read_format = evsel->attr.read_format; + int entry = sizeof(u64); /* value */ + int size = 0; + int nr = 1; + + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + size += sizeof(u64); + + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + size += sizeof(u64); + + if (read_format & PERF_FORMAT_ID) + entry += sizeof(u64); + + if (read_format & PERF_FORMAT_GROUP) { + nr = evsel->nr_members; + size += sizeof(u64); + } + + size += entry * nr; + return size; +} + +int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, + struct perf_counts_values *count) +{ + size_t size = perf_evsel__read_size(evsel); + + memset(count, 0, sizeof(*count)); + + if (FD(evsel, cpu, thread) < 0) + return -EINVAL; + + if (readn(FD(evsel, cpu, thread), count->values, size) <= 0) + return -errno; + + return 0; +} + +static int perf_evsel__run_ioctl(struct perf_evsel *evsel, + int ioc, void *arg) +{ + int cpu, thread; + + for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) { + for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) { + int fd = FD(evsel, cpu, thread), + err = ioctl(fd, ioc, arg); + + if (err) + return err; + } + } + + return 0; +} + +int perf_evsel__enable(struct perf_evsel *evsel) +{ + return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0); +} + +int perf_evsel__disable(struct perf_evsel *evsel) +{ + return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0); +} + +int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter) +{ + return perf_evsel__run_ioctl(evsel, + PERF_EVENT_IOC_SET_FILTER, + (void *)filter); +} + +struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) +{ + return evsel->cpus; +} + +struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel) +{ + return evsel->threads; +} + +struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel) +{ + return &evsel->attr; +} diff --git a/tools/perf/lib/include/internal/cpumap.h b/tools/perf/lib/include/internal/cpumap.h new file mode 100644 index 000000000000..840d4032587b --- /dev/null +++ b/tools/perf/lib/include/internal/cpumap.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_CPUMAP_H +#define __LIBPERF_INTERNAL_CPUMAP_H + +#include <linux/refcount.h> + +struct perf_cpu_map { + refcount_t refcnt; + int nr; + int map[]; +}; + +#ifndef MAX_NR_CPUS +#define MAX_NR_CPUS 2048 +#endif + +int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu); + +#endif /* __LIBPERF_INTERNAL_CPUMAP_H */ diff --git a/tools/perf/lib/include/internal/evlist.h b/tools/perf/lib/include/internal/evlist.h new file mode 100644 index 000000000000..448891f06e3e --- /dev/null +++ b/tools/perf/lib/include/internal/evlist.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_EVLIST_H +#define __LIBPERF_INTERNAL_EVLIST_H + +#include <linux/list.h> + +struct perf_cpu_map; +struct perf_thread_map; + +struct perf_evlist { + struct list_head entries; + int nr_entries; + bool has_user_cpus; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; +}; + +/** + * __perf_evlist__for_each_entry - iterate thru all the evsels + * @list: list_head instance to iterate + * @evsel: struct perf_evsel iterator + */ +#define __perf_evlist__for_each_entry(list, evsel) \ + list_for_each_entry(evsel, list, node) + +/** + * evlist__for_each_entry - iterate thru all the evsels + * @evlist: perf_evlist instance to iterate + * @evsel: struct perf_evsel iterator + */ +#define perf_evlist__for_each_entry(evlist, evsel) \ + __perf_evlist__for_each_entry(&(evlist)->entries, evsel) + +/** + * __perf_evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order + * @list: list_head instance to iterate + * @evsel: struct evsel iterator + */ +#define __perf_evlist__for_each_entry_reverse(list, evsel) \ + list_for_each_entry_reverse(evsel, list, node) + +/** + * perf_evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order + * @evlist: evlist instance to iterate + * @evsel: struct evsel iterator + */ +#define perf_evlist__for_each_entry_reverse(evlist, evsel) \ + __perf_evlist__for_each_entry_reverse(&(evlist)->entries, evsel) + +#endif /* __LIBPERF_INTERNAL_EVLIST_H */ diff --git a/tools/perf/lib/include/internal/evsel.h b/tools/perf/lib/include/internal/evsel.h new file mode 100644 index 000000000000..8b854d1c9b45 --- /dev/null +++ b/tools/perf/lib/include/internal/evsel.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_EVSEL_H +#define __LIBPERF_INTERNAL_EVSEL_H + +#include <linux/types.h> +#include <linux/perf_event.h> + +struct perf_cpu_map; +struct perf_thread_map; + +struct perf_evsel { + struct list_head node; + struct perf_event_attr attr; + struct perf_cpu_map *cpus; + struct perf_cpu_map *own_cpus; + struct perf_thread_map *threads; + struct xyarray *fd; + + /* parse modifier helper */ + int nr_members; +}; + +int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); +void perf_evsel__close_fd(struct perf_evsel *evsel); +void perf_evsel__free_fd(struct perf_evsel *evsel); +int perf_evsel__read_size(struct perf_evsel *evsel); +int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter); + +#endif /* __LIBPERF_INTERNAL_EVSEL_H */ diff --git a/tools/perf/lib/include/internal/lib.h b/tools/perf/lib/include/internal/lib.h new file mode 100644 index 000000000000..0b56f1201dc9 --- /dev/null +++ b/tools/perf/lib/include/internal/lib.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_LIB_H +#define __LIBPERF_INTERNAL_LIB_H + +#include <unistd.h> + +ssize_t readn(int fd, void *buf, size_t n); +ssize_t writen(int fd, const void *buf, size_t n); + +#endif /* __LIBPERF_INTERNAL_CPUMAP_H */ diff --git a/tools/perf/lib/include/internal/tests.h b/tools/perf/lib/include/internal/tests.h new file mode 100644 index 000000000000..b7a20cd24ee1 --- /dev/null +++ b/tools/perf/lib/include/internal/tests.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_TESTS_H +#define __LIBPERF_INTERNAL_TESTS_H + +#include <stdio.h> + +#define __T_START fprintf(stdout, "- running %s...", __FILE__) +#define __T_OK fprintf(stdout, "OK\n") +#define __T_FAIL fprintf(stdout, "FAIL\n") + +#define __T(text, cond) \ +do { \ + if (!(cond)) { \ + fprintf(stderr, "FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ + return -1; \ + } \ +} while (0) + +#endif /* __LIBPERF_INTERNAL_TESTS_H */ diff --git a/tools/perf/lib/include/internal/threadmap.h b/tools/perf/lib/include/internal/threadmap.h new file mode 100644 index 000000000000..df748baf9eda --- /dev/null +++ b/tools/perf/lib/include/internal/threadmap.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_THREADMAP_H +#define __LIBPERF_INTERNAL_THREADMAP_H + +#include <linux/refcount.h> +#include <sys/types.h> +#include <unistd.h> + +struct thread_map_data { + pid_t pid; + char *comm; +}; + +struct perf_thread_map { + refcount_t refcnt; + int nr; + int err_thread; + struct thread_map_data map[]; +}; + +struct perf_thread_map *perf_thread_map__realloc(struct perf_thread_map *map, int nr); + +#endif /* __LIBPERF_INTERNAL_THREADMAP_H */ diff --git a/tools/perf/util/xyarray.h b/tools/perf/lib/include/internal/xyarray.h index 7ffe562e7ae7..51e35d6c8ec4 100644 --- a/tools/perf/util/xyarray.h +++ b/tools/perf/lib/include/internal/xyarray.h @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _PERF_XYARRAY_H_ -#define _PERF_XYARRAY_H_ 1 +#ifndef __LIBPERF_INTERNAL_XYARRAY_H +#define __LIBPERF_INTERNAL_XYARRAY_H +#include <linux/compiler.h> #include <sys/types.h> struct xyarray { @@ -10,7 +11,7 @@ struct xyarray { size_t entries; size_t max_x; size_t max_y; - char contents[]; + char contents[] __aligned(8); }; struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); @@ -32,4 +33,4 @@ static inline int xyarray__max_x(struct xyarray *xy) return xy->max_x; } -#endif /* _PERF_XYARRAY_H_ */ +#endif /* __LIBPERF_INTERNAL_XYARRAY_H */ diff --git a/tools/perf/lib/include/perf/core.h b/tools/perf/lib/include/perf/core.h new file mode 100644 index 000000000000..c341a7b2c874 --- /dev/null +++ b/tools/perf/lib/include/perf/core.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_CORE_H +#define __LIBPERF_CORE_H + +#include <stdarg.h> + +#ifndef LIBPERF_API +#define LIBPERF_API __attribute__((visibility("default"))) +#endif + +enum libperf_print_level { + LIBPERF_WARN, + LIBPERF_INFO, + LIBPERF_DEBUG, +}; + +typedef int (*libperf_print_fn_t)(enum libperf_print_level level, + const char *, va_list ap); + +LIBPERF_API void libperf_set_print(libperf_print_fn_t fn); + +#endif /* __LIBPERF_CORE_H */ diff --git a/tools/perf/lib/include/perf/cpumap.h b/tools/perf/lib/include/perf/cpumap.h new file mode 100644 index 000000000000..8aa995c59498 --- /dev/null +++ b/tools/perf/lib/include/perf/cpumap.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_CPUMAP_H +#define __LIBPERF_CPUMAP_H + +#include <perf/core.h> +#include <stdio.h> +#include <stdbool.h> + +struct perf_cpu_map; + +LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void); +LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list); +LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file); +LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map); +LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map); +LIBPERF_API int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx); +LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus); +LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map); + +#define perf_cpu_map__for_each_cpu(cpu, idx, cpus) \ + for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx); \ + (idx) < perf_cpu_map__nr(cpus); \ + (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx)) + +#endif /* __LIBPERF_CPUMAP_H */ diff --git a/tools/perf/lib/include/perf/event.h b/tools/perf/lib/include/perf/event.h new file mode 100644 index 000000000000..18106899cb4e --- /dev/null +++ b/tools/perf/lib/include/perf/event.h @@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_EVENT_H +#define __LIBPERF_EVENT_H + +#include <linux/perf_event.h> +#include <linux/types.h> +#include <linux/limits.h> +#include <linux/bpf.h> +#include <sys/types.h> /* pid_t */ + +struct perf_record_mmap { + struct perf_event_header header; + __u32 pid, tid; + __u64 start; + __u64 len; + __u64 pgoff; + char filename[PATH_MAX]; +}; + +struct perf_record_mmap2 { + struct perf_event_header header; + __u32 pid, tid; + __u64 start; + __u64 len; + __u64 pgoff; + __u32 maj; + __u32 min; + __u64 ino; + __u64 ino_generation; + __u32 prot; + __u32 flags; + char filename[PATH_MAX]; +}; + +struct perf_record_comm { + struct perf_event_header header; + __u32 pid, tid; + char comm[16]; +}; + +struct perf_record_namespaces { + struct perf_event_header header; + __u32 pid, tid; + __u64 nr_namespaces; + struct perf_ns_link_info link_info[]; +}; + +struct perf_record_fork { + struct perf_event_header header; + __u32 pid, ppid; + __u32 tid, ptid; + __u64 time; +}; + +struct perf_record_lost { + struct perf_event_header header; + __u64 id; + __u64 lost; +}; + +struct perf_record_lost_samples { + struct perf_event_header header; + __u64 lost; +}; + +/* + * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID + */ +struct perf_record_read { + struct perf_event_header header; + __u32 pid, tid; + __u64 value; + __u64 time_enabled; + __u64 time_running; + __u64 id; +}; + +struct perf_record_throttle { + struct perf_event_header header; + __u64 time; + __u64 id; + __u64 stream_id; +}; + +#ifndef KSYM_NAME_LEN +#define KSYM_NAME_LEN 256 +#endif + +struct perf_record_ksymbol { + struct perf_event_header header; + __u64 addr; + __u32 len; + __u16 ksym_type; + __u16 flags; + char name[KSYM_NAME_LEN]; +}; + +struct perf_record_bpf_event { + struct perf_event_header header; + __u16 type; + __u16 flags; + __u32 id; + + /* for bpf_prog types */ + __u8 tag[BPF_TAG_SIZE]; // prog tag +}; + +struct perf_record_sample { + struct perf_event_header header; + __u64 array[]; +}; + +struct perf_record_switch { + struct perf_event_header header; + __u32 next_prev_pid; + __u32 next_prev_tid; +}; + +struct perf_record_header_attr { + struct perf_event_header header; + struct perf_event_attr attr; + __u64 id[]; +}; + +enum { + PERF_CPU_MAP__CPUS = 0, + PERF_CPU_MAP__MASK = 1, +}; + +struct cpu_map_entries { + __u16 nr; + __u16 cpu[]; +}; + +struct perf_record_record_cpu_map { + __u16 nr; + __u16 long_size; + unsigned long mask[]; +}; + +struct perf_record_cpu_map_data { + __u16 type; + char data[]; +}; + +struct perf_record_cpu_map { + struct perf_event_header header; + struct perf_record_cpu_map_data data; +}; + +enum { + PERF_EVENT_UPDATE__UNIT = 0, + PERF_EVENT_UPDATE__SCALE = 1, + PERF_EVENT_UPDATE__NAME = 2, + PERF_EVENT_UPDATE__CPUS = 3, +}; + +struct perf_record_event_update_cpus { + struct perf_record_cpu_map_data cpus; +}; + +struct perf_record_event_update_scale { + double scale; +}; + +struct perf_record_event_update { + struct perf_event_header header; + __u64 type; + __u64 id; + char data[]; +}; + +#define MAX_EVENT_NAME 64 + +struct perf_trace_event_type { + __u64 event_id; + char name[MAX_EVENT_NAME]; +}; + +struct perf_record_header_event_type { + struct perf_event_header header; + struct perf_trace_event_type event_type; +}; + +struct perf_record_header_tracing_data { + struct perf_event_header header; + __u32 size; +}; + +struct perf_record_header_build_id { + struct perf_event_header header; + pid_t pid; + __u8 build_id[24]; + char filename[]; +}; + +struct id_index_entry { + __u64 id; + __u64 idx; + __u64 cpu; + __u64 tid; +}; + +struct perf_record_id_index { + struct perf_event_header header; + __u64 nr; + struct id_index_entry entries[0]; +}; + +struct perf_record_auxtrace_info { + struct perf_event_header header; + __u32 type; + __u32 reserved__; /* For alignment */ + __u64 priv[]; +}; + +struct perf_record_auxtrace { + struct perf_event_header header; + __u64 size; + __u64 offset; + __u64 reference; + __u32 idx; + __u32 tid; + __u32 cpu; + __u32 reserved__; /* For alignment */ +}; + +#define MAX_AUXTRACE_ERROR_MSG 64 + +struct perf_record_auxtrace_error { + struct perf_event_header header; + __u32 type; + __u32 code; + __u32 cpu; + __u32 pid; + __u32 tid; + __u32 fmt; + __u64 ip; + __u64 time; + char msg[MAX_AUXTRACE_ERROR_MSG]; +}; + +struct perf_record_aux { + struct perf_event_header header; + __u64 aux_offset; + __u64 aux_size; + __u64 flags; +}; + +struct perf_record_itrace_start { + struct perf_event_header header; + __u32 pid; + __u32 tid; +}; + +struct perf_record_thread_map_entry { + __u64 pid; + char comm[16]; +}; + +struct perf_record_thread_map { + struct perf_event_header header; + __u64 nr; + struct perf_record_thread_map_entry entries[]; +}; + +enum { + PERF_STAT_CONFIG_TERM__AGGR_MODE = 0, + PERF_STAT_CONFIG_TERM__INTERVAL = 1, + PERF_STAT_CONFIG_TERM__SCALE = 2, + PERF_STAT_CONFIG_TERM__MAX = 3, +}; + +struct perf_record_stat_config_entry { + __u64 tag; + __u64 val; +}; + +struct perf_record_stat_config { + struct perf_event_header header; + __u64 nr; + struct perf_record_stat_config_entry data[]; +}; + +struct perf_record_stat { + struct perf_event_header header; + + __u64 id; + __u32 cpu; + __u32 thread; + + union { + struct { + __u64 val; + __u64 ena; + __u64 run; + }; + __u64 values[3]; + }; +}; + +struct perf_record_stat_round { + struct perf_event_header header; + __u64 type; + __u64 time; +}; + +struct perf_record_time_conv { + struct perf_event_header header; + __u64 time_shift; + __u64 time_mult; + __u64 time_zero; +}; + +struct perf_record_header_feature { + struct perf_event_header header; + __u64 feat_id; + char data[]; +}; + +struct perf_record_compressed { + struct perf_event_header header; + char data[]; +}; + +enum perf_user_event_type { /* above any possible kernel type */ + PERF_RECORD_USER_TYPE_START = 64, + PERF_RECORD_HEADER_ATTR = 64, + PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */ + PERF_RECORD_HEADER_TRACING_DATA = 66, + PERF_RECORD_HEADER_BUILD_ID = 67, + PERF_RECORD_FINISHED_ROUND = 68, + PERF_RECORD_ID_INDEX = 69, + PERF_RECORD_AUXTRACE_INFO = 70, + PERF_RECORD_AUXTRACE = 71, + PERF_RECORD_AUXTRACE_ERROR = 72, + PERF_RECORD_THREAD_MAP = 73, + PERF_RECORD_CPU_MAP = 74, + PERF_RECORD_STAT_CONFIG = 75, + PERF_RECORD_STAT = 76, + PERF_RECORD_STAT_ROUND = 77, + PERF_RECORD_EVENT_UPDATE = 78, + PERF_RECORD_TIME_CONV = 79, + PERF_RECORD_HEADER_FEATURE = 80, + PERF_RECORD_COMPRESSED = 81, + PERF_RECORD_HEADER_MAX +}; + +union perf_event { + struct perf_event_header header; + struct perf_record_mmap mmap; + struct perf_record_mmap2 mmap2; + struct perf_record_comm comm; + struct perf_record_namespaces namespaces; + struct perf_record_fork fork; + struct perf_record_lost lost; + struct perf_record_lost_samples lost_samples; + struct perf_record_read read; + struct perf_record_throttle throttle; + struct perf_record_sample sample; + struct perf_record_bpf_event bpf; + struct perf_record_ksymbol ksymbol; + struct perf_record_header_attr attr; + struct perf_record_event_update event_update; + struct perf_record_header_event_type event_type; + struct perf_record_header_tracing_data tracing_data; + struct perf_record_header_build_id build_id; + struct perf_record_id_index id_index; + struct perf_record_auxtrace_info auxtrace_info; + struct perf_record_auxtrace auxtrace; + struct perf_record_auxtrace_error auxtrace_error; + struct perf_record_aux aux; + struct perf_record_itrace_start itrace_start; + struct perf_record_switch context_switch; + struct perf_record_thread_map thread_map; + struct perf_record_cpu_map cpu_map; + struct perf_record_stat_config stat_config; + struct perf_record_stat stat; + struct perf_record_stat_round stat_round; + struct perf_record_time_conv time_conv; + struct perf_record_header_feature feat; + struct perf_record_compressed pack; +}; + +#endif /* __LIBPERF_EVENT_H */ diff --git a/tools/perf/lib/include/perf/evlist.h b/tools/perf/lib/include/perf/evlist.h new file mode 100644 index 000000000000..38365f8f3fba --- /dev/null +++ b/tools/perf/lib/include/perf/evlist.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_EVLIST_H +#define __LIBPERF_EVLIST_H + +#include <perf/core.h> + +struct perf_evlist; +struct perf_evsel; +struct perf_cpu_map; +struct perf_thread_map; + +LIBPERF_API void perf_evlist__init(struct perf_evlist *evlist); +LIBPERF_API void perf_evlist__add(struct perf_evlist *evlist, + struct perf_evsel *evsel); +LIBPERF_API void perf_evlist__remove(struct perf_evlist *evlist, + struct perf_evsel *evsel); +LIBPERF_API struct perf_evlist *perf_evlist__new(void); +LIBPERF_API void perf_evlist__delete(struct perf_evlist *evlist); +LIBPERF_API struct perf_evsel* perf_evlist__next(struct perf_evlist *evlist, + struct perf_evsel *evsel); +LIBPERF_API int perf_evlist__open(struct perf_evlist *evlist); +LIBPERF_API void perf_evlist__close(struct perf_evlist *evlist); +LIBPERF_API void perf_evlist__enable(struct perf_evlist *evlist); +LIBPERF_API void perf_evlist__disable(struct perf_evlist *evlist); + +#define perf_evlist__for_each_evsel(evlist, pos) \ + for ((pos) = perf_evlist__next((evlist), NULL); \ + (pos) != NULL; \ + (pos) = perf_evlist__next((evlist), (pos))) + +LIBPERF_API void perf_evlist__set_maps(struct perf_evlist *evlist, + struct perf_cpu_map *cpus, + struct perf_thread_map *threads); + +#endif /* __LIBPERF_EVLIST_H */ diff --git a/tools/perf/lib/include/perf/evsel.h b/tools/perf/lib/include/perf/evsel.h new file mode 100644 index 000000000000..4388667f265c --- /dev/null +++ b/tools/perf/lib/include/perf/evsel.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_EVSEL_H +#define __LIBPERF_EVSEL_H + +#include <stdint.h> +#include <perf/core.h> + +struct perf_evsel; +struct perf_event_attr; +struct perf_cpu_map; +struct perf_thread_map; + +struct perf_counts_values { + union { + struct { + uint64_t val; + uint64_t ena; + uint64_t run; + }; + uint64_t values[3]; + }; +}; + +LIBPERF_API void perf_evsel__init(struct perf_evsel *evsel, + struct perf_event_attr *attr); +LIBPERF_API struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr); +LIBPERF_API void perf_evsel__delete(struct perf_evsel *evsel); +LIBPERF_API int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads); +LIBPERF_API void perf_evsel__close(struct perf_evsel *evsel); +LIBPERF_API int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, + struct perf_counts_values *count); +LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel); +LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel); +LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel); +LIBPERF_API struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel); +LIBPERF_API struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel); + +#endif /* __LIBPERF_EVSEL_H */ diff --git a/tools/perf/lib/include/perf/threadmap.h b/tools/perf/lib/include/perf/threadmap.h new file mode 100644 index 000000000000..a7c50de8d010 --- /dev/null +++ b/tools/perf/lib/include/perf/threadmap.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_THREADMAP_H +#define __LIBPERF_THREADMAP_H + +#include <perf/core.h> +#include <sys/types.h> + +struct perf_thread_map; + +LIBPERF_API struct perf_thread_map *perf_thread_map__new_dummy(void); + +LIBPERF_API void perf_thread_map__set_pid(struct perf_thread_map *map, int thread, pid_t pid); +LIBPERF_API char *perf_thread_map__comm(struct perf_thread_map *map, int thread); +LIBPERF_API int perf_thread_map__nr(struct perf_thread_map *threads); +LIBPERF_API pid_t perf_thread_map__pid(struct perf_thread_map *map, int thread); + +LIBPERF_API struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map); +LIBPERF_API void perf_thread_map__put(struct perf_thread_map *map); + +#endif /* __LIBPERF_THREADMAP_H */ diff --git a/tools/perf/lib/internal.h b/tools/perf/lib/internal.h new file mode 100644 index 000000000000..dc92f241732e --- /dev/null +++ b/tools/perf/lib/internal.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_H +#define __LIBPERF_INTERNAL_H + +void libperf_print(enum libperf_print_level level, + const char *format, ...) + __attribute__((format(printf, 2, 3))); + +#define __pr(level, fmt, ...) \ +do { \ + libperf_print(level, "libperf: " fmt, ##__VA_ARGS__); \ +} while (0) + +#define pr_warning(fmt, ...) __pr(LIBPERF_WARN, fmt, ##__VA_ARGS__) +#define pr_info(fmt, ...) __pr(LIBPERF_INFO, fmt, ##__VA_ARGS__) +#define pr_debug(fmt, ...) __pr(LIBPERF_DEBUG, fmt, ##__VA_ARGS__) + +#endif /* __LIBPERF_INTERNAL_H */ diff --git a/tools/perf/lib/lib.c b/tools/perf/lib/lib.c new file mode 100644 index 000000000000..2a81819c3b8c --- /dev/null +++ b/tools/perf/lib/lib.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <unistd.h> +#include <stdbool.h> +#include <errno.h> +#include <linux/kernel.h> +#include <internal/lib.h> + +static ssize_t ion(bool is_read, int fd, void *buf, size_t n) +{ + void *buf_start = buf; + size_t left = n; + + while (left) { + /* buf must be treated as const if !is_read. */ + ssize_t ret = is_read ? read(fd, buf, left) : + write(fd, buf, left); + + if (ret < 0 && errno == EINTR) + continue; + if (ret <= 0) + return ret; + + left -= ret; + buf += ret; + } + + BUG_ON((size_t)(buf - buf_start) != n); + return n; +} + +/* + * Read exactly 'n' bytes or return an error. + */ +ssize_t readn(int fd, void *buf, size_t n) +{ + return ion(true, fd, buf, n); +} + +/* + * Write exactly 'n' bytes or return an error. + */ +ssize_t writen(int fd, const void *buf, size_t n) +{ + /* ion does not modify buf. */ + return ion(false, fd, (void *)buf, n); +} diff --git a/tools/perf/lib/libperf.map b/tools/perf/lib/libperf.map new file mode 100644 index 000000000000..dc4d66363bc4 --- /dev/null +++ b/tools/perf/lib/libperf.map @@ -0,0 +1,43 @@ +LIBPERF_0.0.1 { + global: + libperf_set_print; + perf_cpu_map__dummy_new; + perf_cpu_map__get; + perf_cpu_map__put; + perf_cpu_map__new; + perf_cpu_map__read; + perf_cpu_map__nr; + perf_cpu_map__cpu; + perf_cpu_map__empty; + perf_thread_map__new_dummy; + perf_thread_map__set_pid; + perf_thread_map__comm; + perf_thread_map__nr; + perf_thread_map__pid; + perf_thread_map__get; + perf_thread_map__put; + perf_evsel__new; + perf_evsel__delete; + perf_evsel__enable; + perf_evsel__disable; + perf_evsel__init; + perf_evsel__open; + perf_evsel__close; + perf_evsel__read; + perf_evsel__cpus; + perf_evsel__threads; + perf_evsel__attr; + perf_evlist__new; + perf_evlist__delete; + perf_evlist__open; + perf_evlist__close; + perf_evlist__enable; + perf_evlist__disable; + perf_evlist__init; + perf_evlist__add; + perf_evlist__remove; + perf_evlist__next; + perf_evlist__set_maps; + local: + *; +}; diff --git a/tools/perf/lib/libperf.pc.template b/tools/perf/lib/libperf.pc.template new file mode 100644 index 000000000000..117e4a237b55 --- /dev/null +++ b/tools/perf/lib/libperf.pc.template @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +prefix=@PREFIX@ +libdir=@LIBDIR@ +includedir=${prefix}/include + +Name: libperf +Description: perf library +Version: @VERSION@ +Libs: -L${libdir} -lperf +Cflags: -I${includedir} diff --git a/tools/perf/lib/tests/Makefile b/tools/perf/lib/tests/Makefile new file mode 100644 index 000000000000..1ee4e9ba848b --- /dev/null +++ b/tools/perf/lib/tests/Makefile @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +TESTS = test-cpumap test-threadmap test-evlist test-evsel + +TESTS_SO := $(addsuffix -so,$(TESTS)) +TESTS_A := $(addsuffix -a,$(TESTS)) + +# Set compile option CFLAGS +ifdef EXTRA_CFLAGS + CFLAGS := $(EXTRA_CFLAGS) +else + CFLAGS := -g -Wall +endif + +all: + +include $(srctree)/tools/scripts/Makefile.include + +INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include + +$(TESTS_A): FORCE + $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a + +$(TESTS_SO): FORCE + $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) -lperf + +all: $(TESTS_A) $(TESTS_SO) + +run: + @echo "running static:" + @for i in $(TESTS_A); do ./$$i; done + @echo "running dynamic:" + @for i in $(TESTS_SO); do LD_LIBRARY_PATH=../ ./$$i; done + +clean: + $(call QUIET_CLEAN, tests)$(RM) $(TESTS_A) $(TESTS_SO) + +.PHONY: all clean FORCE diff --git a/tools/perf/lib/tests/test-cpumap.c b/tools/perf/lib/tests/test-cpumap.c new file mode 100644 index 000000000000..76a43cfb83a1 --- /dev/null +++ b/tools/perf/lib/tests/test-cpumap.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <perf/cpumap.h> +#include <internal/tests.h> + +int main(int argc, char **argv) +{ + struct perf_cpu_map *cpus; + + __T_START; + + cpus = perf_cpu_map__dummy_new(); + if (!cpus) + return -1; + + perf_cpu_map__get(cpus); + perf_cpu_map__put(cpus); + perf_cpu_map__put(cpus); + + __T_OK; + return 0; +} diff --git a/tools/perf/lib/tests/test-evlist.c b/tools/perf/lib/tests/test-evlist.c new file mode 100644 index 000000000000..4e1407f20ffd --- /dev/null +++ b/tools/perf/lib/tests/test-evlist.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/perf_event.h> +#include <perf/cpumap.h> +#include <perf/threadmap.h> +#include <perf/evlist.h> +#include <perf/evsel.h> +#include <internal/tests.h> + +static int test_stat_cpu(void) +{ + struct perf_cpu_map *cpus; + struct perf_evlist *evlist; + struct perf_evsel *evsel; + struct perf_event_attr attr1 = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, + }; + struct perf_event_attr attr2 = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_TASK_CLOCK, + }; + int err, cpu, tmp; + + cpus = perf_cpu_map__new(NULL); + __T("failed to create cpus", cpus); + + evlist = perf_evlist__new(); + __T("failed to create evlist", evlist); + + evsel = perf_evsel__new(&attr1); + __T("failed to create evsel1", evsel); + + perf_evlist__add(evlist, evsel); + + evsel = perf_evsel__new(&attr2); + __T("failed to create evsel2", evsel); + + perf_evlist__add(evlist, evsel); + + perf_evlist__set_maps(evlist, cpus, NULL); + + err = perf_evlist__open(evlist); + __T("failed to open evsel", err == 0); + + perf_evlist__for_each_evsel(evlist, evsel) { + cpus = perf_evsel__cpus(evsel); + + perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { + struct perf_counts_values counts = { .val = 0 }; + + perf_evsel__read(evsel, cpu, 0, &counts); + __T("failed to read value for evsel", counts.val != 0); + } + } + + perf_evlist__close(evlist); + perf_evlist__delete(evlist); + + perf_cpu_map__put(cpus); + return 0; +} + +static int test_stat_thread(void) +{ + struct perf_counts_values counts = { .val = 0 }; + struct perf_thread_map *threads; + struct perf_evlist *evlist; + struct perf_evsel *evsel; + struct perf_event_attr attr1 = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, + }; + struct perf_event_attr attr2 = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_TASK_CLOCK, + }; + int err; + + threads = perf_thread_map__new_dummy(); + __T("failed to create threads", threads); + + perf_thread_map__set_pid(threads, 0, 0); + + evlist = perf_evlist__new(); + __T("failed to create evlist", evlist); + + evsel = perf_evsel__new(&attr1); + __T("failed to create evsel1", evsel); + + perf_evlist__add(evlist, evsel); + + evsel = perf_evsel__new(&attr2); + __T("failed to create evsel2", evsel); + + perf_evlist__add(evlist, evsel); + + perf_evlist__set_maps(evlist, NULL, threads); + + err = perf_evlist__open(evlist); + __T("failed to open evsel", err == 0); + + perf_evlist__for_each_evsel(evlist, evsel) { + perf_evsel__read(evsel, 0, 0, &counts); + __T("failed to read value for evsel", counts.val != 0); + } + + perf_evlist__close(evlist); + perf_evlist__delete(evlist); + + perf_thread_map__put(threads); + return 0; +} + +static int test_stat_thread_enable(void) +{ + struct perf_counts_values counts = { .val = 0 }; + struct perf_thread_map *threads; + struct perf_evlist *evlist; + struct perf_evsel *evsel; + struct perf_event_attr attr1 = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, + .disabled = 1, + }; + struct perf_event_attr attr2 = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_TASK_CLOCK, + .disabled = 1, + }; + int err; + + threads = perf_thread_map__new_dummy(); + __T("failed to create threads", threads); + + perf_thread_map__set_pid(threads, 0, 0); + + evlist = perf_evlist__new(); + __T("failed to create evlist", evlist); + + evsel = perf_evsel__new(&attr1); + __T("failed to create evsel1", evsel); + + perf_evlist__add(evlist, evsel); + + evsel = perf_evsel__new(&attr2); + __T("failed to create evsel2", evsel); + + perf_evlist__add(evlist, evsel); + + perf_evlist__set_maps(evlist, NULL, threads); + + err = perf_evlist__open(evlist); + __T("failed to open evsel", err == 0); + + perf_evlist__for_each_evsel(evlist, evsel) { + perf_evsel__read(evsel, 0, 0, &counts); + __T("failed to read value for evsel", counts.val == 0); + } + + perf_evlist__enable(evlist); + + perf_evlist__for_each_evsel(evlist, evsel) { + perf_evsel__read(evsel, 0, 0, &counts); + __T("failed to read value for evsel", counts.val != 0); + } + + perf_evlist__disable(evlist); + + perf_evlist__close(evlist); + perf_evlist__delete(evlist); + + perf_thread_map__put(threads); + return 0; +} + +int main(int argc, char **argv) +{ + __T_START; + + test_stat_cpu(); + test_stat_thread(); + test_stat_thread_enable(); + + __T_OK; + return 0; +} diff --git a/tools/perf/lib/tests/test-evsel.c b/tools/perf/lib/tests/test-evsel.c new file mode 100644 index 000000000000..2c648fe5617e --- /dev/null +++ b/tools/perf/lib/tests/test-evsel.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/perf_event.h> +#include <perf/cpumap.h> +#include <perf/threadmap.h> +#include <perf/evsel.h> +#include <internal/tests.h> + +static int test_stat_cpu(void) +{ + struct perf_cpu_map *cpus; + struct perf_evsel *evsel; + struct perf_event_attr attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, + }; + int err, cpu, tmp; + + cpus = perf_cpu_map__new(NULL); + __T("failed to create cpus", cpus); + + evsel = perf_evsel__new(&attr); + __T("failed to create evsel", evsel); + + err = perf_evsel__open(evsel, cpus, NULL); + __T("failed to open evsel", err == 0); + + perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { + struct perf_counts_values counts = { .val = 0 }; + + perf_evsel__read(evsel, cpu, 0, &counts); + __T("failed to read value for evsel", counts.val != 0); + } + + perf_evsel__close(evsel); + perf_evsel__delete(evsel); + + perf_cpu_map__put(cpus); + return 0; +} + +static int test_stat_thread(void) +{ + struct perf_counts_values counts = { .val = 0 }; + struct perf_thread_map *threads; + struct perf_evsel *evsel; + struct perf_event_attr attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_TASK_CLOCK, + }; + int err; + + threads = perf_thread_map__new_dummy(); + __T("failed to create threads", threads); + + perf_thread_map__set_pid(threads, 0, 0); + + evsel = perf_evsel__new(&attr); + __T("failed to create evsel", evsel); + + err = perf_evsel__open(evsel, NULL, threads); + __T("failed to open evsel", err == 0); + + perf_evsel__read(evsel, 0, 0, &counts); + __T("failed to read value for evsel", counts.val != 0); + + perf_evsel__close(evsel); + perf_evsel__delete(evsel); + + perf_thread_map__put(threads); + return 0; +} + +static int test_stat_thread_enable(void) +{ + struct perf_counts_values counts = { .val = 0 }; + struct perf_thread_map *threads; + struct perf_evsel *evsel; + struct perf_event_attr attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_TASK_CLOCK, + .disabled = 1, + }; + int err; + + threads = perf_thread_map__new_dummy(); + __T("failed to create threads", threads); + + perf_thread_map__set_pid(threads, 0, 0); + + evsel = perf_evsel__new(&attr); + __T("failed to create evsel", evsel); + + err = perf_evsel__open(evsel, NULL, threads); + __T("failed to open evsel", err == 0); + + perf_evsel__read(evsel, 0, 0, &counts); + __T("failed to read value for evsel", counts.val == 0); + + err = perf_evsel__enable(evsel); + __T("failed to enable evsel", err == 0); + + perf_evsel__read(evsel, 0, 0, &counts); + __T("failed to read value for evsel", counts.val != 0); + + err = perf_evsel__disable(evsel); + __T("failed to enable evsel", err == 0); + + perf_evsel__close(evsel); + perf_evsel__delete(evsel); + + perf_thread_map__put(threads); + return 0; +} + +int main(int argc, char **argv) +{ + __T_START; + + test_stat_cpu(); + test_stat_thread(); + test_stat_thread_enable(); + + __T_OK; + return 0; +} diff --git a/tools/perf/lib/tests/test-threadmap.c b/tools/perf/lib/tests/test-threadmap.c new file mode 100644 index 000000000000..10a4f4cbbdd5 --- /dev/null +++ b/tools/perf/lib/tests/test-threadmap.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <perf/threadmap.h> +#include <internal/tests.h> + +int main(int argc, char **argv) +{ + struct perf_thread_map *threads; + + __T_START; + + threads = perf_thread_map__new_dummy(); + if (!threads) + return -1; + + perf_thread_map__get(threads); + perf_thread_map__put(threads); + perf_thread_map__put(threads); + + __T_OK; + return 0; +} diff --git a/tools/perf/lib/threadmap.c b/tools/perf/lib/threadmap.c new file mode 100644 index 000000000000..e92c368b0a6c --- /dev/null +++ b/tools/perf/lib/threadmap.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <perf/threadmap.h> +#include <stdlib.h> +#include <linux/refcount.h> +#include <internal/threadmap.h> +#include <string.h> +#include <asm/bug.h> +#include <stdio.h> + +static void perf_thread_map__reset(struct perf_thread_map *map, int start, int nr) +{ + size_t size = (nr - start) * sizeof(map->map[0]); + + memset(&map->map[start], 0, size); + map->err_thread = -1; +} + +struct perf_thread_map *perf_thread_map__realloc(struct perf_thread_map *map, int nr) +{ + size_t size = sizeof(*map) + sizeof(map->map[0]) * nr; + int start = map ? map->nr : 0; + + map = realloc(map, size); + /* + * We only realloc to add more items, let's reset new items. + */ + if (map) + perf_thread_map__reset(map, start, nr); + + return map; +} + +#define thread_map__alloc(__nr) perf_thread_map__realloc(NULL, __nr) + +void perf_thread_map__set_pid(struct perf_thread_map *map, int thread, pid_t pid) +{ + map->map[thread].pid = pid; +} + +char *perf_thread_map__comm(struct perf_thread_map *map, int thread) +{ + return map->map[thread].comm; +} + +struct perf_thread_map *perf_thread_map__new_dummy(void) +{ + struct perf_thread_map *threads = thread_map__alloc(1); + + if (threads != NULL) { + perf_thread_map__set_pid(threads, 0, -1); + threads->nr = 1; + refcount_set(&threads->refcnt, 1); + } + return threads; +} + +static void perf_thread_map__delete(struct perf_thread_map *threads) +{ + if (threads) { + int i; + + WARN_ONCE(refcount_read(&threads->refcnt) != 0, + "thread map refcnt unbalanced\n"); + for (i = 0; i < threads->nr; i++) + free(perf_thread_map__comm(threads, i)); + free(threads); + } +} + +struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map) +{ + if (map) + refcount_inc(&map->refcnt); + return map; +} + +void perf_thread_map__put(struct perf_thread_map *map) +{ + if (map && refcount_dec_and_test(&map->refcnt)) + perf_thread_map__delete(map); +} + +int perf_thread_map__nr(struct perf_thread_map *threads) +{ + return threads ? threads->nr : 1; +} + +pid_t perf_thread_map__pid(struct perf_thread_map *map, int thread) +{ + return map->map[thread].pid; +} diff --git a/tools/perf/lib/xyarray.c b/tools/perf/lib/xyarray.c new file mode 100644 index 000000000000..dcd901d154bb --- /dev/null +++ b/tools/perf/lib/xyarray.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <internal/xyarray.h> +#include <linux/zalloc.h> +#include <stdlib.h> +#include <string.h> + +struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size) +{ + size_t row_size = ylen * entry_size; + struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size); + + if (xy != NULL) { + xy->entry_size = entry_size; + xy->row_size = row_size; + xy->entries = xlen * ylen; + xy->max_x = xlen; + xy->max_y = ylen; + } + + return xy; +} + +void xyarray__reset(struct xyarray *xy) +{ + size_t n = xy->entries * xy->entry_size; + + memset(xy->contents, 0, n); +} + +void xyarray__delete(struct xyarray *xy) +{ + free(xy); +} diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h index 3eb7a39169f6..63e4349a772a 100644 --- a/tools/perf/perf-sys.h +++ b/tools/perf/perf-sys.h @@ -5,54 +5,17 @@ #include <unistd.h> #include <sys/types.h> #include <sys/syscall.h> -#include <linux/types.h> #include <linux/compiler.h> -#include <linux/perf_event.h> -#include <asm/barrier.h> -#ifdef __powerpc__ -#define CPUINFO_PROC {"cpu"} -#endif - -#ifdef __s390__ -#define CPUINFO_PROC {"vendor_id"} -#endif - -#ifdef __sh__ -#define CPUINFO_PROC {"cpu type"} -#endif +struct perf_event_attr; -#ifdef __hppa__ -#define CPUINFO_PROC {"cpu"} -#endif - -#ifdef __sparc__ -#define CPUINFO_PROC {"cpu"} -#endif - -#ifdef __alpha__ -#define CPUINFO_PROC {"cpu model"} -#endif +extern bool test_attr__enabled; +void test_attr__ready(void); +void test_attr__init(void); +void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, + int fd, int group_fd, unsigned long flags); -#ifdef __arm__ -#define CPUINFO_PROC {"model name", "Processor"} -#endif - -#ifdef __mips__ -#define CPUINFO_PROC {"cpu model"} -#endif - -#ifdef __arc__ -#define CPUINFO_PROC {"Processor"} -#endif - -#ifdef __xtensa__ -#define CPUINFO_PROC {"core ID"} -#endif - -#ifndef CPUINFO_PROC -#define CPUINFO_PROC { "model name", } -#endif +#define HAVE_ATTR_TEST static inline int sys_perf_event_open(struct perf_event_attr *attr, diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 97e2628ea5dd..1193b923e801 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0 /* * perf.c * @@ -8,7 +7,10 @@ * perf top, perf record, perf report, etc.) are started. */ #include "builtin.h" +#include "perf.h" +#include "util/build-id.h" +#include "util/cache.h" #include "util/env.h" #include <subcmd/exec-cmd.h> #include "util/config.h" @@ -18,6 +20,9 @@ #include "util/bpf-loader.h" #include "util/debug.h" #include "util/event.h" +#include "util/util.h" +#include "ui/ui.h" +#include "perf-sys.h" #include <api/fs/fs.h> #include <api/fs/tracing_path.h> #include <errno.h> @@ -29,6 +34,7 @@ #include <sys/stat.h> #include <unistd.h> #include <linux/kernel.h> +#include <linux/string.h> #include <linux/zalloc.h> const char perf_usage_string[] = @@ -441,6 +447,9 @@ int main(int argc, const char **argv) srandom(time(NULL)); + /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ + config_exclusive_filename = getenv("PERF_CONFIG"); + err = perf_config(perf_default_config, NULL); if (err) return err; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 74d0124d38f3..74014033df60 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -2,28 +2,7 @@ #ifndef _PERF_PERF_H #define _PERF_PERF_H -#include <time.h> #include <stdbool.h> -#include <linux/types.h> -#include <linux/stddef.h> -#include <linux/perf_event.h> - -extern bool test_attr__enabled; -void test_attr__ready(void); -void test_attr__init(void); -void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, - int fd, int group_fd, unsigned long flags); - -#define HAVE_ATTR_TEST -#include "perf-sys.h" - -static inline unsigned long long rdclock(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; -} #ifndef MAX_NR_CPUS #define MAX_NR_CPUS 2048 @@ -35,62 +14,6 @@ extern const char perf_version_string[]; void pthread__unblock_sigwinch(void); -#include "util/target.h" - -struct record_opts { - struct target target; - bool group; - bool inherit_stat; - bool no_buffering; - bool no_inherit; - bool no_inherit_set; - bool no_samples; - bool raw_samples; - bool sample_address; - bool sample_phys_addr; - bool sample_weight; - bool sample_time; - bool sample_time_set; - bool sample_cpu; - bool period; - bool period_set; - bool running_time; - bool full_auxtrace; - bool auxtrace_snapshot_mode; - bool record_namespaces; - bool record_switch_events; - bool all_kernel; - bool all_user; - bool kernel_callchains; - bool user_callchains; - bool tail_synthesize; - bool overwrite; - bool ignore_missing_thread; - bool strict_freq; - bool sample_id; - bool no_bpf_event; - unsigned int freq; - unsigned int mmap_pages; - unsigned int auxtrace_mmap_pages; - unsigned int user_freq; - u64 branch_stack; - u64 sample_intr_regs; - u64 sample_user_regs; - u64 default_interval; - u64 user_interval; - size_t auxtrace_snapshot_size; - const char *auxtrace_snapshot_opts; - bool sample_transaction; - unsigned initial_delay; - bool use_clockid; - clockid_t clockid; - u64 clockid_res_ns; - int nr_cblocks; - int affinity; - int mmap_flush; - unsigned int comp_level; -}; - enum perf_affinity { PERF_AFFINITY_SYS = 0, PERF_AFFINITY_NODE, @@ -98,10 +21,5 @@ enum perf_affinity { PERF_AFFINITY_MAX }; -struct option; -extern const char * const *record_usage; -extern struct option *record_options; extern int version_verbose; - -int record__parse_freq(const struct option *opt, const char *str, int unset); #endif diff --git a/tools/perf/pmu-events/arch/powerpc/power9/memory.json b/tools/perf/pmu-events/arch/powerpc/power9/memory.json index 2e2ebc700c74..c3bb283e37e9 100644 --- a/tools/perf/pmu-events/arch/powerpc/power9/memory.json +++ b/tools/perf/pmu-events/arch/powerpc/power9/memory.json @@ -52,7 +52,7 @@ {, "EventCode": "0x4D02C", "EventName": "PM_PMC1_REWIND", - "BriefDescription": "" + "BriefDescription": "PMC1 rewind event" }, {, "EventCode": "0x15158", diff --git a/tools/perf/pmu-events/arch/powerpc/power9/other.json b/tools/perf/pmu-events/arch/powerpc/power9/other.json index 48cf4f920b3f..62b864269623 100644 --- a/tools/perf/pmu-events/arch/powerpc/power9/other.json +++ b/tools/perf/pmu-events/arch/powerpc/power9/other.json @@ -237,7 +237,7 @@ {, "EventCode": "0xD0B0", "EventName": "PM_HWSYNC", - "BriefDescription": "" + "BriefDescription": "A hwsync instruction was decoded and transferred" }, {, "EventCode": "0x168B0", @@ -1232,7 +1232,7 @@ {, "EventCode": "0xD8AC", "EventName": "PM_LWSYNC", - "BriefDescription": "" + "BriefDescription": "An lwsync instruction was decoded and transferred" }, {, "EventCode": "0x2094", @@ -1747,7 +1747,7 @@ {, "EventCode": "0xD8B0", "EventName": "PM_PTESYNC", - "BriefDescription": "" + "BriefDescription": "A ptesync instruction was counted when the instruction is decoded and transmitted" }, {, "EventCode": "0x26086", @@ -2107,7 +2107,7 @@ {, "EventCode": "0xF080", "EventName": "PM_LSU_STCX_FAIL", - "BriefDescription": "" + "BriefDescription": "The LSU detects the condition that a stcx instruction failed. No requirement to wait for a response from the nest" }, {, "EventCode": "0x30038", diff --git a/tools/perf/pmu-events/arch/x86/icelake/cache.json b/tools/perf/pmu-events/arch/x86/icelake/cache.json new file mode 100644 index 000000000000..3529fc338c17 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/cache.json @@ -0,0 +1,552 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of demand Data Read requests that miss L2 cache. Only not rejected loads are counted.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0x21", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "Demand Data Read miss L2, no rejects" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0x22", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.RFO_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "RFO requests that miss L2 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0x24", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.CODE_RD_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "L2 cache misses when fetching instructions" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts demand requests that miss L2 cache.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0x27", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.ALL_DEMAND_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "Demand requests that miss L2 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. This event accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0x28", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.SWPF_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "SW prefetch requests that miss L2 cache." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xc1", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "Demand Data Read requests that hit L2 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xc2", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.RFO_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "RFO requests that hit L2 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xc4", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.CODE_RD_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "L2 cache hits when fetching instructions, code reads." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. This event accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xc8", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.SWPF_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "SW prefetch requests that hit L2 cache." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of demand Data Read requests (including requests from L1D hardware prefetchers). These loads may hit or miss L2 cache. Only non rejected loads are counted.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xe1", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", + "SampleAfterValue": "200003", + "BriefDescription": "Demand Data Read requests" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xe2", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.ALL_RFO", + "SampleAfterValue": "200003", + "BriefDescription": "RFO requests to L2 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the total number of L2 code requests.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xe4", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.ALL_CODE_RD", + "SampleAfterValue": "200003", + "BriefDescription": "L2 code requests" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts demand requests to L2 cache.", + "EventCode": "0x24", + "Counter": "0,1,2,3", + "UMask": "0xe7", + "PEBScounters": "0,1,2,3", + "EventName": "L2_RQSTS.ALL_DEMAND_REFERENCES", + "SampleAfterValue": "200003", + "BriefDescription": "Demand requests to L2 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", + "EventCode": "0x48", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "L1D_PEND_MISS.PENDING", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of L1D misses that are outstanding" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", + "EventCode": "0x48", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "L1D_PEND_MISS.PENDING_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles with L1D load Misses outstanding.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailablability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "EventCode": "0x48", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "L1D_PEND_MISS.FB_FULL", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailablability." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailablability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "EventCode": "0x48", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "L1D_PEND_MISS.FB_FULL_PERIODS", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailablability.", + "CounterMask": "1", + "EdgeDetect": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "EventCode": "0x48", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "L1D_PEND_MISS.L2_STALL", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of cycles a demand request has waited due to L1D due to lack of L2 resources." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", + "EventCode": "0x51", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "L1D.REPLACEMENT", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of cache lines replaced in L1 data cache." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "EventCode": "0x60", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles with offcore outstanding demand rfo reads transactions in SuperQueue (SQ), queue to uncore.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of offcore outstanding cacheable Core Data Read transactions in the super queue every cycle. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", + "EventCode": "0x60", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD", + "SampleAfterValue": "2000003", + "BriefDescription": "Offcore outstanding cacheable Core Data Read transactions in SuperQueue (SQ), queue to uncore" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", + "EventCode": "0x60", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when offcore outstanding cacheable Core Data Read transactions are present in SuperQueue (SQ), queue to uncore.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", + "EventCode": "0xB0", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", + "SampleAfterValue": "100003", + "BriefDescription": "Demand Data Read requests sent to uncore" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", + "EventCode": "0xB0", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", + "SampleAfterValue": "100003", + "BriefDescription": "Demand RFO requests including regular RFOs, locks, ItoM" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", + "EventCode": "0xB0", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS.ALL_DATA_RD", + "SampleAfterValue": "100003", + "BriefDescription": "Demand and prefetch data reads" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts memory transactions reached the super queue including requests initiated by the core, all L3 prefetches, page walks, etc..", + "EventCode": "0xB0", + "Counter": "0,1,2,3", + "UMask": "0x80", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", + "SampleAfterValue": "100003", + "BriefDescription": "Any memory transaction that reached the SQ." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions that true miss the STLB.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x11", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.STLB_MISS_LOADS", + "SampleAfterValue": "100003", + "BriefDescription": "Retired load instructions that miss the STLB.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired store instructions that true miss the STLB.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x12", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.STLB_MISS_STORES", + "SampleAfterValue": "100003", + "BriefDescription": "Retired store instructions that miss the STLB.", + "Data_LA": "1", + "L1_Hit_Indication": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with locked access.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x21", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.LOCK_LOADS", + "SampleAfterValue": "100007", + "BriefDescription": "Retired load instructions with locked access.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions that split across a cacheline boundary.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x41", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.SPLIT_LOADS", + "SampleAfterValue": "100003", + "BriefDescription": "Retired load instructions that split across a cacheline boundary.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired store instructions that split across a cacheline boundary.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x42", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.SPLIT_STORES", + "SampleAfterValue": "100003", + "BriefDescription": "Retired store instructions that split across a cacheline boundary.", + "Data_LA": "1", + "L1_Hit_Indication": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all retired load instructions. This event accounts for SW prefetch instructions for loads.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x81", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.ALL_LOADS", + "SampleAfterValue": "2000003", + "BriefDescription": "All retired load instructions.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all retired store instructions. This event account for SW prefetch instructions and PREFETCHW instruction for stores.", + "EventCode": "0xD0", + "Counter": "0,1,2,3", + "UMask": "0x82", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_INST_RETIRED.ALL_STORES", + "SampleAfterValue": "2000003", + "BriefDescription": "All retired store instructions.", + "Data_LA": "1", + "L1_Hit_Indication": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source.", + "EventCode": "0xD1", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.L1_HIT", + "SampleAfterValue": "2000003", + "BriefDescription": "Retired load instructions with L1 cache hits as data sources", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with L2 cache hits as data sources.", + "EventCode": "0xD1", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.L2_HIT", + "SampleAfterValue": "100003", + "BriefDescription": "Retired load instructions with L2 cache hits as data sources", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L3 cache.", + "EventCode": "0xD1", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.L3_HIT", + "SampleAfterValue": "50021", + "BriefDescription": "Retired load instructions with L3 cache hits as data sources", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache.", + "EventCode": "0xD1", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.L1_MISS", + "SampleAfterValue": "100003", + "BriefDescription": "Retired load instructions missed L1 cache as data sources", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions missed L2 cache as data sources.", + "EventCode": "0xD1", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.L2_MISS", + "SampleAfterValue": "50021", + "BriefDescription": "Retired load instructions missed L2 cache as data sources", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L3 cache.", + "EventCode": "0xD1", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.L3_MISS", + "SampleAfterValue": "100007", + "BriefDescription": "Retired load instructions missed L3 cache as data sources", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready.", + "EventCode": "0xd1", + "Counter": "0,1,2,3", + "UMask": "0x40", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_RETIRED.FB_HIT", + "SampleAfterValue": "100007", + "BriefDescription": "Number of completed demand load requests that missed the L1, but hit the FB(fill buffer), because a preceding miss to the same cacheline initiated the line to be brought into L1, but data is not yet ready in L1.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache.", + "EventCode": "0xd2", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS", + "SampleAfterValue": "20011", + "BriefDescription": "Retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache.", + "EventCode": "0xd2", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_HIT", + "SampleAfterValue": "20011", + "BriefDescription": "Retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions whose data sources were HitM responses from shared L3.", + "EventCode": "0xd2", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM", + "SampleAfterValue": "20011", + "BriefDescription": "Retired load instructions whose data sources were HitM responses from shared L3", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired load instructions whose data sources were hits in L3 without snoops required.", + "EventCode": "0xd2", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_NONE", + "SampleAfterValue": "100003", + "BriefDescription": "Retired load instructions whose data sources were hits in L3 without snoops required", + "Data_LA": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", + "EventCode": "0xF1", + "Counter": "0,1,2,3", + "UMask": "0x1f", + "PEBScounters": "0,1,2,3", + "EventName": "L2_LINES_IN.ALL", + "SampleAfterValue": "100003", + "BriefDescription": "L2 cache lines filling L2" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the cycles for which the thread is active and the superQ cannot take any more entries.", + "EventCode": "0xF4", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "SQ_MISC.SQ_FULL", + "SampleAfterValue": "100003", + "BriefDescription": "Cycles the thread is active and superQ cannot take any more entries." + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/icelake/floating-point.json b/tools/perf/pmu-events/arch/x86/icelake/floating-point.json new file mode 100644 index 000000000000..594c5551f610 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/floating-point.json @@ -0,0 +1,102 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all microcode Floating Point assists.", + "EventCode": "0xC1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "ASSISTS.FP", + "SampleAfterValue": "100003", + "BriefDescription": "Counts all microcode FP assists.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT14 RCP14 RANGE DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x8", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x10", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 RANGE FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x40", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 RANGE FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 RANGE FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "EventCode": "0xc7", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 RANGE FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element." + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/icelake/frontend.json b/tools/perf/pmu-events/arch/x86/icelake/frontend.json new file mode 100644 index 000000000000..9c3cfbfcec0f --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/frontend.json @@ -0,0 +1,424 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.MITE_UOPS", + "SampleAfterValue": "2000003", + "BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from MITE path" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.MITE_CYCLES_OK", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles MITE is delivering optimal number of Uops", + "CounterMask": "5" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.MITE_CYCLES_ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles MITE is delivering any Uop", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.DSB_UOPS", + "SampleAfterValue": "2000003", + "BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.DSB_CYCLES_OK", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles DSB is delivering optimal number of Uops", + "CounterMask": "5" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.DSB_CYCLES_ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering any Uop", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x30", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.MS_SWITCHES", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of switches from DSB or MITE to the MS", + "CounterMask": "1", + "EdgeDetect": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS). Any instruction over 4 uops will be delivered by the MS. Some instructions such as transcendentals may additionally generate uops from the MS.", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x30", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.MS_UOPS", + "SampleAfterValue": "2000003", + "BriefDescription": "Uops delivered to IDQ while MS is busy" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", + "EventCode": "0x79", + "Counter": "0,1,2,3", + "UMask": "0x30", + "PEBScounters": "0,1,2,3", + "EventName": "IDQ.MS_CYCLES_ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when uops are being delivered to IDQ while MS is busy", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The legacy decode pipeline works at a 16 Byte granularity.", + "EventCode": "0x80", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "ICACHE_16B.IFDATA_STALL", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache miss." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts instruction fetch tag lookups that hit in the instruction cache (L1I). Counts at 64-byte cache-line granularity. Accounts for both cacheable and uncacheable accesses.", + "EventCode": "0x83", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "ICACHE_64B.IFTAG_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "Instruction fetch tag lookups that hit in the instruction cache (L1I). Counts at 64-byte cache-line granularity." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts instruction fetch tag lookups that miss in the instruction cache (L1I). Counts at 64-byte cache-line granularity. Accounts for both cacheable and uncacheable accesses.", + "EventCode": "0x83", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "ICACHE_64B.IFTAG_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "Instruction fetch tag lookups that miss in the instruction cache (L1I). Counts at 64-byte cache-line granularity." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", + "EventCode": "0x83", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "ICACHE_64B.IFTAG_STALL", + "SampleAfterValue": "200003", + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache tag miss." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle.", + "EventCode": "0x9C", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "IDQ_UOPS_NOT_DELIVERED.CORE", + "SampleAfterValue": "2000003", + "BriefDescription": "Uops not delivered by IDQ when backend of the machine is not stalled" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle.", + "EventCode": "0x9c", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when no uops are not delivered by the IDQ when backend of the machine is not stalled", + "CounterMask": "5" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle.", + "EventCode": "0x9C", + "Invert": "1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when optimal number of uops was delivered to the back-end when the back-end is not stalled", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", + "EventCode": "0xAB", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "DSB-to-MITE switch true penalty cycles." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss.", + "EventCode": "0xC6", + "MSRValue": "0x11", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.DSB_MISS", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired Instructions who experienced DSB miss.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss.", + "EventCode": "0xC6", + "MSRValue": "0x12", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.L1I_MISS", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired Instructions who experienced Instruction L1 Cache true miss.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss.", + "EventCode": "0xC6", + "MSRValue": "0x13", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.L2_MISS", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired Instructions who experienced Instruction L2 Cache true miss.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss.", + "EventCode": "0xC6", + "MSRValue": "0x14", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.ITLB_MISS", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired Instructions who experienced iTLB true miss.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss.", + "EventCode": "0xC6", + "MSRValue": "0x15", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.STLB_MISS", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired Instructions who experienced STLB (2nd level TLB) true miss.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 2 cycles which was not interrupted by a back-end stall.", + "EventCode": "0xC6", + "MSRValue": "0x500206", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_2", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 2 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall.", + "EventCode": "0xC6", + "MSRValue": "0x500406", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_4", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops.", + "EventCode": "0xC6", + "MSRValue": "0x500806", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_8", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 8 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops.", + "EventCode": "0xC6", + "MSRValue": "0x501006", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_16", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 16 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops.", + "EventCode": "0xC6", + "MSRValue": "0x502006", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_32", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 32 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall.", + "EventCode": "0xC6", + "MSRValue": "0x504006", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_64", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall.", + "EventCode": "0xC6", + "MSRValue": "0x508006", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_128", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall.", + "EventCode": "0xC6", + "MSRValue": "0x510006", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_256", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall.", + "EventCode": "0xC6", + "MSRValue": "0x520006", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_512", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall.", + "EventCode": "0xC6", + "MSRValue": "0x100206", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_2_BUBBLES_GE_1", + "MSRIndex": "0x3F7", + "SampleAfterValue": "100007", + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end had at least 1 bubble-slot for a period of 2 cycles which was not interrupted by a back-end stall.", + "TakenAlone": "1" + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/icelake/memory.json b/tools/perf/pmu-events/arch/x86/icelake/memory.json new file mode 100644 index 000000000000..f158366b9dd6 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/memory.json @@ -0,0 +1,410 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times a TSX line had a cache conflict.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.ABORT_CONFLICT", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times a transactional abort was signaled due to a data conflict on a transactionally accessed address" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Speculatively counts the number Transactional Synchronization Extensions (TSX) Aborts due to a data capacity limitation for transactional writes.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.ABORT_CAPACITY_WRITE", + "SampleAfterValue": "2000003", + "BriefDescription": "Speculatively counts the number TSX Aborts due to a data capacity limitation for transactional writes." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times a TSX Abort was triggered due to a non-release/commit store to lock.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.ABORT_HLE_STORE_TO_ELIDED_LOCK", + "SampleAfterValue": "100003", + "BriefDescription": "Number of times a HLE transactional region aborted due to a non XRELEASE prefixed instruction writing to an elided lock in the elision buffer" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times a TSX Abort was triggered due to commit but Lock Buffer not empty.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.ABORT_HLE_ELISION_BUFFER_NOT_EMPTY", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE transactional execution aborted due to NoAllocatedElisionBuffer being non-zero." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times a TSX Abort was triggered due to release/commit but data and address mismatch.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.ABORT_HLE_ELISION_BUFFER_MISMATCH", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE transactional execution aborted due to XRELEASE lock not satisfying the address and value requirements in the elision buffer" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times a TSX Abort was triggered due to attempting an unsupported alignment from Lock Buffer.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.ABORT_HLE_ELISION_BUFFER_UNSUPPORTED_ALIGNMENT", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE transactional execution aborted due to an unsupported read alignment from the elision buffer." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times we could not allocate Lock Buffer.", + "EventCode": "0x54", + "Counter": "0,1,2,3", + "UMask": "0x40", + "PEBScounters": "0,1,2,3", + "EventName": "TX_MEM.HLE_ELISION_BUFFER_FULL", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times HLE lock could not be elided due to ElisionBufferAvailable being zero." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Unfriendly TSX abort triggered by a vzeroupper instruction.", + "EventCode": "0x5d", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "TX_EXEC.MISC2", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of times a class of instructions that may cause a transactional abort was executed inside a transactional region" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Unfriendly TSX abort triggered by a nest count that is too deep.", + "EventCode": "0x5d", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "TX_EXEC.MISC3", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an instruction execution caused the transactional nest count supported to be exceeded" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLE_ACTIVITY.CYCLES_L3_MISS", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles while L3 cache miss demand load is outstanding.", + "CounterMask": "2" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3", + "UMask": "0x6", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS", + "SampleAfterValue": "2000003", + "BriefDescription": "Execution stalls while L3 cache miss demand load is outstanding.", + "CounterMask": "6" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Demand Data Read requests who miss L3 cache.", + "EventCode": "0xB0", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", + "SampleAfterValue": "100003", + "BriefDescription": "Demand Data Read requests who miss L3 cache" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", + "EventCode": "0xc3", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", + "SampleAfterValue": "100003", + "BriefDescription": "Number of machine clears due to memory ordering conflicts." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times we entered an HLE region. Does not count nested transactions.", + "EventCode": "0xC8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "HLE_RETIRED.START", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE execution started." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times HLE commit succeeded.", + "EventCode": "0xC8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "HLE_RETIRED.COMMIT", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE execution successfully committed", + "Data_LA": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times HLE abort was triggered.", + "EventCode": "0xc8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "HLE_RETIRED.ABORTED", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE execution aborted due to any reasons (multiple categories may count as one)." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an HLE execution aborted due to various memory events (e.g., read/write capacity and conflicts).", + "EventCode": "0xC8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x8", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "HLE_RETIRED.ABORTED_MEM", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE execution aborted due to various memory events (e.g., read/write capacity and conflicts)." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an HLE execution aborted due to HLE-unfriendly instructions and certain unfriendly events (such as AD assists etc.).", + "EventCode": "0xC8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "HLE_RETIRED.ABORTED_UNFRIENDLY", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE execution aborted due to HLE-unfriendly instructions and certain unfriendly events (such as AD assists etc.)." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an HLE execution aborted due to unfriendly events (such as interrupts).", + "EventCode": "0xC8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "HLE_RETIRED.ABORTED_EVENTS", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an HLE execution aborted due to unfriendly events (such as interrupts)." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions.", + "EventCode": "0xC9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.START", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution started." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times RTM commit succeeded.", + "EventCode": "0xC9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.COMMIT", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution successfully committed" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times RTM abort was triggered.", + "EventCode": "0xc9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.ABORTED", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution aborted.", + "Data_LA": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts).", + "EventCode": "0xC9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x8", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.ABORTED_MEM", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions.", + "EventCode": "0xC9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.ABORTED_UNFRIENDLY", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution aborted due to HLE-unfriendly instructions" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type.", + "EventCode": "0xC9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x40", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.ABORTED_MEMTYPE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution aborted due to incompatible memory type" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 4 categories (e.g. interrupt).", + "EventCode": "0xC9", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RTM_RETIRED.ABORTED_EVENTS", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of times an RTM execution aborted due to none of the previous 4 categories (e.g. interrupt)" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_4", + "MSRIndex": "0x3F6", + "SampleAfterValue": "100003", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x8", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_8", + "MSRIndex": "0x3F6", + "SampleAfterValue": "50021", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x10", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_16", + "MSRIndex": "0x3F6", + "SampleAfterValue": "20011", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x20", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_32", + "MSRIndex": "0x3F6", + "SampleAfterValue": "100007", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x40", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_64", + "MSRIndex": "0x3F6", + "SampleAfterValue": "2003", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x80", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_128", + "MSRIndex": "0x3F6", + "SampleAfterValue": "1009", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x100", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_256", + "MSRIndex": "0x3F6", + "SampleAfterValue": "503", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles.", + "TakenAlone": "1" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency.", + "EventCode": "0xcd", + "MSRValue": "0x200", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_512", + "MSRIndex": "0x3F6", + "SampleAfterValue": "101", + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles.", + "TakenAlone": "1" + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/icelake/other.json b/tools/perf/pmu-events/arch/x86/icelake/other.json new file mode 100644 index 000000000000..f8dfdb847224 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/other.json @@ -0,0 +1,121 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Software can use this event as the denominator for the top-level metrics of the Top-down Microarchitecture Analysis method. This event is counted on a designated fixed counter (Fixed Counter 3) and is an architectural event.", + "Counter": "35", + "UMask": "0x4", + "PEBScounters": "35", + "EventName": "TOPDOWN.SLOTS", + "SampleAfterValue": "10000003", + "BriefDescription": "Counts the number of available slots for an unhalted logical processor." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Core cycles where the core was running with power-delivery for baseline license level 0. This includes non-AVX codes, SSE, AVX 128-bit, and low-current AVX 256-bit codes.", + "EventCode": "0x28", + "Counter": "0,1,2,3", + "UMask": "0x7", + "PEBScounters": "0,1,2,3", + "EventName": "CORE_POWER.LVL0_TURBO_LICENSE", + "SampleAfterValue": "200003", + "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the Non-AVX turbo schedule." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Core cycles where the core was running with power-delivery for license level 1. This includes high current AVX 256-bit instructions as well as low current AVX 512-bit instructions.", + "EventCode": "0x28", + "Counter": "0,1,2,3", + "UMask": "0x18", + "PEBScounters": "0,1,2,3", + "EventName": "CORE_POWER.LVL1_TURBO_LICENSE", + "SampleAfterValue": "200003", + "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX2 turbo schedule." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchtecture). This includes high current AVX 512-bit instructions.", + "EventCode": "0x28", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "CORE_POWER.LVL2_TURBO_LICENSE", + "SampleAfterValue": "200003", + "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", + "EventCode": "0x32", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "SW_PREFETCH_ACCESS.NTA", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of PREFETCHNTA instructions executed." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", + "EventCode": "0x32", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "SW_PREFETCH_ACCESS.T0", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of PREFETCHT0 instructions executed." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "EventCode": "0x32", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "SW_PREFETCH_ACCESS.T1_T2", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of PREFETCHT1 or PREFETCHT2 instructions executed." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", + "EventCode": "0x32", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of PREFETCHW instructions executed." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core.", + "EventCode": "0xa4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "TOPDOWN.SLOTS_P", + "SampleAfterValue": "10000003", + "BriefDescription": "Counts the number of available slots for an unhalted logical processor." + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", + "SampleAfterValue": "10000003", + "BriefDescription": "Issue slots where no uops were being issued due to lack of back end resources." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware Examples include AD (page Access Dirty), FP and AVX related assists.", + "EventCode": "0xc1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x7", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "ASSISTS.ANY", + "SampleAfterValue": "100003", + "BriefDescription": "Number of occurrences where a microcode assist is invoked by hardware." + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/icelake/pipeline.json b/tools/perf/pmu-events/arch/x86/icelake/pipeline.json new file mode 100644 index 000000000000..6d8311e634aa --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/pipeline.json @@ -0,0 +1,892 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter.", + "Counter": "32", + "UMask": "0x1", + "PEBScounters": "32", + "EventName": "INST_RETIRED.ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of instructions retired. Fixed Counter - architectural event" + }, + { + "PEBS": "2", + "CollectPEBSRecord": "3", + "PublicDescription": "A version of INST_RETIRED that allows for a more unbiased distribution of samples across instructions retired. It utilizes the Precise Distribution of Instructions Retired (PDIR) feature to mitigate some bias in how retired instructions get sampled. Use on Fixed Counter 0.", + "Counter": "32", + "UMask": "0x1", + "PEBScounters": "32", + "EventName": "INST_RETIRED.PREC_DIST", + "SampleAfterValue": "2000003", + "BriefDescription": "Precise instruction retired event with a reduced effect of PEBS shadow in IP distribution" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events.", + "Counter": "33", + "UMask": "0x2", + "PEBScounters": "33", + "EventName": "CPU_CLK_UNHALTED.THREAD", + "SampleAfterValue": "2000003", + "BriefDescription": "Core cycles when the thread is not in halt state" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. This event has a constant ratio with the CPU_CLK_UNHALTED.REF_XCLK event. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", + "Counter": "34", + "UMask": "0x3", + "PEBScounters": "34", + "EventName": "CPU_CLK_UNHALTED.REF_TSC", + "SampleAfterValue": "2000003", + "BriefDescription": "Reference cycles when the core is not in halt state." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times the load operation got the true Block-on-Store blocking code preventing store forwarding. This includes cases when: a. preceding store conflicts with the load (incomplete overlap),b. store forwarding is impossible due to u-arch limitations, c. preceding lock RMW operations are not forwarded, d. store has the no-forward bit set (uncacheable/page-split/masked stores), e. all-blocking stores are used (mostly, fences and port I/O), and others. The most common case is a load blocked due to its address range overlapping with a preceding smaller uncompleted store. Note: This event does not take into account cases of out-of-SW-control (for example, SbTailHit), unknown physical STA, and cases of blocking loads on store due to being non-WB memory type or a lock. These cases are covered by other events. See the table of not supported store forwards in the Optimization Guide.", + "EventCode": "0x03", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "LD_BLOCKS.STORE_FORWARD", + "SampleAfterValue": "100003", + "BriefDescription": "Loads blocked by overlapping with store buffer that cannot be forwarded." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "EventCode": "0x03", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "LD_BLOCKS.NO_SR", + "SampleAfterValue": "100003", + "BriefDescription": "The number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", + "EventCode": "0x07", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS", + "SampleAfterValue": "100003", + "BriefDescription": "False dependencies in MOB due to partial compare on address." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", + "EventCode": "0x0D", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "INT_MISC.RECOVERY_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Core cycles the allocator was stalled due to recovery from earlier clear event for this thread" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles the Backend cluster is recovering after a miss-speculation or a Store Buffer or Load Buffer drain stall.", + "EventCode": "0x0D", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x3", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "INT_MISC.ALL_RECOVERY_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles the Backend cluster is recovering after a miss-speculation or a Store Buffer or Load Buffer drain stall.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", + "EventCode": "0x0d", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", + "EventCode": "0x0E", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_ISSUED.ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Uops that RAT issues to RS" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which the Resource Allocation Table (RAT) does not issue any Uops to the reservation station (RS) for the current thread.", + "EventCode": "0x0E", + "Invert": "1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_ISSUED.STALL_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when RAT does not issue Uops to RS for the thread", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", + "EventCode": "0x14", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x9", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "ARITH.DIVIDER_ACTIVE", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when divide unit is busy executing divide or square root operations.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", + "EventCode": "0x3C", + "Counter": "0,1,2,3,4,5,6,7", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CPU_CLK_UNHALTED.THREAD_P", + "SampleAfterValue": "2000003", + "BriefDescription": "Thread cycles when thread is not in halt state" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts core crystal clock cycles when the thread is unhalted.", + "EventCode": "0x3C", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CPU_CLK_UNHALTED.REF_XCLK", + "SampleAfterValue": "25003", + "BriefDescription": "Core crystal clock cycles when the thread is unhalted." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.", + "EventCode": "0x3C", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", + "SampleAfterValue": "25003", + "BriefDescription": "Core crystal clock cycles when this thread is unhalted and the other thread is halted." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all not software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions.", + "EventCode": "0x4c", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "LOAD_HIT_PREFETCH.SWPF", + "SampleAfterValue": "100003", + "BriefDescription": "Counts the number of demand load dispatches that hit L1D fill buffer (FB) allocated for software prefetch." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into stravation periods (e.g. branch mispredictions or i-cache misses)", + "EventCode": "0x5E", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RS_EVENTS.EMPTY_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", + "EventCode": "0x5E", + "Invert": "1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RS_EVENTS.EMPTY_END", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts end of periods where the Reservation Station (RS) was empty.", + "CounterMask": "1", + "EdgeDetect": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", + "EventCode": "0x87", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "ILD_STALL.LCP", + "SampleAfterValue": "2000003", + "BriefDescription": "Stalls caused by changing prefix length of the instruction." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to port 0.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_0", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 0" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to port 1.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_1", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to ports 2 and 3.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_2_3", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 2 and 3" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to ports 5 and 9.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x10", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_4_9", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 4 and 9" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to port 5.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_5", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 5" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to port 6.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x40", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_6", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 6" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts, on the per-thread basis, cycles during which at least one uop is dispatched from the Reservation Station (RS) to ports 7 and 8.", + "EventCode": "0xa1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_DISPATCHED.PORT_7_8", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on port 7 and 8" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xa2", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RESOURCE_STALLS.SCOREBOARD", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts cycles where the pipeline is stalled due to serializing operations." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end.", + "EventCode": "0xA2", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x8", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "RESOURCE_STALLS.SB", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles stalled due to no store buffers available. (not including draining form sync)." + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLE_ACTIVITY.CYCLES_L2_MISS", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles while L2 cache miss demand load is outstanding.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", + "SampleAfterValue": "2000003", + "BriefDescription": "Total execution stalls.", + "CounterMask": "4" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3", + "UMask": "0x5", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLE_ACTIVITY.STALLS_L2_MISS", + "SampleAfterValue": "2000003", + "BriefDescription": "Execution stalls while L2 cache miss demand load is outstanding.", + "CounterMask": "5" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLE_ACTIVITY.CYCLES_L1D_MISS", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles while L1 cache miss demand load is outstanding.", + "CounterMask": "8" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3", + "UMask": "0xc", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLE_ACTIVITY.STALLS_L1D_MISS", + "SampleAfterValue": "2000003", + "BriefDescription": "Execution stalls while L1 cache miss demand load is outstanding.", + "CounterMask": "12" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x10", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles while memory subsystem has an outstanding load.", + "CounterMask": "16" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xA3", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x14", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CYCLE_ACTIVITY.STALLS_MEM_ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Execution stalls while memory subsystem has an outstanding load.", + "CounterMask": "20" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", + "EventCode": "0xa6", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles total of 1 uop is executed on all ports and Reservation Station was not empty." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", + "EventCode": "0xa6", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles total of 2 uops are executed on all ports and Reservation Station was not empty." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", + "EventCode": "0xA6", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x40", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where the Store Buffer was full and no loads caused an execution stall.", + "CounterMask": "2" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which no uops were executed on all ports and Reservation Station (RS) was not empty.", + "EventCode": "0xa6", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where no uops were executed, the Reservation Station was not empty, the Store Buffer was full and there was no outstanding load." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", + "EventCode": "0xA8", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "LSD.UOPS", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of Uops delivered by the LSD." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", + "EventCode": "0xA8", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "LSD.CYCLES_ACTIVE", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles Uops delivered by the LSD, but didn't come from the decoder.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", + "EventCode": "0xa8", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "LSD.CYCLES_OK", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles optimal number of Uops delivered by the LSD, but did not come from the decoder.", + "CounterMask": "5" + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.THREAD", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of uops to be executed per-thread each cycle." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", + "EventCode": "0xB1", + "Invert": "1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.STALL_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts number of cycles no uops were dispatched to be executed on this thread.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", + "EventCode": "0xb1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CYCLES_GE_1", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where at least 1 uop was executed per-thread", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", + "EventCode": "0xb1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CYCLES_GE_2", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where at least 2 uops were executed per-thread", + "CounterMask": "2" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", + "EventCode": "0xb1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CYCLES_GE_3", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where at least 3 uops were executed per-thread", + "CounterMask": "3" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", + "EventCode": "0xb1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CYCLES_GE_4", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles where at least 4 uops were executed per-thread", + "CounterMask": "4" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of uops executed from any thread.", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CORE", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of uops executed on the core." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core.", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_1", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles at least 1 micro-op is executed from any thread on physical core.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core.", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_2", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles at least 2 micro-op is executed from any thread on physical core.", + "CounterMask": "2" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core.", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_3", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles at least 3 micro-op is executed from any thread on physical core.", + "CounterMask": "3" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core.", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_4", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles at least 4 micro-op is executed from any thread on physical core.", + "CounterMask": "4" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of x87 uops executed.", + "EventCode": "0xB1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x10", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_EXECUTED.X87", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of x87 uops dispatched." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter.", + "EventCode": "0xC0", + "Counter": "0,1,2,3,4,5,6,7", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "INST_RETIRED.ANY_P", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of instructions retired. General Counter - architectural event" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of cycles using always true condition (uops_ret &lt; 16) applied to non PEBS uops retired event.", + "EventCode": "0xC2", + "Invert": "1", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_RETIRED.TOTAL_CYCLES", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycles with less than 10 actually retired uops.", + "CounterMask": "10" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the retirement slots used each cycle.", + "EventCode": "0xc2", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "UOPS_RETIRED.SLOTS", + "SampleAfterValue": "2000003", + "BriefDescription": "Retirement slots used." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", + "EventCode": "0xC3", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MACHINE_CLEARS.COUNT", + "SampleAfterValue": "100003", + "BriefDescription": "Number of machine clears (nukes) of any type.", + "CounterMask": "1", + "EdgeDetect": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", + "EventCode": "0xC3", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x4", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MACHINE_CLEARS.SMC", + "SampleAfterValue": "100003", + "BriefDescription": "Self-modifying code (SMC) detected." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all branch instructions retired.", + "EventCode": "0xC4", + "Counter": "0,1,2,3,4,5,6,7", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.ALL_BRANCHES", + "SampleAfterValue": "400009", + "BriefDescription": "All branch instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts taken conditional branch instructions retired.", + "EventCode": "0xc4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.COND_TAKEN", + "SampleAfterValue": "400009", + "BriefDescription": "Taken conditional branch instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts both direct and indirect near call instructions retired.", + "EventCode": "0xC4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.NEAR_CALL", + "SampleAfterValue": "100007", + "BriefDescription": "Direct and indirect near call instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts return instructions retired.", + "EventCode": "0xC4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x8", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.NEAR_RETURN", + "SampleAfterValue": "100007", + "BriefDescription": "Return instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts not taken branch instructions retired.", + "EventCode": "0xC4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x10", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.COND_NTAKEN", + "SampleAfterValue": "400009", + "BriefDescription": "Not taken branch instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts conditional branch instructions retired.", + "EventCode": "0xc4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x11", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.COND", + "SampleAfterValue": "400009", + "BriefDescription": "Conditional branch instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts taken branch instructions retired.", + "EventCode": "0xC4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.NEAR_TAKEN", + "SampleAfterValue": "400009", + "BriefDescription": "Taken branch instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts far branch instructions retired.", + "EventCode": "0xC4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x40", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.FAR_BRANCH", + "SampleAfterValue": "100007", + "BriefDescription": "Far branch instructions retired." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all indirect branch instructions retired (excluding RETs. TSX aborts is considered indirect branch).", + "EventCode": "0xc4", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_INST_RETIRED.INDIRECT", + "SampleAfterValue": "100003", + "BriefDescription": "All indirect branch instructions retired (excluding RETs. TSX aborts are considered indirect branch)." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path.", + "EventCode": "0xC5", + "Counter": "0,1,2,3,4,5,6,7", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", + "SampleAfterValue": "400009", + "BriefDescription": "All mispredicted branch instructions retired.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts taken conditional mispredicted branch instructions retired.", + "EventCode": "0xc5", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x1", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_MISP_RETIRED.COND_TAKEN", + "SampleAfterValue": "400009", + "BriefDescription": "number of branch instructions retired that were mispredicted and taken. Non PEBS", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts mispredicted conditional branch instructions retired.", + "EventCode": "0xc5", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x11", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_MISP_RETIRED.COND", + "SampleAfterValue": "400009", + "BriefDescription": "Mispredicted conditional branch instructions retired.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken.", + "EventCode": "0xC5", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_MISP_RETIRED.NEAR_TAKEN", + "SampleAfterValue": "400009", + "BriefDescription": "Number of near branch instructions retired that were mispredicted and taken.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts all miss-predicted indirect branch instructions retired (excluding RETs. TSX aborts is considered indirect branch).", + "EventCode": "0xC5", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x80", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "BR_MISP_RETIRED.INDIRECT", + "SampleAfterValue": "100003", + "BriefDescription": "All miss-predicted indirect branch instructions retired (excluding RETs. TSX aborts is considered indirect branch).", + "Data_LA": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT.", + "EventCode": "0xcc", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x20", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "MISC_RETIRED.LBR_INSERTS", + "SampleAfterValue": "2000003", + "BriefDescription": "Increments whenever there is an update to the LBR array." + }, + { + "PublicDescription": "Counts number of retired PAUSE instructions (that do not end up with a VMExit to the VMM; TSX aborted Instructions may be counted).", + "EventCode": "0xcc", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x40", + "EventName": "MISC_RETIRED.PAUSE_INST", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of retired PAUSE instructions." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times the front-end is resteered when it finds a branch instruction in a fetch line. This occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", + "EventCode": "0xE6", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "BACLEARS.ANY", + "SampleAfterValue": "100003", + "BriefDescription": "Counts the total number when the front end is resteered, mainly when the BPU cannot provide a correct prediction and this is corrected by other branch handling mechanisms at the front end." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", + "EventCode": "0xec", + "Counter": "0,1,2,3,4,5,6,7", + "UMask": "0x2", + "PEBScounters": "0,1,2,3,4,5,6,7", + "EventName": "CPU_CLK_UNHALTED.DISTRIBUTED", + "SampleAfterValue": "2000003", + "BriefDescription": "Cycle counts are evenly distributed between active threads in the Core." + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/icelake/virtual-memory.json b/tools/perf/pmu-events/arch/x86/icelake/virtual-memory.json new file mode 100644 index 000000000000..7180a900c175 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/icelake/virtual-memory.json @@ -0,0 +1,236 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data loads whose address translations missed in the TLB and were mapped to 4K pages. The page walks can end with or without a page fault.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", + "SampleAfterValue": "2000003", + "BriefDescription": "Page walks completed due to a demand data load to a 4K page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data loads whose address translations missed in the TLB and were mapped to 2M/4M pages. The page walks can end with or without a page fault.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", + "SampleAfterValue": "2000003", + "BriefDescription": "Page walks completed due to a demand data load to a 2M/4M page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts demand data loads that caused a completed page walk of any page size (4K/2M/4M/1G). This implies it missed in all TLB levels. The page walk can end with or without a fault.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0xe", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", + "SampleAfterValue": "100003", + "BriefDescription": "Load miss in all TLB levels causes a page walk that completes. (All page sizes)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of page walks outstanding for a demand load in the PMH each cycle." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", + "SampleAfterValue": "100003", + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for a demand load.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.STLB_HIT", + "SampleAfterValue": "2000003", + "BriefDescription": "Loads that miss the DTLB and hit the STLB." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 4K pages. The page walks can end with or without a page fault.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", + "SampleAfterValue": "100003", + "BriefDescription": "Page walks completed due to a demand data store to a 4K page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 2M/4M pages. The page walks can end with or without a page fault.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", + "SampleAfterValue": "100003", + "BriefDescription": "Page walks completed due to a demand data store to a 2M/4M page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts demand data stores that caused a completed page walk of any page size (4K/2M/4M/1G). This implies it missed in all TLB levels. The page walk can end with or without a fault.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0xe", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", + "SampleAfterValue": "100003", + "BriefDescription": "Store misses in all TLB levels causes a page walk that completes. (All page sizes)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_PENDING", + "SampleAfterValue": "2000003", + "BriefDescription": "Number of page walks outstanding for a store in the PMH each cycle." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", + "SampleAfterValue": "100003", + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for a store.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.STLB_HIT", + "SampleAfterValue": "100003", + "BriefDescription": "Stores that miss the DTLB and hit the STLB." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts completed page walks (4K page size) caused by a code fetch. This implies it missed in the ITLB and further levels of TLB. The page walk can end with or without a fault.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", + "SampleAfterValue": "100003", + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (4K)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts code misses in all ITLB (Instruction TLB) levels that caused a completed page walk (2M and 4M page sizes). The page walk can end with or without a fault.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", + "SampleAfterValue": "100003", + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (2M/4M)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts completed page walks (2M and 4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0xe", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_COMPLETED", + "SampleAfterValue": "100003", + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (All page sizes)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_PENDING", + "SampleAfterValue": "100003", + "BriefDescription": "Number of page walks outstanding for an outstanding code request in the PMH each cycle." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_ACTIVE", + "SampleAfterValue": "100003", + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for code (instruction fetch) request.", + "CounterMask": "1" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.STLB_HIT", + "SampleAfterValue": "100003", + "BriefDescription": "Instruction fetch requests that miss the ITLB and hit the STLB." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of flushes of the big or small ITLB pages. Counting include both TLB Flush (covering all sets) and TLB Set Clear (set-specific).", + "EventCode": "0xAE", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB.ITLB_FLUSH", + "SampleAfterValue": "100007", + "BriefDescription": "Flushing of the Instruction TLB (ITLB) pages, includes 4k/2M/4M pages." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of DTLB flush attempts of the thread-specific entries.", + "EventCode": "0xBD", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "TLB_FLUSH.DTLB_THREAD", + "SampleAfterValue": "100007", + "BriefDescription": "DTLB flush attempts of the thread-specific entries" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of any STLB flush attempts (such as entire, VPID, PCID, InvPage, CR3 write, etc.).", + "EventCode": "0xBD", + "Counter": "0,1,2,3", + "UMask": "0x20", + "PEBScounters": "0,1,2,3", + "EventName": "TLB_FLUSH.STLB_ANY", + "SampleAfterValue": "100007", + "BriefDescription": "STLB flush attempts" + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index d6984a3017e0..745ced083844 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -33,4 +33,7 @@ GenuineIntel-6-25,v2,westmereep-sp,core GenuineIntel-6-2F,v2,westmereex,core GenuineIntel-6-55-[01234],v1,skylakex,core GenuineIntel-6-55-[56789ABCDEF],v1,cascadelakex,core +GenuineIntel-6-7D,v1,icelake,core +GenuineIntel-6-7E,v1,icelake,core +GenuineIntel-6-86,v1,tremontx,core AuthenticAMD-23-[[:xdigit:]]+,v1,amdfam17h,core diff --git a/tools/perf/pmu-events/arch/x86/tremontx/cache.json b/tools/perf/pmu-events/arch/x86/tremontx/cache.json new file mode 100644 index 000000000000..f88040171b4d --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/cache.json @@ -0,0 +1,111 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cacheable memory requests that miss in the the Last Level Cache. Requests include Demand Loads, Reads for Ownership(RFO), Instruction fetches and L1 HW prefetches. If the platform has an L3 cache, last level cache is the L3, otherwise it is the L2.", + "EventCode": "0x2e", + "Counter": "0,1,2,3", + "UMask": "0x41", + "PEBScounters": "0,1,2,3", + "EventName": "LONGEST_LAT_CACHE.MISS", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Counts memory requests originating from the core that miss in the last level cache. If the platform has an L3 cache, last level cache is the L3, otherwise it is the L2." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts cacheable memory requests that access the Last Level Cache. Requests include Demand Loads, Reads for Ownership(RFO), Instruction fetches and L1 HW prefetches. If the platform has an L3 cache, last level cache is the L3, otherwise it is the L2.", + "EventCode": "0x2e", + "Counter": "0,1,2,3", + "UMask": "0x4f", + "PEBScounters": "0,1,2,3", + "EventName": "LONGEST_LAT_CACHE.REFERENCE", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Counts memory requests originating from the core that reference a cache line in the last level cache. If the platform has an L3 cache, last level cache is the L3, otherwise it is the L2." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of load uops retired. This event is Precise Event capable", + "EventCode": "0xd0", + "Counter": "0,1,2,3", + "UMask": "0x81", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_UOPS_RETIRED.ALL_LOADS", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of load uops retired.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of store uops retired. This event is Precise Event capable", + "EventCode": "0xd0", + "Counter": "0,1,2,3", + "UMask": "0x82", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_UOPS_RETIRED.ALL_STORES", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of store uops retired.", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "EventCode": "0xd1", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_UOPS_RETIRED.L1_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of load uops retired that hit the level 1 data cache", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "EventCode": "0xd1", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_UOPS_RETIRED.L2_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of load uops retired that hit in the level 2 cache", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "EventCode": "0xd1", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_UOPS_RETIRED.L3_HIT", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of load uops retired that miss in the level 3 cache" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "EventCode": "0xd1", + "Counter": "0,1,2,3", + "UMask": "0x8", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_UOPS_RETIRED.L1_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of load uops retired that miss in the level 1 data cache", + "Data_LA": "1" + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "EventCode": "0xd1", + "Counter": "0,1,2,3", + "UMask": "0x10", + "PEBScounters": "0,1,2,3", + "EventName": "MEM_LOAD_UOPS_RETIRED.L2_MISS", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of load uops retired that miss in the level 2 cache", + "Data_LA": "1" + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/tremontx/frontend.json b/tools/perf/pmu-events/arch/x86/tremontx/frontend.json new file mode 100644 index 000000000000..73b0a1ed5756 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/frontend.json @@ -0,0 +1,26 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts requests to the Instruction Cache (ICache) for one or more bytes in an ICache Line and that cache line is not in the ICache (miss). The event strives to count on a cache line basis, so that multiple accesses which miss in a single cache line count as one ICACHE.MISS. Specifically, the event counts when straight line code crosses the cache line boundary, or when a branch target is to a new line, and that cache line is not in the ICache.", + "EventCode": "0x80", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "ICACHE.MISSES", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Counts requests to the Instruction Cache (ICache) for one or more bytes in a cache line and they do not hit in the ICache (miss)." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts requests to the Instruction Cache (ICache) for one or more bytes in an ICache Line. The event strives to count on a cache line basis, so that multiple fetches to a single cache line count as one ICACHE.ACCESS. Specifically, the event counts when accesses from straight line code crosses the cache line boundary, or when a branch target is to a new line.", + "EventCode": "0x80", + "Counter": "0,1,2,3", + "UMask": "0x3", + "PEBScounters": "0,1,2,3", + "EventName": "ICACHE.ACCESSES", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Counts requests to the Instruction Cache (ICache) for one or more bytes cache Line." + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/tremontx/memory.json b/tools/perf/pmu-events/arch/x86/tremontx/memory.json new file mode 100644 index 000000000000..65469e84f35b --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/memory.json @@ -0,0 +1,26 @@ +[ + { + "PublicDescription": "Offcore response can be programmed only with a specific pair of event select and counter MSR, and with specific event codes and predefine mask bit value in a dedicated MSR to specify attributes of the offcore transaction.", + "EventCode": "0XB7", + "MSRValue": "0x000000003F04000001", + "Counter": "0,1,2,3", + "UMask": "0x1", + "EventName": "OCR.DEMAND_DATA_RD.L3_MISS", + "MSRIndex": "0x1a6,0x1a7", + "SampleAfterValue": "100003", + "BriefDescription": "Counts demand data reads that was not supplied by the L3 cache.", + "Offcore": "1" + }, + { + "PublicDescription": "Offcore response can be programmed only with a specific pair of event select and counter MSR, and with specific event codes and predefine mask bit value in a dedicated MSR to specify attributes of the offcore transaction.", + "EventCode": "0XB7", + "MSRValue": "0x000000003F04000002", + "Counter": "0,1,2,3", + "UMask": "0x1", + "EventName": "OCR.DEMAND_RFO.L3_MISS", + "MSRIndex": "0x1a6,0x1a7", + "SampleAfterValue": "100003", + "BriefDescription": "Counts all demand reads for ownership (RFO) requests and software based prefetches for exclusive ownership (PREFETCHW) that was not supplied by the L3 cache.", + "Offcore": "1" + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/tremontx/other.json b/tools/perf/pmu-events/arch/x86/tremontx/other.json new file mode 100644 index 000000000000..85bf3c8f3914 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/other.json @@ -0,0 +1,26 @@ +[ + { + "PublicDescription": "Offcore response can be programmed only with a specific pair of event select and counter MSR, and with specific event codes and predefine mask bit value in a dedicated MSR to specify attributes of the offcore transaction.", + "EventCode": "0XB7", + "MSRValue": "0x000000000000010001", + "Counter": "0,1,2,3", + "UMask": "0x1", + "EventName": "OCR.DEMAND_DATA_RD.ANY_RESPONSE", + "MSRIndex": "0x1a6,0x1a7", + "SampleAfterValue": "100003", + "BriefDescription": "Counts demand data reads that have any response type.", + "Offcore": "1" + }, + { + "PublicDescription": "Offcore response can be programmed only with a specific pair of event select and counter MSR, and with specific event codes and predefine mask bit value in a dedicated MSR to specify attributes of the offcore transaction.", + "EventCode": "0XB7", + "MSRValue": "0x000000000000010002", + "Counter": "0,1,2,3", + "UMask": "0x1", + "EventName": "OCR.DEMAND_RFO.ANY_RESPONSE", + "MSRIndex": "0x1a6,0x1a7", + "SampleAfterValue": "100003", + "BriefDescription": "Counts all demand reads for ownership (RFO) requests and software based prefetches for exclusive ownership (PREFETCHW) that have any response type.", + "Offcore": "1" + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/tremontx/pipeline.json b/tools/perf/pmu-events/arch/x86/tremontx/pipeline.json new file mode 100644 index 000000000000..05a8f6a7d9c0 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/pipeline.json @@ -0,0 +1,111 @@ +[ + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of instructions that retire. For instructions that consist of multiple uops, this event counts the retirement of the last uop of the instruction. The counter continues counting during hardware interrupts, traps, and inside interrupt handlers. This event uses fixed counter 0.", + "Counter": "32", + "UMask": "0x1", + "PEBScounters": "32", + "EventName": "INST_RETIRED.ANY", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of instructions retired. (Fixed event)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of core cycles while the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. The core frequency may change from time to time. For this reason this event may have a changing ratio with regards to time. This event uses fixed counter 1.", + "Counter": "33", + "UMask": "0x2", + "PEBScounters": "33", + "EventName": "CPU_CLK_UNHALTED.CORE", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of unhalted core clock cycles. (Fixed event)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of reference cycles that the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. The core frequency may change from time. This event is not affected by core frequency changes and at a fixed frequency. This event uses fixed counter 2.", + "Counter": "34", + "UMask": "0x3", + "PEBScounters": "34", + "EventName": "CPU_CLK_UNHALTED.REF_TSC", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of unhalted reference clock cycles at TSC frequency. (Fixed event)" + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of core cycles while the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. The core frequency may change from time to time. For this reason this event may have a changing ratio with regards to time. This event uses a programmable general purpose performance counter.", + "EventCode": "0x3c", + "Counter": "0,1,2,3", + "PEBScounters": "0,1,2,3", + "EventName": "CPU_CLK_UNHALTED.CORE_P", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of unhalted core clock cycles." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts reference cycles (at TSC frequency) when core is not halted. This event uses a programmable general purpose perfmon counter.", + "EventCode": "0x3c", + "Counter": "0,1,2,3", + "UMask": "0x1", + "PEBScounters": "0,1,2,3", + "EventName": "CPU_CLK_UNHALTED.REF", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of unhalted reference clock cycles at TSC frequency." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of instructions that retire execution. For instructions that consist of multiple uops, this event counts the retirement of the last uop of the instruction. The event continues counting during hardware interrupts, traps, and inside interrupt handlers. This is an architectural performance event. This event uses a Programmable general purpose perfmon counter. *This event is Precise Event capable: The EventingRIP field in the PEBS record is precise to the address of the instruction which caused the event.", + "EventCode": "0xc0", + "Counter": "0,1,2,3", + "PEBScounters": "0,1,2,3", + "EventName": "INST_RETIRED.ANY_P", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts the number of instructions retired." + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xc3", + "Counter": "0,1,2,3", + "PEBScounters": "0,1,2,3", + "EventName": "MACHINE_CLEARS.ANY", + "PDIR_COUNTER": "na", + "SampleAfterValue": "20003", + "BriefDescription": "Counts all machine clears due to, but not limited to memory ordering, memory disambiguation, SMC, page faults and FP assist." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts branch instructions retired for all branch types. This event is Precise Event capable. This is an architectural event.", + "EventCode": "0xc4", + "Counter": "0,1,2,3", + "PEBScounters": "0,1,2,3", + "EventName": "BR_INST_RETIRED.ALL_BRANCHES", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of branch instructions retired for all branch types." + }, + { + "PEBS": "1", + "CollectPEBSRecord": "2", + "PublicDescription": "Counts mispredicted branch instructions retired for all branch types. This event is Precise Event capable. This is an architectural event.", + "EventCode": "0xc5", + "Counter": "0,1,2,3", + "PEBScounters": "0,1,2,3", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of mispredicted branch instructions retired." + }, + { + "CollectPEBSRecord": "2", + "EventCode": "0xcd", + "Counter": "0,1,2,3", + "PEBScounters": "0,1,2,3", + "EventName": "CYCLES_DIV_BUSY.ANY", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Counts cycles the floating point divider or integer divider or both are busy. Does not imply a stall waiting for either divider." + } +]
\ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/tremontx/uncore-memory.json b/tools/perf/pmu-events/arch/x86/tremontx/uncore-memory.json new file mode 100644 index 000000000000..15376f2cf052 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/uncore-memory.json @@ -0,0 +1,73 @@ +[ + { + "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x04", + "EventName": "LLC_MISSES.MEM_READ", + "PerPkg": "1", + "ScaleUnit": "64Bytes", + "UMask": "0x0f", + "Unit": "iMC" + }, + { + "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x04", + "EventName": "LLC_MISSES.MEM_WRITE", + "PerPkg": "1", + "ScaleUnit": "64Bytes", + "UMask": "0x30", + "Unit": "iMC" + }, + { + "BriefDescription": "Memory controller clock ticks", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventName": "UNC_M_CLOCKTICKS", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Pre-charge for reads", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x02", + "EventName": "UNC_M_PRE_COUNT.RD", + "PerPkg": "1", + "UMask": "0x04", + "Unit": "iMC" + }, + { + "BriefDescription": "Pre-charge for writes", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x02", + "EventName": "UNC_M_PRE_COUNT.WR", + "PerPkg": "1", + "UMask": "0x08", + "Unit": "iMC" + }, + { + "BriefDescription": "Precharge due to read on page miss, write on page miss or PGT", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x02", + "EventName": "UNC_M_PRE_COUNT.ALL", + "PerPkg": "1", + "UMask": "0x1c", + "Unit": "iMC" + }, + { + "BriefDescription": "DRAM Precharge commands. : Precharge due to page table", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x02", + "EventName": "UNC_M_PRE_COUNT.PGT", + "PerPkg": "1", + "PublicDescription": "DRAM Precharge commands. : Precharge due to page table : Counts the number of DRAM Precharge commands sent on this channel.", + "UMask": "0x10", + "Unit": "iMC" + } +] diff --git a/tools/perf/pmu-events/arch/x86/tremontx/uncore-other.json b/tools/perf/pmu-events/arch/x86/tremontx/uncore-other.json new file mode 100644 index 000000000000..6deff1fe89e3 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/uncore-other.json @@ -0,0 +1,431 @@ +[ + { + "BriefDescription": "Uncore cache clock ticks", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventName": "UNC_CHA_CLOCKTICKS", + "PerPkg": "1", + "Unit": "CHA" + }, + { + "BriefDescription": "LLC misses - Uncacheable reads (from cpu) . Derived from unc_cha_tor_inserts.ia_miss", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "LLC_MISSES.UNCACHEABLE", + "Filter": "config1=0x40e33", + "PerPkg": "1", + "UMask": "0xC001FE01", + "UMaskExt": "0xC001FE", + "Unit": "CHA" + }, + { + "BriefDescription": "MMIO reads. Derived from unc_cha_tor_inserts.ia_miss", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "LLC_MISSES.MMIO_READ", + "Filter": "config1=0x40040e33", + "PerPkg": "1", + "UMask": "0xC001FE01", + "UMaskExt": "0xC001FE", + "Unit": "CHA" + }, + { + "BriefDescription": "MMIO writes. Derived from unc_cha_tor_inserts.ia_miss", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "LLC_MISSES.MMIO_WRITE", + "Filter": "config1=0x40041e33", + "PerPkg": "1", + "UMask": "0xC001FE01", + "UMaskExt": "0xC001FE", + "Unit": "CHA" + }, + { + "BriefDescription": "Streaming stores (full cache line). Derived from unc_cha_tor_inserts.ia_miss", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "LLC_REFERENCES.STREAMING_FULL", + "Filter": "config1=0x41833", + "PerPkg": "1", + "ScaleUnit": "64Bytes", + "UMask": "0xC001FE01", + "UMaskExt": "0xC001FE", + "Unit": "CHA" + }, + { + "BriefDescription": "Streaming stores (partial cache line). Derived from unc_cha_tor_inserts.ia_miss", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "LLC_REFERENCES.STREAMING_PARTIAL", + "Filter": "config1=0x41a33", + "PerPkg": "1", + "ScaleUnit": "64Bytes", + "UMask": "0xC001FE01", + "UMaskExt": "0xC001FE", + "Unit": "CHA" + }, + { + "BriefDescription": "PCI Express bandwidth reading at IIO. Derived from unc_iio_data_req_of_cpu.mem_read.part0", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "LLC_MISSES.PCIE_READ", + "FCMask": "0x07", + "Filter": "ch_mask=0x1f", + "MetricExpr": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART0 +UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART1 +UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART2 +UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART3", + "MetricName": "LLC_MISSES.PCIE_READ", + "PerPkg": "1", + "PortMask": "0x01", + "ScaleUnit": "4Bytes", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth writing at IIO. Derived from unc_iio_data_req_of_cpu.mem_write.part0", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "LLC_MISSES.PCIE_WRITE", + "FCMask": "0x07", + "Filter": "ch_mask=0x1f", + "MetricExpr": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 +UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1 +UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 +UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3", + "MetricName": "LLC_MISSES.PCIE_WRITE", + "PerPkg": "1", + "PortMask": "0x01", + "ScaleUnit": "4Bytes", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth writing at IIO, part 1", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART1", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x02", + "ScaleUnit": "4Bytes", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth writing at IIO, part 2", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x04", + "ScaleUnit": "4Bytes", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth writing at IIO, part 3", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x08", + "ScaleUnit": "4Bytes", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth reading at IIO, part 1", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART1", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x02", + "ScaleUnit": "4Bytes", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth reading at IIO, part 2", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART2", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x04", + "ScaleUnit": "4Bytes", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "PCI Express bandwidth reading at IIO, part 3", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART3", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x08", + "ScaleUnit": "4Bytes", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "TOR Inserts; CRd misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_CRD", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Code read from local IA that misses in the snoop filter", + "UMask": "0xC80FFE01", + "UMaskExt": "0xC80FFE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; CRd Pref misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_CRD_PREF", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Code read prefetch from local IA that misses in the snoop filter", + "UMask": "0xC88FFE01", + "UMaskExt": "0xC88FFE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; DRd Opt misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_DRD_OPT", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Data read opt from local IA that misses in the snoop filter", + "UMask": "0xC827FE01", + "UMaskExt": "0xC827FE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; DRd Opt Pref misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_DRD_OPT_PREF", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Data read opt prefetch from local IA that misses in the snoop filter", + "UMask": "0xC8A7FE01", + "UMaskExt": "0xC8A7FE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; RFO misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_RFO", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Read for ownership from local IA that misses in the snoop filter", + "UMask": "0xC807FE01", + "UMaskExt": "0xC807FE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; RFO pref misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_RFO_PREF", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Read for ownership prefetch from local IA that misses in the snoop filter", + "UMask": "0xC887FE01", + "UMaskExt": "0xC887FE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; WCiL misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_WCIL", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Data read from local IA that misses in the snoop filter", + "UMask": "0xC86FFE01", + "UMaskExt": "0xC86FFE", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Inserts; WCiLF misses from local IA", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IA_MISS_WCILF", + "PerPkg": "1", + "PublicDescription": "TOR Inserts; Data read from local IA that misses in the snoop filter", + "UMask": "0xC867FE01", + "UMaskExt": "0xC867FE", + "Unit": "CHA" + }, + { + "BriefDescription": "Clockticks of the integrated IO (IIO) traffic controller", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x01", + "EventName": "UNC_IIO_CLOCKTICKS", + "PerPkg": "1", + "PublicDescription": "Clockticks of the integrated IO (IIO) traffic controller", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card reading from DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART4", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x10", + "PublicDescription": "Data requested of the CPU : Card reading from DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x16 card plugged in to stack, Or x8 card plugged in to Lane 0/1, Or x4 card is plugged in to slot 0", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card reading from DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART5", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x20", + "PublicDescription": "Data requested of the CPU : Card reading from DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x4 card is plugged in to slot 1", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card reading from DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART6", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x40", + "PublicDescription": "Data requested of the CPU : Card reading from DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x8 card plugged in to Lane 2/3, Or x4 card is plugged in to slot 1", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card reading from DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART7", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x80", + "PublicDescription": "Data requested of the CPU : Card reading from DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x4 card is plugged in to slot 3", + "UMask": "0x04", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card writing to DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART4", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x10", + "PublicDescription": "Data requested of the CPU : Card writing to DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x16 card plugged in to stack, Or x8 card plugged in to Lane 0/1, Or x4 card is plugged in to slot 0", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card writing to DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART5", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x20", + "PublicDescription": "Data requested of the CPU : Card writing to DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x4 card is plugged in to slot 1", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card writing to DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART6", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x40", + "PublicDescription": "Data requested of the CPU : Card writing to DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x8 card plugged in to Lane 2/3, Or x4 card is plugged in to slot 1", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "Data requested of the CPU : Card writing to DRAM", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x83", + "EventName": "UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART7", + "FCMask": "0x07", + "PerPkg": "1", + "PortMask": "0x80", + "PublicDescription": "Data requested of the CPU : Card writing to DRAM : Number of DWs (4 bytes) the card requests of the main die. Includes all requests initiated by the Card, including reads and writes. : x4 card is plugged in to slot 3", + "UMask": "0x01", + "Unit": "IIO" + }, + { + "BriefDescription": "Clockticks of the IO coherency tracker (IRP)", + "Counter": "0,1", + "CounterType": "PGMABLE", + "EventCode": "0x01", + "EventName": "UNC_I_CLOCKTICKS", + "PerPkg": "1", + "PublicDescription": "Clockticks of the IO coherency tracker (IRP)", + "Unit": "IRP" + }, + { + "BriefDescription": "Clockticks of the mesh to memory (M2M)", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventName": "UNC_M2M_CLOCKTICKS", + "PerPkg": "1", + "PublicDescription": "Clockticks of the mesh to memory (M2M)", + "Unit": "M2M" + }, + { + "BriefDescription": "Clockticks of the mesh to PCI (M2P)", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventCode": "0x01", + "EventName": "UNC_M2P_CLOCKTICKS", + "PerPkg": "1", + "PublicDescription": "Clockticks of the mesh to PCI (M2P)", + "Unit": "M2PCIe" + }, + { + "BriefDescription": "Clockticks in the UBOX using a dedicated 48-bit Fixed Counter", + "Counter": "FIXED", + "CounterType": "PGMABLE", + "EventCode": "0xff", + "EventName": "UNC_U_CLOCKTICKS", + "PerPkg": "1", + "PublicDescription": "Clockticks in the UBOX using a dedicated 48-bit Fixed Counter", + "Unit": "UBOX" + } +] diff --git a/tools/perf/pmu-events/arch/x86/tremontx/uncore-power.json b/tools/perf/pmu-events/arch/x86/tremontx/uncore-power.json new file mode 100644 index 000000000000..ea62c092b43f --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/uncore-power.json @@ -0,0 +1,11 @@ +[ + { + "BriefDescription": "Clockticks of the power control unit (PCU)", + "Counter": "0,1,2,3", + "CounterType": "PGMABLE", + "EventName": "UNC_P_CLOCKTICKS", + "PerPkg": "1", + "PublicDescription": "Clockticks of the power control unit (PCU)", + "Unit": "PCU" + } +] diff --git a/tools/perf/pmu-events/arch/x86/tremontx/virtual-memory.json b/tools/perf/pmu-events/arch/x86/tremontx/virtual-memory.json new file mode 100644 index 000000000000..93e407a0f645 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/tremontx/virtual-memory.json @@ -0,0 +1,86 @@ +[ + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data loads (including SW prefetches) whose address translations missed in all TLB levels and were mapped to 4K pages. The page walks can end with or without a page fault.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Page walk completed due to a demand load to a 4K page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data loads (including SW prefetches) whose address translations missed in all TLB levels and were mapped to 2M or 4M pages. The page walks can end with or without a page fault.", + "EventCode": "0x08", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Page walk completed due to a demand load to a 2M or 4M page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 4K pages. The page walks can end with or without a page fault.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Page walk completed due to a demand data store to a 4K page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 2M or 4M pages. The page walks can end with or without a page fault.", + "EventCode": "0x49", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Page walk completed due to a demand data store to a 2M or 4M page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts the number of times the machine was unable to find a translation in the Instruction Translation Lookaside Buffer (ITLB) and new translation was filled into the ITLB. The event is speculative in nature, but will not count translations (page walks) that are begun and not finished, or translations that are finished but not filled into the ITLB.", + "EventCode": "0x81", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB.FILLS", + "PDIR_COUNTER": "na", + "SampleAfterValue": "200003", + "BriefDescription": "Counts the number of times there was an ITLB miss and a new translation was filled into the ITLB." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to instruction fetches whose address translations missed in the TLB and were mapped to 4K pages. The page walks can end with or without a page fault.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x2", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Page walk completed due to an instruction fetch in a 4K page." + }, + { + "CollectPEBSRecord": "2", + "PublicDescription": "Counts page walks completed due to instruction fetches whose address translations missed in the TLB and were mapped to 2M or 4M pages. The page walks can end with or without a page fault.", + "EventCode": "0x85", + "Counter": "0,1,2,3", + "UMask": "0x4", + "PEBScounters": "0,1,2,3", + "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", + "PDIR_COUNTER": "na", + "SampleAfterValue": "2000003", + "BriefDescription": "Page walk completed due to an instruction fetch in a 2M or 4M page." + } +]
\ No newline at end of file diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c index ead521dd8d79..25c47d23a130 100644 --- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c @@ -19,7 +19,6 @@ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" -#include "../../../perf.h" #include "../../../util/trace-event.h" #ifndef PERL_UNUSED_VAR diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 217568bc29ce..0b7096847991 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -6,7 +6,6 @@ */ #include <Python.h> -#include "../../../perf.h" #include "../../../util/trace-event.h" #if PY_MAJOR_VERSION < 3 diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index d8426547219b..a9599ab8c471 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c @@ -30,8 +30,9 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> -#include "../perf.h" +#include "../perf-sys.h" #include <subcmd/exec-cmd.h> +#include "event.h" #include "tests.h" #define ENV "PERF_TEST_ATTR" diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index 1a9c3becf5ff..a637a4a90760 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -4,12 +4,14 @@ * beginning */ -#include <perf.h> #include <evlist.h> #include <sys/prctl.h> +#include "record.h" #include "tests.h" #include "debug.h" +#include "parse-events.h" #include <errno.h> +#include <linux/string.h> #define NR_ITERS 111 @@ -25,7 +27,7 @@ static void testcase(void) } } -static int count_samples(struct perf_evlist *evlist, int *sample_count, +static int count_samples(struct evlist *evlist, int *sample_count, int *comm_count) { int i; @@ -55,7 +57,7 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count, return TEST_OK; } -static int do_test(struct perf_evlist *evlist, int mmap_pages, +static int do_test(struct evlist *evlist, int mmap_pages, int *sample_count, int *comm_count) { int err; @@ -68,9 +70,9 @@ static int do_test(struct perf_evlist *evlist, int mmap_pages, return TEST_FAIL; } - perf_evlist__enable(evlist); + evlist__enable(evlist); testcase(); - perf_evlist__disable(evlist); + evlist__disable(evlist); err = count_samples(evlist, sample_count, comm_count); perf_evlist__munmap(evlist); @@ -82,8 +84,8 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m { int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0; char pid[16], sbuf[STRERR_BUFSIZE]; - struct perf_evlist *evlist; - struct perf_evsel *evsel __maybe_unused; + struct evlist *evlist; + struct evsel *evsel __maybe_unused; struct parse_events_error parse_error; struct record_opts opts = { .target = { @@ -99,7 +101,7 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m pid[sizeof(pid) - 1] = '\0'; opts.target.tid = opts.target.pid = pid; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) { pr_debug("Not enough memory to create evlist\n"); return TEST_FAIL; @@ -125,7 +127,7 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m perf_evlist__config(evlist, &opts, NULL); - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -150,6 +152,6 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m ret = TEST_OK; out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); return ret; } diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c index 96e7fc1ad3f9..db2aadff3708 100644 --- a/tools/perf/tests/bitmap.c +++ b/tools/perf/tests/bitmap.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> #include <linux/bitmap.h> +#include <perf/cpumap.h> #include "tests.h" #include "cpumap.h" #include "debug.h" @@ -9,7 +10,7 @@ static unsigned long *get_bitmap(const char *str, int nbits) { - struct cpu_map *map = cpu_map__new(str); + struct perf_cpu_map *map = perf_cpu_map__new(str); unsigned long *bm = NULL; int i; @@ -21,7 +22,7 @@ static unsigned long *get_bitmap(const char *str, int nbits) } if (map) - cpu_map__put(map); + perf_cpu_map__put(map); return bm; } diff --git a/tools/perf/tests/bp_account.c b/tools/perf/tests/bp_account.c index 153624e2d0f5..016bba2c142d 100644 --- a/tools/perf/tests/bp_account.c +++ b/tools/perf/tests/bp_account.c @@ -19,7 +19,8 @@ #include "tests.h" #include "debug.h" -#include "perf.h" +#include "event.h" +#include "../perf-sys.h" #include "cloexec.h" volatile long the_var; diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index 910e25e64188..c1c2c13de254 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c @@ -25,7 +25,8 @@ #include "tests.h" #include "debug.h" -#include "perf.h" +#include "event.h" +#include "perf-sys.h" #include "cloexec.h" static int fd1; diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c index ca962559e845..eb4dbbddf4ff 100644 --- a/tools/perf/tests/bp_signal_overflow.c +++ b/tools/perf/tests/bp_signal_overflow.c @@ -24,7 +24,8 @@ #include "tests.h" #include "debug.h" -#include "perf.h" +#include "event.h" +#include "../perf-sys.h" #include "cloexec.h" static int overflows; diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index c9e4cdc4c9c8..fc102e4f403e 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -5,17 +5,20 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <util/record.h> #include <util/util.h> #include <util/bpf-loader.h> #include <util/evlist.h> #include <linux/bpf.h> #include <linux/filter.h> #include <linux/kernel.h> +#include <linux/string.h> #include <api/fs/fs.h> #include <bpf/bpf.h> #include "tests.h" #include "llvm.h" #include "debug.h" +#include "parse-events.h" #define NR_ITERS 111 #define PERF_TEST_BPF_PATH "/sys/fs/bpf/perf_test" @@ -118,7 +121,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), char pid[16]; char sbuf[STRERR_BUFSIZE]; - struct perf_evlist *evlist; + struct evlist *evlist; int i, ret = TEST_FAIL, err = 0, count = 0; struct parse_events_state parse_state; @@ -140,7 +143,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), opts.target.tid = opts.target.pid = pid; /* Instead of perf_evlist__new_default, don't add default events */ - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) { pr_debug("Not enough memory to create evlist\n"); return TEST_FAIL; @@ -157,7 +160,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), perf_evlist__config(evlist, &opts, NULL); - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -171,9 +174,9 @@ static int do_test(struct bpf_object *obj, int (*func)(void), goto out_delete_evlist; } - perf_evlist__enable(evlist); + evlist__enable(evlist); (*func)(); - perf_evlist__disable(evlist); + evlist__disable(evlist); for (i = 0; i < evlist->nr_mmaps; i++) { union perf_event *event; @@ -200,7 +203,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), ret = TEST_OK; out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); return ret; } diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c3bec9d2c201..55774baffc2a 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -8,6 +8,7 @@ #include <errno.h> #include <unistd.h> #include <string.h> +#include <stdlib.h> #include <sys/types.h> #include <dirent.h> #include <sys/wait.h> diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index aa6df122b175..c1c29e08e7fb 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -8,8 +8,14 @@ #include <stdio.h> #include <string.h> #include <sys/param.h> +#include <perf/cpumap.h> +#include <perf/evlist.h> +#include "debug.h" +#include "dso.h" +#include "env.h" #include "parse-events.h" +#include "trace-event.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" @@ -18,6 +24,7 @@ #include "map.h" #include "symbol.h" #include "event.h" +#include "record.h" #include "thread.h" #include "tests.h" @@ -362,7 +369,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, } static int process_sample_event(struct machine *machine, - struct perf_evlist *evlist, + struct evlist *evlist, union perf_event *event, struct state *state) { struct perf_sample sample; @@ -385,7 +392,7 @@ static int process_sample_event(struct machine *machine, return ret; } -static int process_event(struct machine *machine, struct perf_evlist *evlist, +static int process_event(struct machine *machine, struct evlist *evlist, union perf_event *event, struct state *state) { if (event->header.type == PERF_RECORD_SAMPLE) @@ -408,7 +415,7 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist, return 0; } -static int process_events(struct machine *machine, struct perf_evlist *evlist, +static int process_events(struct machine *machine, struct evlist *evlist, struct state *state) { union perf_event *event; @@ -491,6 +498,10 @@ static void fs_something(void) } } +#ifdef __s390x__ +#include "header.h" // for get_cpuid() +#endif + static const char *do_determine_event(bool excl_kernel) { const char *event = excl_kernel ? "cycles:u" : "cycles"; @@ -552,10 +563,10 @@ static int do_test_code_reading(bool try_kcore) struct state state = { .done_cnt = 0, }; - struct thread_map *threads = NULL; - struct cpu_map *cpus = NULL; - struct perf_evlist *evlist = NULL; - struct perf_evsel *evsel = NULL; + struct perf_thread_map *threads = NULL; + struct perf_cpu_map *cpus = NULL; + struct evlist *evlist = NULL; + struct evsel *evsel = NULL; int err = -1, ret; pid_t pid; struct map *map; @@ -613,22 +624,22 @@ static int do_test_code_reading(bool try_kcore) goto out_put; } - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) { - pr_debug("cpu_map__new failed\n"); + pr_debug("perf_cpu_map__new failed\n"); goto out_put; } while (1) { const char *str; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) { pr_debug("perf_evlist__new failed\n"); goto out_put; } - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); str = do_determine_event(excl_kernel); pr_debug("Parsing event '%s'\n", str); @@ -642,11 +653,11 @@ static int do_test_code_reading(bool try_kcore) evsel = perf_evlist__first(evlist); - evsel->attr.comm = 1; - evsel->attr.disabled = 1; - evsel->attr.enable_on_exec = 0; + evsel->core.attr.comm = 1; + evsel->core.attr.disabled = 1; + evsel->core.attr.enable_on_exec = 0; - ret = perf_evlist__open(evlist); + ret = evlist__open(evlist); if (ret < 0) { if (!excl_kernel) { excl_kernel = true; @@ -655,10 +666,10 @@ static int do_test_code_reading(bool try_kcore) * and will be freed by following perf_evlist__set_maps * call. Getting refference to keep them alive. */ - cpu_map__get(cpus); - thread_map__get(threads); - perf_evlist__set_maps(evlist, NULL, NULL); - perf_evlist__delete(evlist); + perf_cpu_map__get(cpus); + perf_thread_map__get(threads); + perf_evlist__set_maps(&evlist->core, NULL, NULL); + evlist__delete(evlist); evlist = NULL; continue; } @@ -680,11 +691,11 @@ static int do_test_code_reading(bool try_kcore) goto out_put; } - perf_evlist__enable(evlist); + evlist__enable(evlist); do_something(); - perf_evlist__disable(evlist); + evlist__disable(evlist); ret = process_events(machine, evlist, &state); if (ret < 0) @@ -703,10 +714,10 @@ out_put: out_err: if (evlist) { - perf_evlist__delete(evlist); + evlist__delete(evlist); } else { - cpu_map__put(cpus); - thread_map__put(threads); + perf_cpu_map__put(cpus); + perf_thread_map__put(threads); } machine__delete_threads(machine); machine__delete(machine); diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index e78b897677bd..39493de50117 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -5,6 +5,7 @@ #include "event.h" #include <string.h> #include <linux/bitops.h> +#include <perf/cpumap.h> #include "debug.h" struct machine; @@ -14,17 +15,17 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct cpu_map_event *map_event = &event->cpu_map; - struct cpu_map_mask *mask; - struct cpu_map_data *data; - struct cpu_map *map; + struct perf_record_cpu_map *map_event = &event->cpu_map; + struct perf_record_record_cpu_map *mask; + struct perf_record_cpu_map_data *data; + struct perf_cpu_map *map; int i; data = &map_event->data; TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK); - mask = (struct cpu_map_mask *)data->data; + mask = (struct perf_record_record_cpu_map *)data->data; TEST_ASSERT_VAL("wrong nr", mask->nr == 1); @@ -39,7 +40,7 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong cpu", map->map[i] == i); } - cpu_map__put(map); + perf_cpu_map__put(map); return 0; } @@ -48,10 +49,10 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct cpu_map_event *map_event = &event->cpu_map; + struct perf_record_cpu_map *map_event = &event->cpu_map; struct cpu_map_entries *cpus; - struct cpu_map_data *data; - struct cpu_map *map; + struct perf_record_cpu_map_data *data; + struct perf_cpu_map *map; data = &map_event->data; @@ -68,36 +69,36 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1); TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256); TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); - cpu_map__put(map); + perf_cpu_map__put(map); return 0; } int test__cpu_map_synthesize(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct cpu_map *cpus; + struct perf_cpu_map *cpus; /* This one is better stores in mask. */ - cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19"); + cpus = perf_cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19"); TEST_ASSERT_VAL("failed to synthesize map", !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL)); - cpu_map__put(cpus); + perf_cpu_map__put(cpus); /* This one is better stores in cpu values. */ - cpus = cpu_map__new("1,256"); + cpus = perf_cpu_map__new("1,256"); TEST_ASSERT_VAL("failed to synthesize map", !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL)); - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return 0; } static int cpu_map_print(const char *str) { - struct cpu_map *map = cpu_map__new(str); + struct perf_cpu_map *map = perf_cpu_map__new(str); char buf[100]; if (!map) diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 946ab4b63acd..a4874d4ce7ef 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -9,6 +9,7 @@ #include <sys/time.h> #include <sys/resource.h> #include <api/fs/fs.h> +#include "dso.h" #include "util.h" #include "machine.h" #include "symbol.h" diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index f33709a79335..4125255ff637 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -3,6 +3,7 @@ #include <linux/types.h> #include <linux/zalloc.h> #include <inttypes.h> +#include <limits.h> #include <unistd.h> #include "tests.h" #include "debug.h" diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index 1a2686f1fcf0..d824a726906c 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -1,20 +1,23 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> +#include <linux/string.h> #include <errno.h> #include <inttypes.h> #include <string.h> #include <sys/wait.h> +#include <perf/cpumap.h> #include "tests.h" #include "evlist.h" #include "evsel.h" #include "util.h" #include "debug.h" +#include "parse-events.h" #include "thread_map.h" #include "target.h" -static int attach__enable_on_exec(struct perf_evlist *evlist) +static int attach__enable_on_exec(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = perf_evlist__last(evlist); struct target target = { .uid = UINT_MAX, }; @@ -36,9 +39,9 @@ static int attach__enable_on_exec(struct perf_evlist *evlist) return err; } - evsel->attr.enable_on_exec = 1; + evsel->core.attr.enable_on_exec = 1; - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -48,16 +51,16 @@ static int attach__enable_on_exec(struct perf_evlist *evlist) return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; } -static int detach__enable_on_exec(struct perf_evlist *evlist) +static int detach__enable_on_exec(struct evlist *evlist) { waitpid(evlist->workload.pid, NULL, 0); return 0; } -static int attach__current_disabled(struct perf_evlist *evlist) +static int attach__current_disabled(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(evlist); - struct thread_map *threads; + struct evsel *evsel = perf_evlist__last(evlist); + struct perf_thread_map *threads; int err; pr_debug("attaching to current thread as disabled\n"); @@ -68,7 +71,7 @@ static int attach__current_disabled(struct perf_evlist *evlist) return -1; } - evsel->attr.disabled = 1; + evsel->core.attr.disabled = 1; err = perf_evsel__open_per_thread(evsel, threads); if (err) { @@ -76,14 +79,14 @@ static int attach__current_disabled(struct perf_evlist *evlist) return err; } - thread_map__put(threads); - return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; + perf_thread_map__put(threads); + return evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; } -static int attach__current_enabled(struct perf_evlist *evlist) +static int attach__current_enabled(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(evlist); - struct thread_map *threads; + struct evsel *evsel = perf_evlist__last(evlist); + struct perf_thread_map *threads; int err; pr_debug("attaching to current thread as enabled\n"); @@ -96,32 +99,32 @@ static int attach__current_enabled(struct perf_evlist *evlist) err = perf_evsel__open_per_thread(evsel, threads); - thread_map__put(threads); + perf_thread_map__put(threads); return err == 0 ? TEST_OK : TEST_FAIL; } -static int detach__disable(struct perf_evlist *evlist) +static int detach__disable(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = perf_evlist__last(evlist); - return perf_evsel__enable(evsel); + return evsel__enable(evsel); } -static int attach__cpu_disabled(struct perf_evlist *evlist) +static int attach__cpu_disabled(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(evlist); - struct cpu_map *cpus; + struct evsel *evsel = perf_evlist__last(evlist); + struct perf_cpu_map *cpus; int err; pr_debug("attaching to CPU 0 as enabled\n"); - cpus = cpu_map__new("0"); + cpus = perf_cpu_map__new("0"); if (cpus == NULL) { - pr_debug("failed to call cpu_map__new\n"); + pr_debug("failed to call perf_cpu_map__new\n"); return -1; } - evsel->attr.disabled = 1; + evsel->core.attr.disabled = 1; err = perf_evsel__open_per_cpu(evsel, cpus); if (err) { @@ -132,21 +135,21 @@ static int attach__cpu_disabled(struct perf_evlist *evlist) return err; } - cpu_map__put(cpus); - return perf_evsel__enable(evsel); + perf_cpu_map__put(cpus); + return evsel__enable(evsel); } -static int attach__cpu_enabled(struct perf_evlist *evlist) +static int attach__cpu_enabled(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__last(evlist); - struct cpu_map *cpus; + struct evsel *evsel = perf_evlist__last(evlist); + struct perf_cpu_map *cpus; int err; pr_debug("attaching to CPU 0 as enabled\n"); - cpus = cpu_map__new("0"); + cpus = perf_cpu_map__new("0"); if (cpus == NULL) { - pr_debug("failed to call cpu_map__new\n"); + pr_debug("failed to call perf_cpu_map__new\n"); return -1; } @@ -154,19 +157,19 @@ static int attach__cpu_enabled(struct perf_evlist *evlist) if (err == -EACCES) return TEST_SKIP; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return err ? TEST_FAIL : TEST_OK; } -static int test_times(int (attach)(struct perf_evlist *), - int (detach)(struct perf_evlist *)) +static int test_times(int (attach)(struct evlist *), + int (detach)(struct evlist *)) { struct perf_counts_values count; - struct perf_evlist *evlist = NULL; - struct perf_evsel *evsel; + struct evlist *evlist = NULL; + struct evsel *evsel; int err = -1, i; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) { pr_debug("failed to create event list\n"); goto out_err; @@ -179,7 +182,7 @@ static int test_times(int (attach)(struct perf_evlist *), } evsel = perf_evlist__last(evlist); - evsel->attr.read_format |= + evsel->core.attr.read_format |= PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; @@ -195,7 +198,7 @@ static int test_times(int (attach)(struct perf_evlist *), TEST_ASSERT_VAL("failed to detach", !detach(evlist)); - perf_evsel__read(evsel, 0, 0, &count); + perf_evsel__read(&evsel->core, 0, 0, &count); err = !(count.ena == count.run); @@ -204,7 +207,7 @@ static int test_times(int (attach)(struct perf_evlist *), count.ena, count.run); out_err: - perf_evlist__delete(evlist); + evlist__delete(evlist); return !err ? TEST_OK : TEST_FAIL; } diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index f14dcd613438..cac4290e233a 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> +#include <perf/cpumap.h> +#include <string.h> #include "evlist.h" #include "evsel.h" +#include "header.h" #include "machine.h" +#include "tool.h" #include "tests.h" #include "debug.h" @@ -11,7 +15,7 @@ static int process_event_unit(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct event_update_event *ev = (struct event_update_event *) event; + struct perf_record_event_update *ev = (struct perf_record_event_update *)event; TEST_ASSERT_VAL("wrong id", ev->id == 123); TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT); @@ -24,10 +28,10 @@ static int process_event_scale(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct event_update_event *ev = (struct event_update_event *) event; - struct event_update_event_scale *ev_data; + struct perf_record_event_update *ev = (struct perf_record_event_update *)event; + struct perf_record_event_update_scale *ev_data; - ev_data = (struct event_update_event_scale *) ev->data; + ev_data = (struct perf_record_event_update_scale *)ev->data; TEST_ASSERT_VAL("wrong id", ev->id == 123); TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); @@ -46,7 +50,7 @@ static int process_event_name(struct perf_tool *tool, struct machine *machine __maybe_unused) { struct event_name *tmp = container_of(tool, struct event_name, tool); - struct event_update_event *ev = (struct event_update_event*) event; + struct perf_record_event_update *ev = (struct perf_record_event_update *)event; TEST_ASSERT_VAL("wrong id", ev->id == 123); TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME); @@ -59,11 +63,11 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct event_update_event *ev = (struct event_update_event*) event; - struct event_update_event_cpus *ev_data; - struct cpu_map *map; + struct perf_record_event_update *ev = (struct perf_record_event_update *)event; + struct perf_record_event_update_cpus *ev_data; + struct perf_cpu_map *map; - ev_data = (struct event_update_event_cpus*) ev->data; + ev_data = (struct perf_record_event_update_cpus *) ev->data; map = cpu_map__new_data(&ev_data->cpus); @@ -73,14 +77,14 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1); TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2); TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3); - cpu_map__put(map); + perf_cpu_map__put(map); return 0; } int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct perf_evlist *evlist; - struct perf_evsel *evsel; + struct evlist *evlist; + struct evsel *evsel; struct event_name tmp; evlist = perf_evlist__new_default(); @@ -108,11 +112,11 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu TEST_ASSERT_VAL("failed to synthesize attr update name", !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name)); - evsel->own_cpus = cpu_map__new("1,2,3"); + evsel->core.own_cpus = perf_cpu_map__new("1,2,3"); TEST_ASSERT_VAL("failed to synthesize attr update cpus", !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus)); - cpu_map__put(evsel->own_cpus); + perf_cpu_map__put(evsel->core.own_cpus); return 0; } diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index a104728ebf25..5330f106a6ee 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -11,8 +11,8 @@ static int perf_evsel__roundtrip_cache_name_test(void) { char name[128]; int type, op, err = 0, ret = 0, i, idx; - struct perf_evsel *evsel; - struct perf_evlist *evlist = perf_evlist__new(); + struct evsel *evsel; + struct evlist *evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; @@ -60,15 +60,15 @@ static int perf_evsel__roundtrip_cache_name_test(void) } } - perf_evlist__delete(evlist); + evlist__delete(evlist); return ret; } static int __perf_evsel__name_array_test(const char *names[], int nr_names) { int i, err; - struct perf_evsel *evsel; - struct perf_evlist *evlist = perf_evlist__new(); + struct evsel *evsel; + struct evlist *evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; @@ -91,7 +91,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) } out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index 71f60c0f9faa..261e6eaaee99 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -5,7 +5,7 @@ #include "tests.h" #include "debug.h" -static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, +static int perf_evsel__test_field(struct evsel *evsel, const char *name, int size, bool should_be_signed) { struct tep_format_field *field = perf_evsel__field(evsel, name); @@ -35,7 +35,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch"); + struct evsel *evsel = perf_evsel__newtp("sched", "sched_switch"); int ret = 0; if (IS_ERR(evsel)) { @@ -64,7 +64,7 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes if (perf_evsel__test_field(evsel, "next_prio", 4, true)) ret = -1; - perf_evsel__delete(evsel); + evsel__delete(evsel); evsel = perf_evsel__newtp("sched", "sched_wakeup"); @@ -85,6 +85,6 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) ret = -1; - perf_evsel__delete(evsel); + evsel__delete(evsel); return ret; } diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index ee1d88650e69..87843af4c118 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -3,6 +3,7 @@ #include "util/expr.h" #include "tests.h" #include <stdlib.h> +#include <string.h> #include <linux/zalloc.h> static int test(struct parse_ctx *ctx, const char *e, double val2) diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c index 469958cd7fe0..de110d8f169b 100644 --- a/tools/perf/tests/hists_common.c +++ b/tools/perf/tests/hists_common.c @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 #include <inttypes.h> -#include "perf.h" #include "util/debug.h" +#include "util/dso.h" #include "util/map.h" #include "util/symbol.h" #include "util/sort.h" #include "util/evsel.h" -#include "util/evlist.h" #include "util/machine.h" #include "util/thread.h" #include "tests/hists_common.h" diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 7a2eed6c783e..fa55b7bad3af 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" #include "util/debug.h" +#include "util/dso.h" #include "util/event.h" #include "util/map.h" #include "util/symbol.h" @@ -80,7 +80,7 @@ static u64 fake_callchains[][10] = { static int add_hist_entries(struct hists *hists, struct machine *machine) { struct addr_location al; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); struct perf_sample sample = { .period = 1000, }; size_t i; @@ -147,7 +147,7 @@ static void del_hist_entries(struct hists *hists) } } -typedef int (*test_fn_t)(struct perf_evsel *, struct machine *); +typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) #define DSO(he) (he->ms.map->dso->short_name) @@ -247,7 +247,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec } /* NO callchain + NO children */ -static int test1(struct perf_evsel *evsel, struct machine *machine) +static int test1(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -298,7 +298,7 @@ out: } /* callcain + NO children */ -static int test2(struct perf_evsel *evsel, struct machine *machine) +static int test2(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -446,7 +446,7 @@ out: } /* NO callchain + children */ -static int test3(struct perf_evsel *evsel, struct machine *machine) +static int test3(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -503,7 +503,7 @@ out: } /* callchain + children */ -static int test4(struct perf_evsel *evsel, struct machine *machine) +static int test4(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -694,8 +694,8 @@ int test__hists_cumulate(struct test *test __maybe_unused, int subtest __maybe_u int err = TEST_FAIL; struct machines machines; struct machine *machine; - struct perf_evsel *evsel; - struct perf_evlist *evlist = perf_evlist__new(); + struct evsel *evsel; + struct evlist *evlist = evlist__new(); size_t i; test_fn_t testcases[] = { test1, @@ -731,7 +731,7 @@ int test__hists_cumulate(struct test *test __maybe_unused, int subtest __maybe_u out: /* tear down everything */ - perf_evlist__delete(evlist); + evlist__delete(evlist); machines__exit(&machines); return err; diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 975844807fe2..618b51ffcc01 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" #include "util/debug.h" #include "util/map.h" #include "util/symbol.h" @@ -8,7 +7,6 @@ #include "util/event.h" #include "util/evlist.h" #include "util/machine.h" -#include "util/thread.h" #include "util/parse-events.h" #include "tests/tests.h" #include "tests/hists_common.h" @@ -47,10 +45,10 @@ static struct sample fake_samples[] = { { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 3 }, }; -static int add_hist_entries(struct perf_evlist *evlist, +static int add_hist_entries(struct evlist *evlist, struct machine *machine) { - struct perf_evsel *evsel; + struct evsel *evsel; struct addr_location al; struct perf_sample sample = { .period = 100, }; size_t i; @@ -108,8 +106,8 @@ int test__hists_filter(struct test *test __maybe_unused, int subtest __maybe_unu int err = TEST_FAIL; struct machines machines; struct machine *machine; - struct perf_evsel *evsel; - struct perf_evlist *evlist = perf_evlist__new(); + struct evsel *evsel; + struct evlist *evlist = evlist__new(); TEST_ASSERT_VAL("No memory", evlist); @@ -321,7 +319,7 @@ int test__hists_filter(struct test *test __maybe_unused, int subtest __maybe_unu out: /* tear down everything */ - perf_evlist__delete(evlist); + evlist__delete(evlist); reset_output_field(); machines__exit(&machines); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index af633db63f4d..8be4d0b61e3a 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" #include "tests.h" #include "debug.h" #include "symbol.h" @@ -7,7 +6,6 @@ #include "evsel.h" #include "evlist.h" #include "machine.h" -#include "thread.h" #include "parse-events.h" #include "hists_common.h" #include <errno.h> @@ -62,9 +60,9 @@ static struct sample fake_samples[][5] = { }, }; -static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) +static int add_hist_entries(struct evlist *evlist, struct machine *machine) { - struct perf_evsel *evsel; + struct evsel *evsel; struct addr_location al; struct hist_entry *he; struct perf_sample sample = { .period = 1, .weight = 1, }; @@ -271,8 +269,8 @@ int test__hists_link(struct test *test __maybe_unused, int subtest __maybe_unuse struct hists *hists, *first_hists; struct machines machines; struct machine *machine = NULL; - struct perf_evsel *evsel, *first; - struct perf_evlist *evlist = perf_evlist__new(); + struct evsel *evsel, *first; + struct evlist *evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; @@ -334,7 +332,7 @@ int test__hists_link(struct test *test __maybe_unused, int subtest __maybe_unuse out: /* tear down everything */ - perf_evlist__delete(evlist); + evlist__delete(evlist); reset_output_field(); machines__exit(&machines); diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 0a510c524a5d..3f6dfa212260 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" #include "util/debug.h" +#include "util/dso.h" #include "util/event.h" #include "util/map.h" #include "util/symbol.h" @@ -50,7 +50,7 @@ static struct sample fake_samples[] = { static int add_hist_entries(struct hists *hists, struct machine *machine) { struct addr_location al; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); struct perf_sample sample = { .period = 100, }; size_t i; @@ -113,7 +113,7 @@ static void del_hist_entries(struct hists *hists) } } -typedef int (*test_fn_t)(struct perf_evsel *, struct machine *); +typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) #define DSO(he) (he->ms.map->dso->short_name) @@ -122,7 +122,7 @@ typedef int (*test_fn_t)(struct perf_evsel *, struct machine *); #define PID(he) (he->thread->tid) /* default sort keys (no field) */ -static int test1(struct perf_evsel *evsel, struct machine *machine) +static int test1(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -224,7 +224,7 @@ out: } /* mixed fields and sort keys */ -static int test2(struct perf_evsel *evsel, struct machine *machine) +static int test2(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -280,7 +280,7 @@ out: } /* fields only (no sort key) */ -static int test3(struct perf_evsel *evsel, struct machine *machine) +static int test3(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -354,7 +354,7 @@ out: } /* handle duplicate 'dso' field */ -static int test4(struct perf_evsel *evsel, struct machine *machine) +static int test4(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -456,7 +456,7 @@ out: } /* full sort keys w/o overhead field */ -static int test5(struct perf_evsel *evsel, struct machine *machine) +static int test5(struct evsel *evsel, struct machine *machine) { int err; struct hists *hists = evsel__hists(evsel); @@ -580,8 +580,8 @@ int test__hists_output(struct test *test __maybe_unused, int subtest __maybe_unu int err = TEST_FAIL; struct machines machines; struct machine *machine; - struct perf_evsel *evsel; - struct perf_evlist *evlist = perf_evlist__new(); + struct evsel *evsel; + struct evlist *evlist = evlist__new(); size_t i; test_fn_t testcases[] = { test1, @@ -618,7 +618,7 @@ int test__hists_output(struct test *test __maybe_unused, int subtest __maybe_unu out: /* tear down everything */ - perf_evlist__delete(evlist); + evlist__delete(evlist); machines__exit(&machines); return err; diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 17c46f3e6f1e..9f0762d987fa 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/types.h> +#include <limits.h> #include <unistd.h> #include <sys/prctl.h> +#include <perf/cpumap.h> +#include <perf/evlist.h> +#include "debug.h" #include "parse-events.h" #include "evlist.h" #include "evsel.h" +#include "record.h" #include "thread_map.h" #include "cpumap.h" #include "tests.h" @@ -24,7 +29,7 @@ } \ } -static int find_comm(struct perf_evlist *evlist, const char *comm) +static int find_comm(struct evlist *evlist, const char *comm) { union perf_event *event; struct perf_mmap *md; @@ -65,23 +70,23 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un .uses_mmap = true, }, }; - struct thread_map *threads = NULL; - struct cpu_map *cpus = NULL; - struct perf_evlist *evlist = NULL; - struct perf_evsel *evsel = NULL; + struct perf_thread_map *threads = NULL; + struct perf_cpu_map *cpus = NULL; + struct evlist *evlist = NULL; + struct evsel *evsel = NULL; int found, err = -1; const char *comm; threads = thread_map__new(-1, getpid(), UINT_MAX); CHECK_NOT_NULL__(threads); - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); CHECK_NOT_NULL__(cpus); - evlist = perf_evlist__new(); + evlist = evlist__new(); CHECK_NOT_NULL__(evlist); - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); CHECK__(parse_events(evlist, "dummy:u", NULL)); CHECK__(parse_events(evlist, "cycles:u", NULL)); @@ -90,11 +95,11 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un evsel = perf_evlist__first(evlist); - evsel->attr.comm = 1; - evsel->attr.disabled = 1; - evsel->attr.enable_on_exec = 0; + evsel->core.attr.comm = 1; + evsel->core.attr.disabled = 1; + evsel->core.attr.enable_on_exec = 0; - if (perf_evlist__open(evlist) < 0) { + if (evlist__open(evlist) < 0) { pr_debug("Unable to open dummy and cycles event\n"); err = TEST_SKIP; goto out_err; @@ -107,12 +112,12 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un * enabled. */ - perf_evlist__enable(evlist); + evlist__enable(evlist); comm = "Test COMM 1"; CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); - perf_evlist__disable(evlist); + evlist__disable(evlist); found = find_comm(evlist, comm); if (found != 1) { @@ -125,16 +130,16 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un * disabled with the dummy event still enabled. */ - perf_evlist__enable(evlist); + evlist__enable(evlist); evsel = perf_evlist__last(evlist); - CHECK__(perf_evsel__disable(evsel)); + CHECK__(evsel__disable(evsel)); comm = "Test COMM 2"; CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); - perf_evlist__disable(evlist); + evlist__disable(evlist); found = find_comm(evlist, comm); if (found != 1) { @@ -146,11 +151,11 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un out_err: if (evlist) { - perf_evlist__disable(evlist); - perf_evlist__delete(evlist); + evlist__disable(evlist); + evlist__delete(evlist); } else { - cpu_map__put(cpus); - thread_map__put(threads); + perf_cpu_map__put(cpus); + perf_thread_map__put(threads); } return err; diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c index 0579a70bbbff..e483210b176b 100644 --- a/tools/perf/tests/kmod-path.c +++ b/tools/perf/tests/kmod-path.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 #include <stdbool.h> #include <stdlib.h> +#include <string.h> #include "tests.h" #include "dso.h" #include "debug.h" +#include "event.h" static int test(const char *path, bool alloc_name, bool kmod, int comp, const char *name) diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index ca5a5f94ce79..022e4c9cf092 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <bpf/libbpf.h> #include <util/llvm-utils.h> -#include <util/cache.h> #include "llvm.h" #include "tests.h" #include "debug.h" diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 5363a12a8b9b..70c48475896d 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -108,6 +108,7 @@ make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 +make_minimal += NO_LIBCAP=1 # $(run) contains all available tests run := make_pure diff --git a/tools/perf/tests/mem.c b/tools/perf/tests/mem.c index efe3397824d2..673a11a6cd1b 100644 --- a/tools/perf/tests/mem.c +++ b/tools/perf/tests/mem.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include "util/map_symbol.h" #include "util/mem-events.h" #include "util/symbol.h" #include "linux/perf_event.h" diff --git a/tools/perf/tests/mem2node.c b/tools/perf/tests/mem2node.c index 520cc91af256..7672ade70f20 100644 --- a/tools/perf/tests/mem2node.c +++ b/tools/perf/tests/mem2node.c @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> #include <linux/bitmap.h> +#include <linux/kernel.h> #include <linux/zalloc.h> +#include <perf/cpumap.h> #include "cpumap.h" +#include "debug.h" +#include "env.h" #include "mem2node.h" #include "tests.h" @@ -19,7 +23,7 @@ static struct node { static unsigned long *get_bitmap(const char *str, int nbits) { - struct cpu_map *map = cpu_map__new(str); + struct perf_cpu_map *map = perf_cpu_map__new(str); unsigned long *bm = NULL; int i; @@ -32,7 +36,7 @@ static unsigned long *get_bitmap(const char *str, int nbits) } if (map) - cpu_map__put(map); + perf_cpu_map__put(map); else free(bm); diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 0919b0793e5b..85e1d7337dc0 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -3,7 +3,10 @@ #include <inttypes.h> /* For the CLR_() macros */ #include <pthread.h> +#include <stdlib.h> +#include <perf/cpumap.h> +#include "debug.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" @@ -11,6 +14,8 @@ #include "tests.h" #include <linux/err.h> #include <linux/kernel.h> +#include <linux/string.h> +#include <perf/evlist.h> /* * This test will generate random numbers of calls to some getpid syscalls, @@ -27,16 +32,16 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse { int err = -1; union perf_event *event; - struct thread_map *threads; - struct cpu_map *cpus; - struct perf_evlist *evlist; + struct perf_thread_map *threads; + struct perf_cpu_map *cpus; + struct evlist *evlist; cpu_set_t cpu_set; const char *syscall_names[] = { "getsid", "getppid", "getpgid", }; pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid }; #define nsyscalls ARRAY_SIZE(syscall_names) unsigned int nr_events[nsyscalls], expected_nr_events[nsyscalls], i, j; - struct perf_evsel *evsels[nsyscalls], *evsel; + struct evsel *evsels[nsyscalls], *evsel; char sbuf[STRERR_BUFSIZE]; struct perf_mmap *md; @@ -46,7 +51,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse return -1; } - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (cpus == NULL) { pr_debug("cpu_map__new\n"); goto out_free_threads; @@ -61,13 +66,13 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse goto out_free_cpus; } - evlist = perf_evlist__new(); + evlist = evlist__new(); if (evlist == NULL) { pr_debug("perf_evlist__new\n"); goto out_free_cpus; } - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); for (i = 0; i < nsyscalls; ++i) { char name[64]; @@ -79,12 +84,12 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse goto out_delete_evlist; } - evsels[i]->attr.wakeup_events = 1; + evsels[i]->core.attr.wakeup_events = 1; perf_evsel__set_sample_id(evsels[i], false); - perf_evlist__add(evlist, evsels[i]); + evlist__add(evlist, evsels[i]); - if (perf_evsel__open(evsels[i], cpus, threads) < 0) { + if (evsel__open(evsels[i], cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -151,12 +156,12 @@ out_init: } out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); cpus = NULL; threads = NULL; out_free_cpus: - cpu_map__put(cpus); + perf_cpu_map__put(cpus); out_free_threads: - thread_map__put(threads); + perf_thread_map__put(threads); return err; } diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index 0a4301a5155c..360d70deb855 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -138,7 +138,7 @@ static int synth_all(struct machine *machine) static int synth_process(struct machine *machine) { - struct thread_map *map; + struct perf_thread_map *map; int err; map = thread_map__new_by_pid(getpid()); @@ -147,7 +147,7 @@ static int synth_process(struct machine *machine) perf_event__process, machine, 0); - thread_map__put(map); + perf_thread_map__put(map); return err; } diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 493ecb611540..9171f77cd9cd 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -9,6 +9,7 @@ #include <fcntl.h> #include <api/fs/fs.h> #include <linux/err.h> +#include <linux/string.h> #include <api/fs/tracing_path.h> #include "evsel.h" #include "tests.h" @@ -16,15 +17,16 @@ #include "cpumap.h" #include "debug.h" #include "stat.h" +#include "util/counts.h" int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int subtest __maybe_unused) { int err = -1, fd, cpu; - struct cpu_map *cpus; - struct perf_evsel *evsel; + struct perf_cpu_map *cpus; + struct evsel *evsel; unsigned int nr_openat_calls = 111, i; cpu_set_t cpu_set; - struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); + struct perf_thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); char sbuf[STRERR_BUFSIZE]; char errbuf[BUFSIZ]; @@ -33,7 +35,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int return -1; } - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (cpus == NULL) { pr_debug("cpu_map__new\n"); goto out_thread_map_delete; @@ -48,7 +50,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int goto out_cpu_map_delete; } - if (perf_evsel__open(evsel, cpus, threads) < 0) { + if (evsel__open(evsel, cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -116,12 +118,12 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int perf_evsel__free_counts(evsel); out_close_fd: - perf_evsel__close_fd(evsel); + perf_evsel__close_fd(&evsel->core); out_evsel_delete: - perf_evsel__delete(evsel); + evsel__delete(evsel); out_cpu_map_delete: - cpu_map__put(cpus); + perf_cpu_map__put(cpus); out_thread_map_delete: - thread_map__put(threads); + perf_thread_map__put(threads); return err; } diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 344dc3ac2469..b71167b43dda 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 +#include <stdbool.h> #include <linux/err.h> +#include <linux/string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> -#include "perf.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" +#include "record.h" #include "tests.h" #include "debug.h" #include <errno.h> @@ -32,8 +34,8 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest }; const char *filename = "/etc/passwd"; int flags = O_RDONLY | O_DIRECTORY; - struct perf_evlist *evlist = perf_evlist__new(); - struct perf_evsel *evsel; + struct evlist *evlist = evlist__new(); + struct evsel *evsel; int err = -1, i, nr_events = 0, nr_polls = 0; char sbuf[STRERR_BUFSIZE]; @@ -48,7 +50,7 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest goto out_delete_evlist; } - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); err = perf_evlist__create_maps(evlist, &opts.target); if (err < 0) { @@ -58,9 +60,9 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest perf_evsel__config(evsel, &opts, NULL); - thread_map__set_pid(evlist->threads, 0, getpid()); + perf_thread_map__set_pid(evlist->core.threads, 0, getpid()); - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -74,7 +76,7 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest goto out_delete_evlist; } - perf_evlist__enable(evlist); + evlist__enable(evlist); /* * Generate the event: @@ -134,7 +136,7 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest out_ok: err = 0; out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); out: return err; } diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 00cd63f90b92..5ebffae18605 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -3,6 +3,7 @@ #include <inttypes.h> #include <api/fs/tracing_path.h> #include <linux/err.h> +#include <linux/string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -10,13 +11,14 @@ #include "evsel.h" #include "debug.h" #include "tests.h" +#include "util/counts.h" int test__openat_syscall_event(struct test *test __maybe_unused, int subtest __maybe_unused) { int err = -1, fd; - struct perf_evsel *evsel; + struct evsel *evsel; unsigned int nr_openat_calls = 111, i; - struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); + struct perf_thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); char sbuf[STRERR_BUFSIZE]; char errbuf[BUFSIZ]; @@ -57,10 +59,10 @@ int test__openat_syscall_event(struct test *test __maybe_unused, int subtest __m err = 0; out_close_fd: - perf_evsel__close_fd(evsel); + perf_evsel__close_fd(&evsel->core); out_evsel_delete: - perf_evsel__delete(evsel); + evsel__delete(evsel); out_thread_map_delete: - thread_map__put(threads); + perf_thread_map__put(threads); return err; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 8f3c80e13584..02ba696fb87f 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -5,6 +5,7 @@ #include <api/fs/fs.h> #include "tests.h" #include "debug.h" +#include "pmu.h" #include "util.h" #include <dirent.h> #include <errno.h> @@ -44,549 +45,549 @@ static bool kvm_s390_create_vm_valid(void) } #endif -static int test__checkevent_tracepoint(struct perf_evlist *evlist) +static int test__checkevent_tracepoint(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); - TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); + PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); + TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->core.attr.sample_period); return 0; } -static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) +static int test__checkevent_tracepoint_multi(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); + TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", - PERF_TYPE_TRACEPOINT == evsel->attr.type); + PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); + PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); TEST_ASSERT_VAL("wrong sample_period", - 1 == evsel->attr.sample_period); + 1 == evsel->core.attr.sample_period); } return 0; } -static int test__checkevent_raw(struct perf_evlist *evlist) +static int test__checkevent_raw(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config); return 0; } -static int test__checkevent_numeric(struct perf_evlist *evlist) +static int test__checkevent_numeric(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", 1 == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); return 0; } -static int test__checkevent_symbolic_name(struct perf_evlist *evlist) +static int test__checkevent_symbolic_name(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); return 0; } -static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist) +static int test__checkevent_symbolic_name_config(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); /* * The period value gets configured within perf_evlist__config, * while this test executes only parse events method. */ TEST_ASSERT_VAL("wrong period", - 0 == evsel->attr.sample_period); + 0 == evsel->core.attr.sample_period); TEST_ASSERT_VAL("wrong config1", - 0 == evsel->attr.config1); + 0 == evsel->core.attr.config1); TEST_ASSERT_VAL("wrong config2", - 1 == evsel->attr.config2); + 1 == evsel->core.attr.config2); return 0; } -static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) +static int test__checkevent_symbolic_alias(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config); + PERF_COUNT_SW_PAGE_FAULTS == evsel->core.attr.config); return 0; } -static int test__checkevent_genhw(struct perf_evlist *evlist) +static int test__checkevent_genhw(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->core.attr.config); return 0; } -static int test__checkevent_breakpoint(struct perf_evlist *evlist) +static int test__checkevent_breakpoint(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == - evsel->attr.bp_type); + evsel->core.attr.bp_type); TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 == - evsel->attr.bp_len); + evsel->core.attr.bp_len); return 0; } -static int test__checkevent_breakpoint_x(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_x(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", - HW_BREAKPOINT_X == evsel->attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len); + HW_BREAKPOINT_X == evsel->core.attr.bp_type); + TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->core.attr.bp_len); return 0; } -static int test__checkevent_breakpoint_r(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_r(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", - PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", - HW_BREAKPOINT_R == evsel->attr.bp_type); + HW_BREAKPOINT_R == evsel->core.attr.bp_type); TEST_ASSERT_VAL("wrong bp_len", - HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); + HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len); return 0; } -static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_w(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", - PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", - HW_BREAKPOINT_W == evsel->attr.bp_type); + HW_BREAKPOINT_W == evsel->core.attr.bp_type); TEST_ASSERT_VAL("wrong bp_len", - HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); + HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len); return 0; } -static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_rw(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", - PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", - (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->attr.bp_type); + (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->core.attr.bp_type); TEST_ASSERT_VAL("wrong bp_len", - HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); + HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len); return 0; } -static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) +static int test__checkevent_tracepoint_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); return test__checkevent_tracepoint(evlist); } static int -test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) +test__checkevent_tracepoint_multi_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); + TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong exclude_user", - !evsel->attr.exclude_user); + !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); } return test__checkevent_tracepoint_multi(evlist); } -static int test__checkevent_raw_modifier(struct perf_evlist *evlist) +static int test__checkevent_raw_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); return test__checkevent_raw(evlist); } -static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) +static int test__checkevent_numeric_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); return test__checkevent_numeric(evlist); } -static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) +static int test__checkevent_symbolic_name_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); return test__checkevent_symbolic_name(evlist); } -static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) +static int test__checkevent_exclude_host_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); return test__checkevent_symbolic_name(evlist); } -static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) +static int test__checkevent_exclude_guest_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); return test__checkevent_symbolic_name(evlist); } -static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) +static int test__checkevent_symbolic_alias_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); return test__checkevent_symbolic_alias(evlist); } -static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) +static int test__checkevent_genhw_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); return test__checkevent_genhw(evlist); } -static int test__checkevent_exclude_idle_modifier(struct perf_evlist *evlist) +static int test__checkevent_exclude_idle_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude idle", evsel->attr.exclude_idle); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude idle", evsel->core.attr.exclude_idle); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); return test__checkevent_symbolic_name(evlist); } -static int test__checkevent_exclude_idle_modifier_1(struct perf_evlist *evlist) +static int test__checkevent_exclude_idle_modifier_1(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude idle", evsel->attr.exclude_idle); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude idle", evsel->core.attr.exclude_idle); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); return test__checkevent_symbolic_name(evlist); } -static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "mem:0:u")); return test__checkevent_breakpoint(evlist); } -static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_x_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "mem:0:x:k")); return test__checkevent_breakpoint_x(evlist); } -static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_r_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "mem:0:r:hp")); return test__checkevent_breakpoint_r(evlist); } -static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_w_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "mem:0:w:up")); return test__checkevent_breakpoint_w(evlist); } -static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_rw_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "mem:0:rw:kp")); return test__checkevent_breakpoint_rw(evlist); } -static int test__checkevent_pmu(struct perf_evlist *evlist) +static int test__checkevent_pmu(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config); - TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1); - TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); + TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2); /* * The period value gets configured within perf_evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); + TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); return 0; } -static int test__checkevent_list(struct perf_evlist *evlist) +static int test__checkevent_list(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); /* r1 */ - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); - TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); - TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong config1", 0 == evsel->core.attr.config1); + TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); /* syscalls:sys_enter_openat:k */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); - TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); + TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->core.attr.sample_period); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); /* 1:1:hp */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong type", 1 == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); return 0; } -static int test__checkevent_pmu_name(struct perf_evlist *evlist) +static int test__checkevent_pmu_name(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); /* cpu/config=1,name=krava/u */ - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava")); /* cpu/config=2/u" */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 2 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "cpu/config=2/u")); return 0; } -static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlist) +static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); /* cpu/config=1,call-graph=fp,time,period=100000/ */ - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); /* * The period, time and callgraph value gets configured * within perf_evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); + TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); - TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); + TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->core.attr.sample_type)); /* cpu/config=2,call-graph=no,time=0,period=2000/ */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 2 == evsel->core.attr.config); /* * The period, time and callgraph value gets configured * within perf_evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); + TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); - TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); + TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->core.attr.sample_type)); return 0; } -static int test__checkevent_pmu_events(struct perf_evlist *evlist) +static int test__checkevent_pmu_events(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong exclude_user", - !evsel->attr.exclude_user); + !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned); + evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); return 0; } -static int test__checkevent_pmu_events_mix(struct perf_evlist *evlist) +static int test__checkevent_pmu_events_mix(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); /* pmu-event:u */ - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong exclude_user", - !evsel->attr.exclude_user); + !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned); + evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); /* cpu/pmu-event/u*/ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong exclude_user", - !evsel->attr.exclude_user); + !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned); + evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); return 0; } @@ -634,41 +635,41 @@ static int test__checkterms_simple(struct list_head *terms) return 0; } -static int test__group1(struct perf_evlist *evlist) +static int test__group1(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* instructions:k */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* cycles:upp */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -676,99 +677,99 @@ static int test__group1(struct perf_evlist *evlist) return 0; } -static int test__group2(struct perf_evlist *evlist) +static int test__group2(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* faults + :ku modifier */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_SW_PAGE_FAULTS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* cache-references + :u modifier */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_REFERENCES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CACHE_REFERENCES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* cycles:k */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); return 0; } -static int test__group3(struct perf_evlist *evlist __maybe_unused) +static int test__group3(struct evlist *evlist __maybe_unused) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); /* group1 syscalls:sys_enter_openat:H */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); - TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); + TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->core.attr.sample_period); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); TEST_ASSERT_VAL("wrong group name", !strcmp(leader->group_name, "group1")); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* group1 cycles:kppp */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 3); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); @@ -776,90 +777,90 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) /* group2 cycles + G modifier */ evsel = leader = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); TEST_ASSERT_VAL("wrong group name", !strcmp(leader->group_name, "group2")); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* group2 1:3 + G modifier */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong type", 1 == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 3 == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* instructions:u */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); return 0; } -static int test__group4(struct perf_evlist *evlist __maybe_unused) +static int test__group4(struct evlist *evlist __maybe_unused) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles:u + p */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 1); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* instructions:kp + p */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -867,298 +868,298 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) return 0; } -static int test__group5(struct perf_evlist *evlist __maybe_unused) +static int test__group5(struct evlist *evlist __maybe_unused) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); /* cycles + G */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* instructions + G */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* cycles:G */ evsel = leader = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); /* instructions:G */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); /* cycles */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); return 0; } -static int test__group_gh1(struct perf_evlist *evlist) +static int test__group_gh1(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles + :H group modifier */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); /* cache-misses:G + :H group modifier */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CACHE_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); return 0; } -static int test__group_gh2(struct perf_evlist *evlist) +static int test__group_gh2(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles + :G group modifier */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); /* cache-misses:H + :G group modifier */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CACHE_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); return 0; } -static int test__group_gh3(struct perf_evlist *evlist) +static int test__group_gh3(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles:G + :u group modifier */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); /* cache-misses:H + :u group modifier */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CACHE_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); return 0; } -static int test__group_gh4(struct perf_evlist *evlist) +static int test__group_gh4(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles:G + :uG group modifier */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); /* cache-misses:H + :uG group modifier */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CACHE_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); return 0; } -static int test__leader_sample1(struct perf_evlist *evlist) +static int test__leader_sample1(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); /* cycles - sampling group leader */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* cache-misses - not sampling */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_CACHE_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* branch-misses - not sampling */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_BRANCH_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); @@ -1166,38 +1167,38 @@ static int test__leader_sample1(struct perf_evlist *evlist) return 0; } -static int test__leader_sample2(struct perf_evlist *evlist __maybe_unused) +static int test__leader_sample2(struct evlist *evlist __maybe_unused) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); /* instructions - sampling group leader */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* branch-misses - not sampling */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + PERF_COUNT_HW_BRANCH_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); @@ -1205,131 +1206,131 @@ static int test__leader_sample2(struct perf_evlist *evlist __maybe_unused) return 0; } -static int test__checkevent_pinned_modifier(struct perf_evlist *evlist) +static int test__checkevent_pinned_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); + TEST_ASSERT_VAL("wrong pinned", evsel->core.attr.pinned); return test__checkevent_symbolic_name(evlist); } -static int test__pinned_group(struct perf_evlist *evlist) +static int test__pinned_group(struct evlist *evlist) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); /* cycles - group leader */ evsel = leader = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); + PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); - TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned); + TEST_ASSERT_VAL("wrong pinned", evsel->core.attr.pinned); /* cache-misses - can not be pinned, but will go on with the leader */ evsel = perf_evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned); + PERF_COUNT_HW_CACHE_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); /* branch-misses - ditto */ evsel = perf_evsel__next(evsel); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config); - TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned); + PERF_COUNT_HW_BRANCH_MISSES == evsel->core.attr.config); + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); return 0; } -static int test__checkevent_breakpoint_len(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_len(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == - evsel->attr.bp_type); + evsel->core.attr.bp_type); TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_1 == - evsel->attr.bp_len); + evsel->core.attr.bp_len); return 0; } -static int test__checkevent_breakpoint_len_w(struct perf_evlist *evlist) +static int test__checkevent_breakpoint_len_w(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong bp_type", HW_BREAKPOINT_W == - evsel->attr.bp_type); + evsel->core.attr.bp_type); TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_2 == - evsel->attr.bp_len); + evsel->core.attr.bp_len); return 0; } static int -test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist) +test__checkevent_breakpoint_len_rw_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); return test__checkevent_breakpoint_rw(evlist); } -static int test__checkevent_precise_max_modifier(struct perf_evlist *evlist) +static int test__checkevent_precise_max_modifier(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", - PERF_COUNT_SW_TASK_CLOCK == evsel->attr.config); + PERF_COUNT_SW_TASK_CLOCK == evsel->core.attr.config); return 0; } -static int test__checkevent_config_symbol(struct perf_evlist *evlist) +static int test__checkevent_config_symbol(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "insn") == 0); return 0; } -static int test__checkevent_config_raw(struct perf_evlist *evlist) +static int test__checkevent_config_raw(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "rawpmu") == 0); return 0; } -static int test__checkevent_config_num(struct perf_evlist *evlist) +static int test__checkevent_config_num(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "numpmu") == 0); return 0; } -static int test__checkevent_config_cache(struct perf_evlist *evlist) +static int test__checkevent_config_cache(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "cachepmu") == 0); return 0; @@ -1340,39 +1341,39 @@ static bool test__intel_pt_valid(void) return !!perf_pmu__find("intel_pt"); } -static int test__intel_pt(struct perf_evlist *evlist) +static int test__intel_pt(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "intel_pt//u") == 0); return 0; } -static int test__checkevent_complex_name(struct perf_evlist *evlist) +static int test__checkevent_complex_name(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); TEST_ASSERT_VAL("wrong complex name parsing", strcmp(evsel->name, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks") == 0); return 0; } -static int test__sym_event_slash(struct perf_evlist *evlist) +static int test__sym_event_slash(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", evsel->attr.type == PERF_TYPE_HARDWARE); - TEST_ASSERT_VAL("wrong config", evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); + TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); return 0; } -static int test__sym_event_dc(struct perf_evlist *evlist) +static int test__sym_event_dc(struct evlist *evlist) { - struct perf_evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = perf_evlist__first(evlist); - TEST_ASSERT_VAL("wrong type", evsel->attr.type == PERF_TYPE_HARDWARE); - TEST_ASSERT_VAL("wrong config", evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); + TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES); + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); return 0; } @@ -1422,10 +1423,10 @@ static int count_tracepoints(void) return cnt; } -static int test__all_tracepoints(struct perf_evlist *evlist) +static int test__all_tracepoints(struct evlist *evlist) { TEST_ASSERT_VAL("wrong events count", - count_tracepoints() == evlist->nr_entries); + count_tracepoints() == evlist->core.nr_entries); return test__checkevent_tracepoint_multi(evlist); } @@ -1435,7 +1436,7 @@ struct evlist_test { __u32 type; const int id; bool (*valid)(void); - int (*check)(struct perf_evlist *evlist); + int (*check)(struct evlist *evlist); }; static struct evlist_test test__events[] = { @@ -1769,7 +1770,7 @@ static struct terms_test test__terms[] = { static int test_event(struct evlist_test *e) { struct parse_events_error err = { .idx = 0, }; - struct perf_evlist *evlist; + struct evlist *evlist; int ret; if (e->valid && !e->valid()) { @@ -1777,7 +1778,7 @@ static int test_event(struct evlist_test *e) return 0; } - evlist = perf_evlist__new(); + evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; @@ -1790,7 +1791,7 @@ static int test_event(struct evlist_test *e) ret = e->check(evlist); } - perf_evlist__delete(evlist); + evlist__delete(evlist); return ret; } diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 2196d1497c0c..8284752a60c8 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -11,7 +11,7 @@ #include "util.h" #include "debug.h" -static int process_event(struct perf_evlist **pevlist, union perf_event *event) +static int process_event(struct evlist **pevlist, union perf_event *event) { struct perf_sample sample; @@ -39,14 +39,14 @@ static int process_event(struct perf_evlist **pevlist, union perf_event *event) static int process_events(union perf_event **events, size_t count) { - struct perf_evlist *evlist = NULL; + struct evlist *evlist = NULL; int err = 0; size_t i; for (i = 0; i < count && !err; i++) err = process_event(&evlist, events[i]); - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } @@ -87,10 +87,10 @@ int test__parse_no_sample_id_all(struct test *test __maybe_unused, int subtest _ }, .id = 2, }; - struct mmap_event event3 = { + struct perf_record_mmap event3 = { .header = { .type = PERF_RECORD_MMAP, - .size = sizeof(struct mmap_event), + .size = sizeof(struct perf_record_mmap), }, }; union perf_event *events[] = { diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 07f6bd8ed719..e1b42292cf7f 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -1,14 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <inttypes.h> +#include <linux/string.h> /* For the CLR_() macros */ #include <pthread.h> #include <sched.h> #include "evlist.h" #include "evsel.h" -#include "perf.h" #include "debug.h" +#include "record.h" #include "tests.h" static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp) @@ -50,8 +51,8 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus }; cpu_set_t cpu_mask; size_t cpu_mask_size = sizeof(cpu_mask); - struct perf_evlist *evlist = perf_evlist__new_dummy(); - struct perf_evsel *evsel; + struct evlist *evlist = perf_evlist__new_dummy(); + struct evsel *evsel; struct perf_sample sample; const char *cmd = "sleep"; const char *argv[] = { cmd, "1", NULL, }; @@ -130,7 +131,7 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus * Call sys_perf_event_open on all the fds on all the evsels, * grouping them if asked to. */ - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -153,7 +154,7 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus * Now that all is properly set up, enable the events, they will * count just on workload.pid, which will start... */ - perf_evlist__enable(evlist); + evlist__enable(evlist); /* * Now! @@ -325,7 +326,7 @@ found_exit: ++errs; } out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); out: return (err < 0 || errs > 0) ? -1 : 0; } diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 361714e2583c..5fcc06817076 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -2,10 +2,12 @@ #include <stdbool.h> #include <inttypes.h> #include <stdlib.h> +#include <string.h> #include <linux/bitops.h> #include <linux/kernel.h> #include <linux/types.h> +#include "map_symbol.h" #include "branch.h" #include "util.h" #include "event.h" @@ -153,11 +155,13 @@ static bool samples_same(const struct perf_sample *s1, static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) { - struct perf_evsel evsel = { + struct evsel evsel = { .needs_swap = false, - .attr = { - .sample_type = sample_type, - .read_format = read_format, + .core = { + . attr = { + .sample_type = sample_type, + .read_format = read_format, + }, }, }; union perf_event *event; @@ -221,10 +225,10 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) int err, ret = -1; if (sample_type & PERF_SAMPLE_REGS_USER) - evsel.attr.sample_regs_user = sample_regs; + evsel.core.attr.sample_regs_user = sample_regs; if (sample_type & PERF_SAMPLE_REGS_INTR) - evsel.attr.sample_regs_intr = sample_regs; + evsel.core.attr.sample_regs_intr = sample_regs; for (i = 0; i < sizeof(regs); i++) *(i + (u8 *)regs) = i & 0xfe; diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c index 8bfaa630389c..cf1bd57d3023 100644 --- a/tools/perf/tests/sdt.c +++ b/tools/perf/tests/sdt.c @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> +#include <limits.h> #include <stdio.h> +#include <stdlib.h> #include <sys/epoll.h> -#include <util/evlist.h> #include <util/symbol.h> #include <linux/filter.h> #include "tests.h" #include "debug.h" #include "probe-file.h" #include "build-id.h" +#include "util.h" /* To test SDT event, we need libelf support to scan elf binary */ #if defined(HAVE_SDT_EVENT) && defined(HAVE_LIBELF_SUPPORT) diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp.sh b/tools/perf/tests/shell/record+zstd_comp_decomp.sh index 899604d17b85..63a91ec473bb 100755 --- a/tools/perf/tests/shell/record+zstd_comp_decomp.sh +++ b/tools/perf/tests/shell/record+zstd_comp_decomp.sh @@ -13,7 +13,7 @@ skip_if_no_z_record() { collect_z_record() { echo "Collecting compressed record file:" $perf_tool record -o $trace_file -g -z -F 5000 -- \ - dd count=500 if=/dev/random of=/dev/null + dd count=500 if=/dev/urandom of=/dev/null } check_compressed_stats() { diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index 45d269b0157e..11cc2af13f2b 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -32,6 +32,10 @@ if [ $err -ne 0 ] ; then exit $err fi +# Do not use whatever ~/.perfconfig file, it may change the output +# via trace.{show_timestamp,show_prefix,etc} +export PERF_CONFIG=/dev/null + trace_open_vfs_getname err=$? rm -f ${file} diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c index 94250024684a..cc10b4116c9f 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -6,7 +6,7 @@ #include "counts.h" #include "debug.h" -static bool has_term(struct stat_config_event *config, +static bool has_term(struct perf_record_stat_config *config, u64 tag, u64 val) { unsigned i; @@ -25,7 +25,7 @@ static int process_stat_config_event(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct stat_config_event *config = &event->stat_config; + struct perf_record_stat_config *config = &event->stat_config; struct perf_stat_config stat_config; #define HAS(term, val) \ @@ -65,7 +65,7 @@ static int process_stat_event(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct stat_event *st = &event->stat; + struct perf_record_stat *st = &event->stat; TEST_ASSERT_VAL("wrong cpu", st->cpu == 1); TEST_ASSERT_VAL("wrong thread", st->thread == 2); @@ -95,7 +95,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct stat_round_event *stat_round = &event->stat_round; + struct perf_record_stat_round *stat_round = &event->stat_round; TEST_ASSERT_VAL("wrong time", stat_round->time == 0xdeadbeef); TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL); diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index f9490b237893..97694a040986 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -5,12 +5,15 @@ #include <stdlib.h> #include <signal.h> #include <sys/mman.h> +#include <linux/string.h> #include "tests.h" +#include "util/debug.h" #include "util/evsel.h" #include "util/evlist.h" #include "util/cpumap.h" #include "util/thread_map.h" +#include <perf/evlist.h> #define NR_LOOPS 10000000 @@ -27,8 +30,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) int nr_samples = 0; char sbuf[STRERR_BUFSIZE]; union perf_event *event; - struct perf_evsel *evsel; - struct perf_evlist *evlist; + struct evsel *evsel; + struct evlist *evlist; struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = clock_id, @@ -37,26 +40,26 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) .disabled = 1, .freq = 1, }; - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; struct perf_mmap *md; attr.sample_freq = 500; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (evlist == NULL) { - pr_debug("perf_evlist__new\n"); + pr_debug("evlist__new\n"); return -1; } - evsel = perf_evsel__new(&attr); + evsel = evsel__new(&attr); if (evsel == NULL) { pr_debug("perf_evsel__new\n"); goto out_delete_evlist; } - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); - cpus = cpu_map__dummy_new(); + cpus = perf_cpu_map__dummy_new(); threads = thread_map__new_by_tid(getpid()); if (!cpus || !threads) { err = -ENOMEM; @@ -64,12 +67,12 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) goto out_free_maps; } - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); cpus = NULL; threads = NULL; - if (perf_evlist__open(evlist)) { + if (evlist__open(evlist)) { const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate"; err = -errno; @@ -86,13 +89,13 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) goto out_delete_evlist; } - perf_evlist__enable(evlist); + evlist__enable(evlist); /* collect samples */ for (i = 0; i < NR_LOOPS; i++) tmp++; - perf_evlist__disable(evlist); + evlist__disable(evlist); md = &evlist->mmap[0]; if (perf_mmap__read_init(md) < 0) @@ -125,10 +128,10 @@ out_init: } out_free_maps: - cpu_map__put(cpus); - thread_map__put(threads); + perf_cpu_map__put(cpus); + perf_thread_map__put(threads); out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index 6cdab5f4812a..1a60fa1219f5 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -2,15 +2,20 @@ #include <sys/time.h> #include <sys/prctl.h> #include <errno.h> +#include <limits.h> #include <time.h> #include <stdlib.h> #include <linux/zalloc.h> +#include <perf/cpumap.h> +#include <perf/evlist.h> +#include "debug.h" #include "parse-events.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "record.h" #include "tests.h" static int spin_sleep(void) @@ -52,8 +57,8 @@ static int spin_sleep(void) } struct switch_tracking { - struct perf_evsel *switch_evsel; - struct perf_evsel *cycles_evsel; + struct evsel *switch_evsel; + struct evsel *cycles_evsel; pid_t *tids; int nr_tids; int comm_seen[4]; @@ -113,12 +118,12 @@ static int check_cpu(struct switch_tracking *switch_tracking, int cpu) return 0; } -static int process_sample_event(struct perf_evlist *evlist, +static int process_sample_event(struct evlist *evlist, union perf_event *event, struct switch_tracking *switch_tracking) { struct perf_sample sample; - struct perf_evsel *evsel; + struct evsel *evsel; pid_t next_tid, prev_tid; int cpu, err; @@ -163,7 +168,7 @@ static int process_sample_event(struct perf_evlist *evlist, return 0; } -static int process_event(struct perf_evlist *evlist, union perf_event *event, +static int process_event(struct evlist *evlist, union perf_event *event, struct switch_tracking *switch_tracking) { if (event->header.type == PERF_RECORD_SAMPLE) @@ -203,7 +208,7 @@ struct event_node { u64 event_time; }; -static int add_event(struct perf_evlist *evlist, struct list_head *events, +static int add_event(struct evlist *evlist, struct list_head *events, union perf_event *event) { struct perf_sample sample; @@ -252,7 +257,7 @@ static int compar(const void *a, const void *b) return cmp; } -static int process_events(struct perf_evlist *evlist, +static int process_events(struct evlist *evlist, struct switch_tracking *switch_tracking) { union perf_event *event; @@ -327,11 +332,11 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ .uses_mmap = true, }, }; - struct thread_map *threads = NULL; - struct cpu_map *cpus = NULL; - struct perf_evlist *evlist = NULL; - struct perf_evsel *evsel, *cpu_clocks_evsel, *cycles_evsel; - struct perf_evsel *switch_evsel, *tracking_evsel; + struct perf_thread_map *threads = NULL; + struct perf_cpu_map *cpus = NULL; + struct evlist *evlist = NULL; + struct evsel *evsel, *cpu_clocks_evsel, *cycles_evsel; + struct evsel *switch_evsel, *tracking_evsel; const char *comm; int err = -1; @@ -341,19 +346,19 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) { - pr_debug("cpu_map__new failed!\n"); + pr_debug("perf_cpu_map__new failed!\n"); goto out_err; } - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) { - pr_debug("perf_evlist__new failed!\n"); + pr_debug("evlist__new failed!\n"); goto out_err; } - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); /* First event */ err = parse_events(evlist, "cpu-clock:u", NULL); @@ -420,8 +425,8 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ perf_evlist__set_tracking_event(evlist, tracking_evsel); - tracking_evsel->attr.freq = 0; - tracking_evsel->attr.sample_period = 1; + tracking_evsel->core.attr.freq = 0; + tracking_evsel->core.attr.sample_period = 1; perf_evsel__set_sample_bit(tracking_evsel, TIME); @@ -435,7 +440,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ } /* Check tracking event is tracking */ - if (!tracking_evsel->attr.mmap || !tracking_evsel->attr.comm) { + if (!tracking_evsel->core.attr.mmap || !tracking_evsel->core.attr.comm) { pr_debug("Tracking event not tracking\n"); goto out_err; } @@ -443,14 +448,14 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ /* Check non-tracking events are not tracking */ evlist__for_each_entry(evlist, evsel) { if (evsel != tracking_evsel) { - if (evsel->attr.mmap || evsel->attr.comm) { + if (evsel->core.attr.mmap || evsel->core.attr.comm) { pr_debug("Non-tracking event is tracking\n"); goto out_err; } } } - if (perf_evlist__open(evlist) < 0) { + if (evlist__open(evlist) < 0) { pr_debug("Not supported\n"); err = 0; goto out; @@ -462,9 +467,9 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - perf_evlist__enable(evlist); + evlist__enable(evlist); - err = perf_evsel__disable(cpu_clocks_evsel); + err = evsel__disable(cpu_clocks_evsel); if (err) { pr_debug("perf_evlist__disable_event failed!\n"); goto out_err; @@ -483,7 +488,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - err = perf_evsel__disable(cycles_evsel); + err = evsel__disable(cycles_evsel); if (err) { pr_debug("perf_evlist__disable_event failed!\n"); goto out_err; @@ -509,7 +514,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - err = perf_evsel__enable(cycles_evsel); + err = evsel__enable(cycles_evsel); if (err) { pr_debug("perf_evlist__disable_event failed!\n"); goto out_err; @@ -528,7 +533,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - perf_evlist__disable(evlist); + evlist__disable(evlist); switch_tracking.switch_evsel = switch_evsel; switch_tracking.cycles_evsel = cycles_evsel; @@ -566,11 +571,11 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ } out: if (evlist) { - perf_evlist__disable(evlist); - perf_evlist__delete(evlist); + evlist__disable(evlist); + evlist__delete(evlist); } else { - cpu_map__put(cpus); - thread_map__put(threads); + perf_cpu_map__put(cpus); + perf_thread_map__put(threads); } return err; diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index e92fa6029ac7..f610e8c0a083 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 +#include "debug.h" #include "evlist.h" #include "evsel.h" +#include "target.h" #include "thread_map.h" #include "cpumap.h" #include "tests.h" #include <errno.h> #include <signal.h> +#include <linux/string.h> +#include <perf/evlist.h> static int exited; static int nr_exit; @@ -37,16 +41,16 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused { int err = -1; union perf_event *event; - struct perf_evsel *evsel; - struct perf_evlist *evlist; + struct evsel *evsel; + struct evlist *evlist; struct target target = { .uid = UINT_MAX, .uses_mmap = true, }; const char *argv[] = { "true", NULL }; char sbuf[STRERR_BUFSIZE]; - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; struct perf_mmap *md; signal(SIGCHLD, sig_handler); @@ -63,7 +67,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused * perf_evlist__prepare_workload we'll fill in the only thread * we're monitoring, the one forked there. */ - cpus = cpu_map__dummy_new(); + cpus = perf_cpu_map__dummy_new(); threads = thread_map__new_by_tid(-1); if (!cpus || !threads) { err = -ENOMEM; @@ -71,7 +75,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused goto out_free_maps; } - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); cpus = NULL; threads = NULL; @@ -84,18 +88,18 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused } evsel = perf_evlist__first(evlist); - evsel->attr.task = 1; + evsel->core.attr.task = 1; #ifdef __s390x__ - evsel->attr.sample_freq = 1000000; + evsel->core.attr.sample_freq = 1000000; #else - evsel->attr.sample_freq = 1; + evsel->core.attr.sample_freq = 1; #endif - evsel->attr.inherit = 0; - evsel->attr.watermark = 0; - evsel->attr.wakeup_events = 1; - evsel->attr.exclude_kernel = 1; + evsel->core.attr.inherit = 0; + evsel->core.attr.watermark = 0; + evsel->core.attr.wakeup_events = 1; + evsel->core.attr.exclude_kernel = 1; - err = perf_evlist__open(evlist); + err = evlist__open(evlist); if (err < 0) { pr_debug("Couldn't open the evlist: %s\n", str_error_r(-err, sbuf, sizeof(sbuf))); @@ -135,9 +139,9 @@ out_init: } out_free_maps: - cpu_map__put(cpus); - thread_map__put(threads); + perf_cpu_map__put(cpus); + perf_thread_map__put(threads); out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c index ccc17aced49e..39168c57943b 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c @@ -1,19 +1,26 @@ // SPDX-License-Identifier: GPL-2.0 #include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <unistd.h> #include <sys/prctl.h> #include "tests.h" #include "thread_map.h" #include "debug.h" +#include "event.h" #include <linux/zalloc.h> +#include <perf/event.h> + +struct perf_sample; +struct perf_tool; +struct machine; #define NAME (const char *) "perf" #define NAMEUL (unsigned long) NAME int test__thread_map(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct thread_map *map; + struct perf_thread_map *map; TEST_ASSERT_VAL("failed to set process name", !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0)); @@ -26,28 +33,28 @@ int test__thread_map(struct test *test __maybe_unused, int subtest __maybe_unuse TEST_ASSERT_VAL("wrong nr", map->nr == 1); TEST_ASSERT_VAL("wrong pid", - thread_map__pid(map, 0) == getpid()); + perf_thread_map__pid(map, 0) == getpid()); TEST_ASSERT_VAL("wrong comm", - thread_map__comm(map, 0) && - !strcmp(thread_map__comm(map, 0), NAME)); + perf_thread_map__comm(map, 0) && + !strcmp(perf_thread_map__comm(map, 0), NAME)); TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); - thread_map__put(map); + perf_thread_map__put(map); /* test dummy pid */ - map = thread_map__new_dummy(); + map = perf_thread_map__new_dummy(); TEST_ASSERT_VAL("failed to alloc map", map); thread_map__read_comms(map); TEST_ASSERT_VAL("wrong nr", map->nr == 1); - TEST_ASSERT_VAL("wrong pid", thread_map__pid(map, 0) == -1); + TEST_ASSERT_VAL("wrong pid", perf_thread_map__pid(map, 0) == -1); TEST_ASSERT_VAL("wrong comm", - thread_map__comm(map, 0) && - !strcmp(thread_map__comm(map, 0), "dummy")); + perf_thread_map__comm(map, 0) && + !strcmp(perf_thread_map__comm(map, 0), "dummy")); TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); - thread_map__put(map); + perf_thread_map__put(map); return 0; } @@ -56,8 +63,8 @@ static int process_event(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct thread_map_event *map = &event->thread_map; - struct thread_map *threads; + struct perf_record_thread_map *map = &event->thread_map; + struct perf_thread_map *threads; TEST_ASSERT_VAL("wrong nr", map->nr == 1); TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid()); @@ -68,19 +75,19 @@ static int process_event(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", threads->nr == 1); TEST_ASSERT_VAL("wrong pid", - thread_map__pid(threads, 0) == getpid()); + perf_thread_map__pid(threads, 0) == getpid()); TEST_ASSERT_VAL("wrong comm", - thread_map__comm(threads, 0) && - !strcmp(thread_map__comm(threads, 0), NAME)); + perf_thread_map__comm(threads, 0) && + !strcmp(perf_thread_map__comm(threads, 0), NAME)); TEST_ASSERT_VAL("wrong refcnt", refcount_read(&threads->refcnt) == 1); - thread_map__put(threads); + perf_thread_map__put(threads); return 0; } int test__thread_map_synthesize(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct thread_map *threads; + struct perf_thread_map *threads; TEST_ASSERT_VAL("failed to set process name", !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0)); @@ -99,7 +106,7 @@ int test__thread_map_synthesize(struct test *test __maybe_unused, int subtest __ int test__thread_map_remove(struct test *test __maybe_unused, int subtest __maybe_unused) { - struct thread_map *threads; + struct perf_thread_map *threads; char *str; int i; diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c index b1d1bbafe7ae..cbac71716dec 100644 --- a/tools/perf/tests/thread-mg-share.c +++ b/tools/perf/tests/thread-mg-share.c @@ -2,7 +2,6 @@ #include "tests.h" #include "machine.h" #include "thread.h" -#include "map.h" #include "debug.h" int test__thread_mg_share(struct test *test __maybe_unused, int subtest __maybe_unused) diff --git a/tools/perf/tests/time-utils-test.c b/tools/perf/tests/time-utils-test.c index 4f53006233a1..fe57ca3b6e54 100644 --- a/tools/perf/tests/time-utils-test.c +++ b/tools/perf/tests/time-utils-test.c @@ -69,7 +69,7 @@ struct test_data { static bool test__perf_time__parse_for_ranges(struct test_data *d) { - struct perf_evlist evlist = { + struct evlist evlist = { .first_sample_time = d->first, .last_sample_time = d->last, }; diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 9497d02f69e6..a4f9f5182b47 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -2,6 +2,7 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <perf/cpumap.h> #include "tests.h" #include "util.h" #include "session.h" @@ -57,7 +58,7 @@ static int session_write_header(char *path) return 0; } -static int check_cpu_topology(char *path, struct cpu_map *map) +static int check_cpu_topology(char *path, struct perf_cpu_map *map) { struct perf_session *session; struct perf_data data = { @@ -116,7 +117,7 @@ static int check_cpu_topology(char *path, struct cpu_map *map) int test__session_topology(struct test *test __maybe_unused, int subtest __maybe_unused) { char path[PATH_MAX]; - struct cpu_map *map; + struct perf_cpu_map *map; int ret = TEST_FAIL; TEST_ASSERT_VAL("can't get templ file", !get_temp(path)); @@ -126,14 +127,14 @@ int test__session_topology(struct test *test __maybe_unused, int subtest __maybe if (session_write_header(path)) goto free_path; - map = cpu_map__new(NULL); + map = perf_cpu_map__new(NULL); if (map == NULL) { pr_debug("failed to get system cpumap\n"); goto free_path; } ret = check_cpu_topology(path, map); - cpu_map__put(map); + perf_cpu_map__put(map); free_path: unlink(path); diff --git a/tools/perf/tests/unit_number__scnprintf.c b/tools/perf/tests/unit_number__scnprintf.c index 2bb8cb0039c1..3721757435da 100644 --- a/tools/perf/tests/unit_number__scnprintf.c +++ b/tools/perf/tests/unit_number__scnprintf.c @@ -2,6 +2,7 @@ #include <inttypes.h> #include <linux/compiler.h> #include <linux/types.h> +#include <string.h> #include "tests.h" #include "units.h" #include "debug.h" diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 5e8834fc7dec..01f434c067c6 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -4,6 +4,7 @@ #include <inttypes.h> #include <string.h> #include <stdlib.h> +#include "dso.h" #include "map.h" #include "symbol.h" #include "util.h" diff --git a/tools/perf/tests/wp.c b/tools/perf/tests/wp.c index f89e6806557b..d262d6639829 100644 --- a/tools/perf/tests/wp.c +++ b/tools/perf/tests/wp.c @@ -1,10 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include <stdlib.h> +#include <string.h> +#include <unistd.h> #include <sys/ioctl.h> #include <linux/hw_breakpoint.h> +#include <linux/kernel.h> #include "tests.h" #include "debug.h" +#include "event.h" #include "cloexec.h" +#include "../perf-sys.h" #define WP_TEST_ASSERT_VAL(fd, text, val) \ do { \ diff --git a/tools/perf/trace/beauty/ioctl.c b/tools/perf/trace/beauty/ioctl.c index 52242fa4072b..e19eb6ea361d 100644 --- a/tools/perf/trace/beauty/ioctl.c +++ b/tools/perf/trace/beauty/ioctl.c @@ -21,7 +21,7 @@ static size_t ioctl__scnprintf_tty_cmd(int nr, int dir, char *bf, size_t size) { static const char *ioctl_tty_cmd[] = { - "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW", + [_IOC_NR(TCGETS)] = "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW", "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL", "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI", "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC", "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index d227d74b28f8..f93d40b1c203 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -2,7 +2,6 @@ #include "../util/util.h" #include "../util/string2.h" #include "../util/config.h" -#include "../perf.h" #include "libslang.h" #include "ui.h" #include "util.h" @@ -347,6 +346,8 @@ static int __ui_browser__refresh(struct ui_browser *browser) SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x, browser->rows - row, width, ' '); + if (browser->nr_entries == 0 && browser->no_samples_msg) + __ui__info_window(NULL, browser->no_samples_msg, NULL); return 0; } diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index dc1444136658..3678eb88f119 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -23,6 +23,7 @@ struct ui_browser { void *priv; const char *title; char *helpline; + const char *no_samples_msg; void (*refresh_dimensions)(struct ui_browser *browser); unsigned int (*refresh)(struct ui_browser *browser); void (*write)(struct ui_browser *browser, void *entry, int row); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e67880bf1efe..ac74ed2c23a0 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -4,6 +4,8 @@ #include "../ui.h" #include "../util.h" #include "../../util/annotate.h" +#include "../../util/debug.h" +#include "../../util/dso.h" #include "../../util/hist.h" #include "../../util/sort.h" #include "../../util/map.h" @@ -299,7 +301,7 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser, } static void annotate_browser__calc_percent(struct annotate_browser *browser, - struct perf_evsel *evsel) + struct evsel *evsel) { struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; @@ -406,7 +408,7 @@ static int sym_title(struct symbol *sym, struct map *map, char *title, * to the calling function. */ static bool annotate_browser__callq(struct annotate_browser *browser, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt) { struct map_symbol *ms = browser->b.priv; @@ -422,7 +424,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, notes = symbol__annotation(dl->ops.target.sym); pthread_mutex_lock(¬es->lock); - if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) { + if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) { pthread_mutex_unlock(¬es->lock); ui__warning("Not enough memory for annotating '%s' symbol!\n", dl->ops.target.sym->name); @@ -455,7 +457,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows } static bool annotate_browser__jump(struct annotate_browser *browser, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt) { struct disasm_line *dl = disasm_line(browser->selection); @@ -656,7 +658,7 @@ switch_percent_type(struct annotation_options *opts, bool base) } static int annotate_browser__run(struct annotate_browser *browser, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt) { struct rb_node *nd = NULL; @@ -869,14 +871,14 @@ out: return key; } -int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *opts) { return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts); } -int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, +int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *opts) { @@ -888,7 +890,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, } int symbol__tui_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *opts) { diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c index 5aeb663dd184..0f59a7001479 100644 --- a/tools/perf/ui/browsers/header.c +++ b/tools/perf/ui/browsers/header.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "util/cache.h" #include "util/debug.h" #include "ui/browser.h" #include "ui/keysyms.h" diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a94eb0755e8b..589168ca9f62 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -11,17 +11,23 @@ #include <linux/time64.h> #include <linux/zalloc.h> +#include "../../util/debug.h" +#include "../../util/dso.h" #include "../../util/callchain.h" #include "../../util/evsel.h" #include "../../util/evlist.h" +#include "../../util/header.h" #include "../../util/hist.h" #include "../../util/map.h" #include "../../util/symbol.h" +#include "../../util/map_symbol.h" +#include "../../util/branch.h" #include "../../util/pstack.h" #include "../../util/sort.h" #include "../../util/top.h" #include "../../util/thread.h" #include "../../arch/common.h" +#include "../../perf.h" #include "../browsers/hists.h" #include "../helpline.h" @@ -2187,7 +2193,7 @@ struct hist_browser *hist_browser__new(struct hists *hists) } static struct hist_browser * -perf_evsel_browser__new(struct perf_evsel *evsel, +perf_evsel_browser__new(struct evsel *evsel, struct hist_browser_timer *hbt, struct perf_env *env, struct annotation_options *annotation_opts) @@ -2352,7 +2358,7 @@ struct popup_action { struct thread *thread; struct map_symbol ms; int socket; - struct perf_evsel *evsel; + struct evsel *evsel; enum rstype rstype; int (*fn)(struct hist_browser *browser, struct popup_action *act); @@ -2361,7 +2367,7 @@ struct popup_action { static int do_annotate(struct hist_browser *browser, struct popup_action *act) { - struct perf_evsel *evsel; + struct evsel *evsel; struct annotation *notes; struct hist_entry *he; int err; @@ -2596,7 +2602,7 @@ static int add_script_opt_2(struct hist_browser *browser __maybe_unused, struct popup_action *act, char **optstr, struct thread *thread, struct symbol *sym, - struct perf_evsel *evsel, const char *tstr) + struct evsel *evsel, const char *tstr) { if (thread) { @@ -2623,7 +2629,7 @@ static int add_script_opt(struct hist_browser *browser, struct popup_action *act, char **optstr, struct thread *thread, struct symbol *sym, - struct perf_evsel *evsel) + struct evsel *evsel) { int n, j; struct hist_entry *he; @@ -2653,7 +2659,7 @@ static int add_res_sample_opt(struct hist_browser *browser __maybe_unused, struct popup_action *act, char **optstr, struct res_sample *res_sample, - struct perf_evsel *evsel, + struct evsel *evsel, enum rstype type) { if (!res_sample) @@ -2814,7 +2820,7 @@ next: } } -static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, +static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline, bool left_exits, struct hist_browser_timer *hbt, @@ -2894,6 +2900,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); + if (!is_report_browser(hbt)) + browser->b.no_samples_msg = "Collecting samples..."; + while (1) { struct thread *thread = NULL; struct map *map = NULL; @@ -3198,9 +3207,9 @@ out: return key; } -struct perf_evsel_menu { +struct evsel_menu { struct ui_browser b; - struct perf_evsel *selection; + struct evsel *selection; struct annotation_options *annotation_opts; bool lost_events, lost_events_warned; float min_pcnt; @@ -3210,9 +3219,9 @@ struct perf_evsel_menu { static void perf_evsel_menu__write(struct ui_browser *browser, void *entry, int row) { - struct perf_evsel_menu *menu = container_of(browser, - struct perf_evsel_menu, b); - struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); + struct evsel_menu *menu = container_of(browser, + struct evsel_menu, b); + struct evsel *evsel = list_entry(entry, struct evsel, core.node); struct hists *hists = evsel__hists(evsel); bool current_entry = ui_browser__is_current_entry(browser, row); unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; @@ -3225,7 +3234,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, HE_COLORSET_NORMAL); if (perf_evsel__is_group_event(evsel)) { - struct perf_evsel *pos; + struct evsel *pos; ev_name = perf_evsel__group_name(evsel); @@ -3257,13 +3266,13 @@ static void perf_evsel_menu__write(struct ui_browser *browser, menu->selection = evsel; } -static int perf_evsel_menu__run(struct perf_evsel_menu *menu, +static int perf_evsel_menu__run(struct evsel_menu *menu, int nr_events, const char *help, struct hist_browser_timer *hbt, bool warn_lost_event) { - struct perf_evlist *evlist = menu->b.priv; - struct perf_evsel *pos; + struct evlist *evlist = menu->b.priv; + struct evsel *pos; const char *title = "Available samples"; int delay_secs = hbt ? hbt->refresh : 0; int key; @@ -3309,13 +3318,13 @@ browse_hists: ui_browser__show_title(&menu->b, title); switch (key) { case K_TAB: - if (pos->node.next == &evlist->entries) + if (pos->core.node.next == &evlist->core.entries) pos = perf_evlist__first(evlist); else pos = perf_evsel__next(pos); goto browse_hists; case K_UNTAB: - if (pos->node.prev == &evlist->entries) + if (pos->core.node.prev == &evlist->core.entries) pos = perf_evlist__last(evlist); else pos = perf_evsel__prev(pos); @@ -3351,7 +3360,7 @@ out: static bool filter_group_entries(struct ui_browser *browser __maybe_unused, void *entry) { - struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); + struct evsel *evsel = list_entry(entry, struct evsel, core.node); if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) return true; @@ -3359,7 +3368,7 @@ static bool filter_group_entries(struct ui_browser *browser __maybe_unused, return false; } -static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, +static int __perf_evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help, struct hist_browser_timer *hbt, float min_pcnt, @@ -3367,10 +3376,10 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, bool warn_lost_event, struct annotation_options *annotation_opts) { - struct perf_evsel *pos; - struct perf_evsel_menu menu = { + struct evsel *pos; + struct evsel_menu menu = { .b = { - .entries = &evlist->entries, + .entries = &evlist->core.entries, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = perf_evsel_menu__write, @@ -3397,18 +3406,18 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, hbt, warn_lost_event); } -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, +int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, bool warn_lost_event, struct annotation_options *annotation_opts) { - int nr_entries = evlist->nr_entries; + int nr_entries = evlist->core.nr_entries; single_entry: if (nr_entries == 1) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); return perf_evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt, @@ -3417,7 +3426,7 @@ single_entry: } if (symbol_conf.event_group) { - struct perf_evsel *pos; + struct evsel *pos; nr_entries = 0; evlist__for_each_entry(evlist, pos) { diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 4c545b92e20d..893b065971f6 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -8,6 +8,7 @@ #include "../../util/util.h" #include "../../util/debug.h" #include "../../util/map.h" +#include "../../util/dso.h" #include "../../util/symbol.h" #include "../browser.h" #include "../helpline.h" diff --git a/tools/perf/ui/browsers/res_sample.c b/tools/perf/ui/browsers/res_sample.c index 8aa3547bb9ff..f16a38fea45e 100644 --- a/tools/perf/ui/browsers/res_sample.c +++ b/tools/perf/ui/browsers/res_sample.c @@ -6,6 +6,11 @@ #include "sort.h" #include "config.h" #include "time-utils.h" +#include "../util.h" +#include "../../util/util.h" +#include "../../perf.h" +#include <stdlib.h> +#include <string.h> #include <linux/time64.h> #include <linux/zalloc.h> @@ -24,7 +29,7 @@ void res_sample_init(void) } int res_sample_browse(struct res_sample *res_samples, int num_res, - struct perf_evsel *evsel, enum rstype rstype) + struct evsel *evsel, enum rstype rstype) { char **names; int i, n; @@ -66,7 +71,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res, timestamp__scnprintf_nsec(r->time, tsample, sizeof tsample); - attr_to_script(extra_format, &evsel->attr); + attr_to_script(extra_format, &evsel->core.attr); if (asprintf(&cmd, "%s script %s%s --time %s %s%s %s%s --ns %s %s %s %s %s | less +/%s", perf, diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index 4d565cc14076..586a21acc13d 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../../util/sort.h" +#include "../../builtin.h" +#include "../../perf.h" +#include "../../util/util.h" #include "../../util/hist.h" #include "../../util/debug.h" #include "../../util/symbol.h" #include "../browser.h" #include "../libslang.h" #include "config.h" +#include <linux/string.h> #include <linux/zalloc.h> +#include <stdlib.h> #define SCRIPT_NAMELEN 128 #define SCRIPT_MAX_NO 64 @@ -78,7 +82,7 @@ static int scripts_config(const char *var, const char *value, void *data) * Return -1 on failure. */ static int list_scripts(char *script_name, bool *custom, - struct perf_evsel *evsel) + struct evsel *evsel) { char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO]; int i, num, choice; @@ -100,7 +104,7 @@ static int list_scripts(char *script_name, bool *custom, return -1; if (evsel) - attr_to_script(scriptc.extra_format, &evsel->attr); + attr_to_script(scriptc.extra_format, &evsel->core.attr); add_script_option("Show individual samples", "", &scriptc); add_script_option("Show individual samples with assembler", "-F +insn --xed", &scriptc); @@ -131,8 +135,10 @@ static int list_scripts(char *script_name, bool *custom, int key = ui_browser__input_window("perf script command", "Enter perf script command line (without perf script prefix)", script_args, "", 0); - if (key != K_ENTER) - return -1; + if (key != K_ENTER) { + ret = -1; + goto out; + } sprintf(script_name, "%s script %s", perf, script_args); } else if (choice < num + max_std) { strcpy(script_name, paths[choice]); @@ -162,7 +168,7 @@ void run_script(char *cmd) SLsmg_refresh(); } -int script_browse(const char *script_opt, struct perf_evsel *evsel) +int script_browse(const char *script_opt, struct evsel *evsel) { char *cmd, script_name[SCRIPT_FULLPATH_LEN]; bool custom = false; diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 3af87c18a914..8e744af24f7c 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -5,6 +5,7 @@ #include "util/annotate.h" #include "util/evsel.h" #include "util/map.h" +#include "util/dso.h" #include "util/symbol.h" #include "ui/helpline.h" #include <inttypes.h> @@ -91,7 +92,7 @@ static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) } static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, - struct map *map, struct perf_evsel *evsel, + struct map *map, struct evsel *evsel, struct hist_browser_timer *hbt __maybe_unused) { struct disasm_line *pos, *n; @@ -129,7 +130,7 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, gtk_list_store_append(store, &iter); if (perf_evsel__is_group_event(evsel)) { - for (i = 0; i < evsel->nr_members; i++) { + for (i = 0; i < evsel->core.nr_members; i++) { ret += perf_gtk__get_percent(s + ret, sizeof(s) - ret, sym, pos, @@ -160,7 +161,7 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, } static int symbol__gtk_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt) { GtkWidget *window; @@ -238,7 +239,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, } int hist_entry__gtk_annotate(struct hist_entry *he, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt) { return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 4820e25ac68d..8f3e43d148a8 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../evlist.h" -#include "../cache.h" #include "../evsel.h" #include "../sort.h" #include "../hist.h" diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 9846ea5c831b..a9563932fa04 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h @@ -52,16 +52,16 @@ static inline GtkWidget *perf_gtk__setup_info_bar(void) } #endif -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct hist_entry; struct hist_browser_timer; -int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, +int perf_evlist__gtk_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt); int hist_entry__gtk_annotate(struct hist_entry *he, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt); void perf_gtk__show_annotations(void); diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c index fbf1ea9ce9a2..e166da9ec767 100644 --- a/tools/perf/ui/gtk/helpline.c +++ b/tools/perf/ui/gtk/helpline.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <stdio.h> #include <string.h> +#include <linux/kernel.h> #include "gtk.h" #include "../ui.h" diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 3955ed1d1bd9..6c2efc10bf5c 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "../evlist.h" -#include "../cache.h" #include "../callchain.h" #include "../evsel.h" #include "../sort.h" @@ -590,12 +589,12 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists, gtk_container_add(GTK_CONTAINER(window), view); } -int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, +int perf_evlist__gtk_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt __maybe_unused, float min_pcnt) { - struct perf_evsel *pos; + struct evsel *pos; GtkWidget *vbox; GtkWidget *notebook; GtkWidget *info_bar; @@ -645,7 +644,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, if (!perf_evsel__is_group_leader(pos)) continue; - if (pos->nr_members > 1) { + if (pos->core.nr_members > 1) { perf_evsel__group_desc(pos, buf, size); evname = buf; } diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c index 506e73b3834c..1a2616b97b5c 100644 --- a/tools/perf/ui/gtk/setup.c +++ b/tools/perf/ui/gtk/setup.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "gtk.h" -#include "../../util/cache.h" #include "../../util/debug.h" extern struct perf_error_ops perf_gtk_eops; diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index c28bdb7517ac..c2c558958b9c 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -3,6 +3,7 @@ #include "../../util/debug.h" #include "gtk.h" +#include <stdlib.h> #include <string.h> #include <linux/zalloc.h> diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index b3c421429ed4..54bcd08df87e 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c @@ -3,10 +3,10 @@ #include <stdlib.h> #include <string.h> -#include "../debug.h" +#include "../util/debug.h" #include "helpline.h" #include "ui.h" -#include "../util.h" +#include "../util/util.h" char ui_helpline__current[512]; diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index 8f775a053ca3..2165a098dee8 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h @@ -5,8 +5,6 @@ #include <stdio.h> #include <stdarg.h> -#include "../util/cache.h" - struct ui_helpline { void (*pop)(void); void (*push)(const char *msg); diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 412d6f1626e3..3e533de7d852 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -1,14 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 #include <inttypes.h> #include <math.h> +#include <stdlib.h> +#include <string.h> #include <linux/compiler.h> #include "../util/callchain.h" +#include "../util/debug.h" #include "../util/hist.h" #include "../util/util.h" #include "../util/sort.h" #include "../util/evsel.h" #include "../util/evlist.h" +#include "../perf.h" /* hist period print (hpp) functions */ @@ -25,7 +29,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, { int ret; struct hists *hists = he->hists; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); char *buf = hpp->buf; size_t size = hpp->size; @@ -43,7 +47,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, if (perf_evsel__is_group_event(evsel)) { int prev_idx, idx_delta; struct hist_entry *pair; - int nr_members = evsel->nr_members; + int nr_members = evsel->core.nr_members; prev_idx = perf_evsel__group_idx(evsel); @@ -153,7 +157,7 @@ static int __hpp__sort(struct hist_entry *a, struct hist_entry *b, { s64 ret; int i, nr_members; - struct perf_evsel *evsel; + struct evsel *evsel; struct hist_entry *pair; u64 *fields_a, *fields_b; @@ -165,7 +169,7 @@ static int __hpp__sort(struct hist_entry *a, struct hist_entry *b, if (!perf_evsel__is_group_event(evsel)) return ret; - nr_members = evsel->nr_members; + nr_members = evsel->core.nr_members; fields_a = calloc(nr_members, sizeof(*fields_a)); fields_b = calloc(nr_members, sizeof(*fields_b)); @@ -223,10 +227,10 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, struct hists *hists) { int len = fmt->user_len ?: fmt->len; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); if (symbol_conf.event_group) - len = max(len, evsel->nr_members * fmt->len); + len = max(len, evsel->core.nr_members * fmt->len); if (len < (int)strlen(fmt->name)) len = strlen(fmt->name); @@ -795,9 +799,9 @@ static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt) } int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, - struct perf_evlist *evlist) + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_hpp_fmt *fmt; struct hists *hists; int ret; diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c index 8cd3b64c6893..99d60223c74b 100644 --- a/tools/perf/ui/progress.c +++ b/tools/perf/ui/progress.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> -#include "../util/cache.h" #include "progress.h" static void null_progress__update(struct ui_progress *p __maybe_unused) diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index 44fe824e96cd..c7a86b4be9f5 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -2,10 +2,11 @@ #include <pthread.h> #include <dlfcn.h> -#include "../util/cache.h" +#include <subcmd/pager.h> #include "../util/debug.h" #include "../util/hist.h" #include "../util/util.h" +#include "ui.h" pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; void *perf_gtk_handle; @@ -89,9 +90,9 @@ void setup_browser(bool fallback_to_pager) printf("GTK browser requested but could not find %s\n", PERF_GTK_DSO); sleep(1); + use_browser = 1; /* fall through */ case 1: - use_browser = 1; if (ui__init() == 0) break; /* fall through */ diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index ee7ea6deed21..832ca6cfbe30 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include <stdio.h> +#include <stdlib.h> #include <linux/string.h> #include "../../util/callchain.h" +#include "../../util/debug.h" #include "../../util/hist.h" #include "../../util/map.h" #include "../../util/map_groups.h" diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 93d6b7240285..5f188f678c55 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c @@ -3,6 +3,8 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> +#include <linux/kernel.h> +#include <linux/string.h> #include "../../util/debug.h" #include "../helpline.h" diff --git a/tools/perf/ui/tui/progress.c b/tools/perf/ui/tui/progress.c index 5a24dd3ce4db..3d74af5a7ece 100644 --- a/tools/perf/ui/tui/progress.c +++ b/tools/perf/ui/tui/progress.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> -#include "../../util/cache.h" #include "../progress.h" #include "../libslang.h" #include "../ui.h" diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index 3ad0d3363ac6..56651a4f5aa0 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <signal.h> #include <stdbool.h> @@ -8,9 +7,9 @@ #include <execinfo.h> #endif -#include "../../util/cache.h" #include "../../util/debug.h" #include "../../util/util.h" +#include "../../perf.h" #include "../browser.h" #include "../helpline.h" #include "../ui.h" diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c index fe5e571816fc..087d9ab054c8 100644 --- a/tools/perf/ui/tui/util.c +++ b/tools/perf/ui/tui/util.c @@ -5,7 +5,6 @@ #include <stdlib.h> #include <sys/ttydefaults.h> -#include "../../util/cache.h" #include "../../util/debug.h" #include "../browser.h" #include "../keysyms.h" @@ -162,8 +161,7 @@ next_key: return key; } -int ui__question_window(const char *title, const char *text, - const char *exit_msg, int delay_secs) +void __ui__info_window(const char *title, const char *text, const char *exit_msg) { int x, y; int max_len = 0, nr_lines = 0; @@ -185,10 +183,10 @@ int ui__question_window(const char *title, const char *text, t = sep + 1; } - pthread_mutex_lock(&ui__lock); - max_len += 2; - nr_lines += 4; + nr_lines += 2; + if (exit_msg) + nr_lines += 2; y = SLtt_Screen_Rows / 2 - nr_lines / 2, x = SLtt_Screen_Cols / 2 - max_len / 2; @@ -199,18 +197,34 @@ int ui__question_window(const char *title, const char *text, SLsmg_write_string((char *)title); } SLsmg_gotorc(++y, x); - nr_lines -= 2; + if (exit_msg) + nr_lines -= 2; max_len -= 2; SLsmg_write_wrapped_string((unsigned char *)text, y, x, nr_lines, max_len, 1); - SLsmg_gotorc(y + nr_lines - 2, x); - SLsmg_write_nstring((char *)" ", max_len); - SLsmg_gotorc(y + nr_lines - 1, x); - SLsmg_write_nstring((char *)exit_msg, max_len); - SLsmg_refresh(); + if (exit_msg) { + SLsmg_gotorc(y + nr_lines - 2, x); + SLsmg_write_nstring((char *)" ", max_len); + SLsmg_gotorc(y + nr_lines - 1, x); + SLsmg_write_nstring((char *)exit_msg, max_len); + } +} +void ui__info_window(const char *title, const char *text) +{ + pthread_mutex_lock(&ui__lock); + __ui__info_window(title, text, NULL); + SLsmg_refresh(); pthread_mutex_unlock(&ui__lock); +} +int ui__question_window(const char *title, const char *text, + const char *exit_msg, int delay_secs) +{ + pthread_mutex_lock(&ui__lock); + __ui__info_window(title, text, exit_msg); + SLsmg_refresh(); + pthread_mutex_unlock(&ui__lock); return ui__getch(delay_secs); } diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 63bf06e80ab9..689b27c34246 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "util.h" -#include "../debug.h" - +#include "../util/debug.h" +#include <stdio.h> /* * Default error logging functions diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h index 5e44223b56fa..40891942f465 100644 --- a/tools/perf/ui/util.h +++ b/tools/perf/ui/util.h @@ -8,6 +8,8 @@ int ui__getch(int delay_secs); int ui__popup_menu(int argc, char * const argv[]); int ui__help_window(const char *text); int ui__dialog_yesno(const char *msg); +void __ui__info_window(const char *title, const char *text, const char *exit_msg); +void ui__info_window(const char *title, const char *text); int ui__question_window(const char *title, const char *text, const char *exit_msg, int delay_secs); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 14f812bb07a7..0b4d8e0d474c 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,6 +1,7 @@ perf-y += annotate.o perf-y += block-range.o perf-y += build-id.o +perf-y += cacheline.o perf-y += config.o perf-y += ctype.o perf-y += db-export.o @@ -9,6 +10,7 @@ perf-y += event.o perf-y += evlist.o perf-y += evsel.o perf-y += evsel_fprintf.o +perf-y += evswitch.o perf-y += find_bit.o perf-y += get_current_dir_name.o perf-y += kallsyms.o @@ -26,7 +28,6 @@ perf-y += rbtree.o perf-y += libstring.o perf-y += bitmap.o perf-y += hweight.o -perf-y += zalloc.o perf-y += smt.o perf-y += strbuf.o perf-y += string.o @@ -35,6 +36,7 @@ perf-y += strfilter.o perf-y += top.o perf-y += usage.o perf-y += dso.o +perf-y += dsos.o perf-y += symbol.o perf-y += symbol_fprintf.o perf-y += color.o @@ -70,7 +72,6 @@ perf-y += svghelper.o perf-y += sort.o perf-y += hist.o perf-y += util.o -perf-y += xyarray.o perf-y += cpumap.o perf-y += cputopo.o perf-y += cgroup.o @@ -150,6 +151,8 @@ perf-$(CONFIG_ZLIB) += zlib.o perf-$(CONFIG_LZMA) += lzma.o perf-$(CONFIG_ZSTD) += zstd.o +perf-$(CONFIG_LIBCAP) += cap.o + perf-y += demangle-java.o perf-y += demangle-rust.o @@ -243,7 +246,3 @@ $(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE $(OUTPUT)util/vsprintf.o: ../lib/vsprintf.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) - -$(OUTPUT)util/zalloc.o: ../lib/zalloc.c FORCE - $(call rule_mkdir) - $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 163536720149..1748f528b6e9 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -9,6 +9,7 @@ #include <errno.h> #include <inttypes.h> #include <libgen.h> +#include <stdlib.h> #include <bpf/bpf.h> #include <bpf/btf.h> #include <bpf/libbpf.h> @@ -19,9 +20,12 @@ #include "build-id.h" #include "color.h" #include "config.h" -#include "cache.h" +#include "dso.h" +#include "env.h" #include "map.h" +#include "map_groups.h" #include "symbol.h" +#include "srcline.h" #include "units.h" #include "debug.h" #include "annotate.h" @@ -37,6 +41,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <bpf/libbpf.h> +#include <subcmd/parse-options.h> /* FIXME: For the HE_COLORSET */ #include "ui/browser.h" @@ -929,14 +934,14 @@ alloc_histograms: } static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, u64 addr, + struct evsel *evsel, u64 addr, struct perf_sample *sample) { struct annotated_source *src; if (sym == NULL) return 0; - src = symbol__hists(sym, evsel->evlist->nr_entries); + src = symbol__hists(sym, evsel->evlist->core.nr_entries); return (src) ? __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample) : 0; } @@ -1080,13 +1085,13 @@ void annotation__compute_ipc(struct annotation *notes, size_t size) } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample); } int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - struct perf_evsel *evsel, u64 ip) + struct evsel *evsel, u64 ip) { return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample); } @@ -1134,7 +1139,7 @@ struct annotate_args { size_t privsize; struct arch *arch; struct map_symbol ms; - struct perf_evsel *evsel; + struct evsel *evsel; struct annotation_options *options; s64 offset; char *line; @@ -1165,12 +1170,12 @@ static struct annotation_line * annotation_line__new(struct annotate_args *args, size_t privsize) { struct annotation_line *al; - struct perf_evsel *evsel = args->evsel; + struct evsel *evsel = args->evsel; size_t size = privsize + sizeof(*al); int nr = 1; if (perf_evsel__is_group_event(evsel)) - nr = evsel->nr_members; + nr = evsel->core.nr_members; size += sizeof(al->data[0]) * nr; @@ -1359,7 +1364,7 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi static int annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, - struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, + struct evsel *evsel, u64 len, int min_pcnt, int printed, int max_lines, struct annotation_line *queue, int addr_fmt_width, int percent_type) { @@ -1448,7 +1453,7 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start return -1; if (perf_evsel__is_group_event(evsel)) - width *= evsel->nr_members; + width *= evsel->core.nr_members; if (!*al->line) printf(" %*s:\n", width, " "); @@ -2011,10 +2016,10 @@ static void calc_percent(struct sym_hist *sym_hist, } static void annotation__calc_percent(struct annotation *notes, - struct perf_evsel *leader, s64 len) + struct evsel *leader, s64 len) { struct annotation_line *al, *next; - struct perf_evsel *evsel; + struct evsel *evsel; list_for_each_entry(al, ¬es->src->source, node) { s64 end; @@ -2041,7 +2046,7 @@ static void annotation__calc_percent(struct annotation *notes, } } -void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) +void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) { struct annotation *notes = symbol__annotation(sym); @@ -2049,7 +2054,7 @@ void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) } int symbol__annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, size_t privsize, + struct evsel *evsel, size_t privsize, struct annotation_options *options, struct arch **parch) { @@ -2214,7 +2219,7 @@ static void print_summary(struct rb_root *root, const char *filename) } } -static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) +static void symbol__annotate_hits(struct symbol *sym, struct evsel *evsel) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evsel->idx); @@ -2241,7 +2246,7 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) } int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *opts) { struct dso *dso = map->dso; @@ -2272,7 +2277,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, len = symbol__size(sym); if (perf_evsel__is_group_event(evsel)) { - width *= evsel->nr_members; + width *= evsel->core.nr_members; perf_evsel__group_desc(evsel, buf, sizeof(buf)); evsel_name = buf; } @@ -2405,7 +2410,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, return 0; } -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts) { const char *ev_name = perf_evsel__name(evsel); @@ -2657,7 +2662,7 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, } int symbol__tty_annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *opts) { struct dso *dso = map->dso; @@ -2685,7 +2690,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, } int symbol__tty_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *opts) { struct dso *dso = map->dso; @@ -2956,7 +2961,7 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes wops->write_graph); } -int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, +int symbol__annotate2(struct symbol *sym, struct map *map, struct evsel *evsel, struct annotation_options *options, struct arch **parch) { struct annotation *notes = symbol__annotation(sym); @@ -2968,7 +2973,7 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev return -1; if (perf_evsel__is_group_event(evsel)) - nr_pcnt = evsel->nr_members; + nr_pcnt = evsel->core.nr_members; err = symbol__annotate(sym, map, evsel, 0, options, parch); if (err) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 5bc0cf655d37..d94be9140e31 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -20,7 +20,7 @@ struct map_symbol; struct addr_map_symbol; struct option; struct perf_sample; -struct perf_evsel; +struct evsel; struct symbol; struct ins { @@ -216,12 +216,12 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes int __annotation__scnprintf_samples_period(struct annotation *notes, char *bf, size_t size, - struct perf_evsel *evsel, + struct evsel *evsel, bool show_freq); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name); size_t disasm__fprintf(struct list_head *head, FILE *fp); -void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); +void symbol__calc_percent(struct symbol *sym, struct evsel *evsel); struct sym_hist { u64 nr_samples; @@ -245,7 +245,7 @@ struct cyc_hist { /** struct annotated_source - symbols with hits have this attached as in sannotation * * @histograms: Array of addr hit histograms per event being monitored - * nr_histograms: This may not be the same as evsel->evlist->nr_entries if + * nr_histograms: This may not be the same as evsel->evlist->core.nr_entries if * we have more than a group in a evlist, where we will want * to see each group separately, that is why symbol__annotate2() * sets src->nr_histograms to evsel->nr_members. @@ -335,24 +335,24 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - struct perf_evsel *evsel); + struct evsel *evsel); int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, struct addr_map_symbol *start, unsigned cycles); int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - struct perf_evsel *evsel, u64 addr); + struct evsel *evsel, u64 addr); struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, size_t privsize, + struct evsel *evsel, size_t privsize, struct annotation_options *options, struct arch **parch); int symbol__annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *options, struct arch **parch); @@ -378,32 +378,32 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int errnum, char *buf, size_t buflen); int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *options); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void annotated_source__purge(struct annotated_source *as); -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts); bool ui__has_annotation(void); int symbol__tty_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, struct annotation_options *opts); + struct evsel *evsel, struct annotation_options *opts); int symbol__tty_annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, struct annotation_options *opts); + struct evsel *evsel, struct annotation_options *opts); #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *opts); #else static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, struct map *map __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, struct annotation_options *opts __maybe_unused) { diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index a314e5b26e9d..8a7340f6a2a2 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -8,6 +8,8 @@ #include <errno.h> #include <byteswap.h> #include <inttypes.h> +#include <unistd.h> +#include <stdlib.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/bitops.h> @@ -17,10 +19,8 @@ #include "cpumap.h" #include "color.h" #include "evsel.h" -#include "evlist.h" #include "machine.h" #include "session.h" -#include "thread.h" #include "debug.h" #include "auxtrace.h" #include "arm-spe.h" @@ -181,7 +181,7 @@ static const char * const arm_spe_info_fmts[] = { [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n", }; -static void arm_spe_print_info(u64 *arr) +static void arm_spe_print_info(__u64 *arr) { if (!dump_trace) return; @@ -192,12 +192,12 @@ static void arm_spe_print_info(u64 *arr) int arm_spe_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE; struct arm_spe *spe; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index ec0af36697c4..6f25224a3def 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -26,7 +26,6 @@ #include <linux/list.h> #include <linux/zalloc.h> -#include "../perf.h" #include "evlist.h" #include "dso.h" #include "map.h" @@ -41,6 +40,7 @@ #include <linux/hash.h> #include "event.h" +#include "record.h" #include "session.h" #include "debug.h" #include <subcmd/parse-options.h> @@ -50,6 +50,7 @@ #include "intel-bts.h" #include "arm-spe.h" #include "s390-cpumsf.h" +#include "util.h" #include <linux/ctype.h> #include "symbol/kallsyms.h" @@ -124,20 +125,20 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, } void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, - struct perf_evlist *evlist, int idx, + struct evlist *evlist, int idx, bool per_cpu) { mp->idx = idx; if (per_cpu) { - mp->cpu = evlist->cpus->map[idx]; - if (evlist->threads) - mp->tid = thread_map__pid(evlist->threads, 0); + mp->cpu = evlist->core.cpus->map[idx]; + if (evlist->core.threads) + mp->tid = perf_thread_map__pid(evlist->core.threads, 0); else mp->tid = -1; } else { mp->cpu = -1; - mp->tid = thread_map__pid(evlist->threads, idx); + mp->tid = perf_thread_map__pid(evlist->core.threads, idx); } } @@ -385,7 +386,7 @@ static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, return err; if (event->header.type == PERF_RECORD_AUXTRACE) { - if (event->header.size < sizeof(struct auxtrace_event) || + if (event->header.size < sizeof(struct perf_record_auxtrace) || event->header.size != sz) { err = -EINVAL; goto out; @@ -503,7 +504,7 @@ void auxtrace_heap__pop(struct auxtrace_heap *heap) } size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, - struct perf_evlist *evlist) + struct evlist *evlist) { if (itr) return itr->info_priv_size(itr, evlist); @@ -518,7 +519,7 @@ static int auxtrace_not_supported(void) int auxtrace_record__info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size) { if (itr) @@ -539,9 +540,9 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr) return 0; } -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit) { - if (itr && itr->snapshot_finish) + if (!on_exit && itr && itr->snapshot_finish) return itr->snapshot_finish(itr); return 0; } @@ -556,7 +557,7 @@ int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, } int auxtrace_record__options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts) { if (itr) @@ -577,6 +578,16 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, if (!str) return 0; + /* PMU-agnostic options */ + switch (*str) { + case 'e': + opts->auxtrace_snapshot_on_exit = true; + str++; + break; + default: + break; + } + if (itr) return itr->parse_snapshot_options(itr, opts, str); @@ -585,7 +596,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, } struct auxtrace_record *__weak -auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) +auxtrace_record__init(struct evlist *evlist __maybe_unused, int *err) { *err = 0; return NULL; @@ -848,13 +859,13 @@ void auxtrace_buffer__free(struct auxtrace_buffer *buffer) free(buffer); } -void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, +void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type, int code, int cpu, pid_t pid, pid_t tid, u64 ip, const char *msg, u64 timestamp) { size_t size; - memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event)); + memset(auxtrace_error, 0, sizeof(struct perf_record_auxtrace_error)); auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; auxtrace_error->type = type; @@ -883,12 +894,12 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, pr_debug2("Synthesizing auxtrace information\n"); priv_size = auxtrace_record__info_priv_size(itr, session->evlist); - ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); + ev = zalloc(sizeof(struct perf_record_auxtrace_info) + priv_size); if (!ev) return -ENOMEM; ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO; - ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) + + ev->auxtrace_info.header.size = sizeof(struct perf_record_auxtrace_info) + priv_size; err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info, priv_size); @@ -932,7 +943,7 @@ s64 perf_event__process_auxtrace(struct perf_session *session, s64 err; if (dump_trace) - fprintf(stdout, " size: %#"PRIx64" offset: %#"PRIx64" ref: %#"PRIx64" idx: %u tid: %d cpu: %d\n", + fprintf(stdout, " size: %#"PRI_lx64" offset: %#"PRI_lx64" ref: %#"PRI_lx64" idx: %u tid: %d cpu: %d\n", event->auxtrace.size, event->auxtrace.offset, event->auxtrace.reference, event->auxtrace.idx, event->auxtrace.tid, event->auxtrace.cpu); @@ -964,6 +975,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, synth_opts->transactions = true; synth_opts->ptwrites = true; synth_opts->pwr_events = true; + synth_opts->other_events = true; synth_opts->errors = true; if (no_sample) { synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; @@ -1061,6 +1073,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, case 'p': synth_opts->pwr_events = true; break; + case 'o': + synth_opts->other_events = true; + break; case 'e': synth_opts->errors = true; break; @@ -1154,7 +1169,7 @@ static const char *auxtrace_error_name(int type) size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) { - struct auxtrace_error_event *e = &event->auxtrace_error; + struct perf_record_auxtrace_error *e = &event->auxtrace_error; unsigned long long nsecs = e->time; const char *msg = e->msg; int ret; @@ -1174,7 +1189,7 @@ size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) if (!e->fmt) msg = (const char *)&e->time; - ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n", + ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %s\n", e->cpu, e->pid, e->tid, e->ip, e->code, msg); return ret; } @@ -1182,7 +1197,7 @@ size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) void perf_session__auxtrace_error_inc(struct perf_session *session, union perf_event *event) { - struct auxtrace_error_event *e = &event->auxtrace_error; + struct perf_record_auxtrace_error *e = &event->auxtrace_error; if (e->type < PERF_AUXTRACE_ERROR_MAX) session->evlist->stats.nr_auxtrace_errors[e->type] += 1; @@ -2084,7 +2099,7 @@ static char *addr_filter__to_str(struct addr_filter *filt) return err < 0 ? NULL : filter; } -static int parse_addr_filter(struct perf_evsel *evsel, const char *filter, +static int parse_addr_filter(struct evsel *evsel, const char *filter, int max_nr) { struct addr_filters filts; @@ -2135,19 +2150,19 @@ out_exit: return err; } -static struct perf_pmu *perf_evsel__find_pmu(struct perf_evsel *evsel) +static struct perf_pmu *perf_evsel__find_pmu(struct evsel *evsel) { struct perf_pmu *pmu = NULL; while ((pmu = perf_pmu__scan(pmu)) != NULL) { - if (pmu->type == evsel->attr.type) + if (pmu->type == evsel->core.attr.type) break; } return pmu; } -static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) +static int perf_evsel__nr_addr_filter(struct evsel *evsel) { struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); int nr_addr_filters = 0; @@ -2160,9 +2175,9 @@ static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) return nr_addr_filters; } -int auxtrace_parse_filters(struct perf_evlist *evlist) +int auxtrace_parse_filters(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; char *filter; int err, max_nr; @@ -2181,3 +2196,36 @@ int auxtrace_parse_filters(struct perf_evlist *evlist) return 0; } + +int auxtrace__process_event(struct perf_session *session, union perf_event *event, + struct perf_sample *sample, struct perf_tool *tool) +{ + if (!session->auxtrace) + return 0; + + return session->auxtrace->process_event(session, event, sample, tool); +} + +int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool) +{ + if (!session->auxtrace) + return 0; + + return session->auxtrace->flush_events(session, tool); +} + +void auxtrace__free_events(struct perf_session *session) +{ + if (!session->auxtrace) + return; + + return session->auxtrace->free_events(session); +} + +void auxtrace__free(struct perf_session *session) +{ + if (!session->auxtrace) + return; + + return session->auxtrace->free(session); +} diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index e9b4c5edf78b..37e70dc01436 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -15,22 +15,25 @@ #include <linux/perf_event.h> #include <linux/types.h> #include <asm/bitsperlong.h> +#include <asm/barrier.h> -#include "../perf.h" #include "event.h" -#include "session.h" -#include "debug.h" union perf_event; struct perf_session; -struct perf_evlist; +struct evlist; struct perf_tool; struct perf_mmap; struct option; struct record_opts; -struct auxtrace_info_event; +struct perf_record_auxtrace_info; struct events_stats; +enum auxtrace_error_type { + PERF_AUXTRACE_ERROR_ITRACE = 1, + PERF_AUXTRACE_ERROR_MAX +}; + /* Auxtrace records must have the same alignment as perf event records */ #define PERF_AUXTRACE_RECORD_ALIGNMENT 8 @@ -60,6 +63,8 @@ enum itrace_period_type { * @transactions: whether to synthesize events for transactions * @ptwrites: whether to synthesize events for ptwrites * @pwr_events: whether to synthesize power events + * @other_events: whether to synthesize other events recorded due to the use of + * aux_output * @errors: whether to synthesize decoder error events * @dont_decode: whether to skip decoding entirely * @log: write a decoding log @@ -86,6 +91,7 @@ struct itrace_synth_opts { bool transactions; bool ptwrites; bool pwr_events; + bool other_events; bool errors; bool dont_decode; bool log; @@ -309,13 +315,13 @@ struct auxtrace_mmap_params { */ struct auxtrace_record { int (*recording_options)(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts); size_t (*info_priv_size)(struct auxtrace_record *itr, - struct perf_evlist *evlist); + struct evlist *evlist); int (*info_fill)(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size); void (*free)(struct auxtrace_record *itr); int (*snapshot_start)(struct auxtrace_record *itr); @@ -373,6 +379,8 @@ struct addr_filters { int cnt; }; +struct auxtrace_cache; + #ifdef HAVE_AUXTRACE_SUPPORT /* @@ -432,7 +440,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, unsigned int auxtrace_pages, bool auxtrace_overwrite); void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, - struct perf_evlist *evlist, int idx, + struct evlist *evlist, int idx, bool per_cpu); typedef int (*process_auxtrace_t)(struct perf_tool *tool, @@ -482,24 +490,24 @@ int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, struct auxtrace_cache_entry *entry); void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key); -struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err); int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, struct record_opts *opts, const char *str); int auxtrace_record__options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts); size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, - struct perf_evlist *evlist); + struct evlist *evlist); int auxtrace_record__info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size); void auxtrace_record__free(struct auxtrace_record *itr); int auxtrace_record__snapshot_start(struct auxtrace_record *itr); -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr); +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit); int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, struct auxtrace_mmap *mm, unsigned char *data, u64 *head, u64 *old); @@ -512,7 +520,7 @@ int auxtrace_index__process(int fd, u64 size, struct perf_session *session, bool needs_swap); void auxtrace_index__free(struct list_head *head); -void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, +void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type, int code, int cpu, pid_t pid, pid_t tid, u64 ip, const char *msg, u64 timestamp); @@ -540,43 +548,13 @@ void addr_filters__init(struct addr_filters *filts); void addr_filters__exit(struct addr_filters *filts); int addr_filters__parse_bare_filter(struct addr_filters *filts, const char *filter); -int auxtrace_parse_filters(struct perf_evlist *evlist); - -static inline int auxtrace__process_event(struct perf_session *session, - union perf_event *event, - struct perf_sample *sample, - struct perf_tool *tool) -{ - if (!session->auxtrace) - return 0; - - return session->auxtrace->process_event(session, event, sample, tool); -} - -static inline int auxtrace__flush_events(struct perf_session *session, - struct perf_tool *tool) -{ - if (!session->auxtrace) - return 0; - - return session->auxtrace->flush_events(session, tool); -} +int auxtrace_parse_filters(struct evlist *evlist); -static inline void auxtrace__free_events(struct perf_session *session) -{ - if (!session->auxtrace) - return; - - return session->auxtrace->free_events(session); -} - -static inline void auxtrace__free(struct perf_session *session) -{ - if (!session->auxtrace) - return; - - return session->auxtrace->free(session); -} +int auxtrace__process_event(struct perf_session *session, union perf_event *event, + struct perf_sample *sample, struct perf_tool *tool); +int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool); +void auxtrace__free_events(struct perf_session *session); +void auxtrace__free(struct perf_session *session); #define ITRACE_HELP \ " i: synthesize instructions events\n" \ @@ -611,9 +589,10 @@ void itrace_synth_opts__clear_time_range(struct itrace_synth_opts *opts) } #else +#include "debug.h" static inline struct auxtrace_record * -auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, +auxtrace_record__init(struct evlist *evlist __maybe_unused, int *err) { *err = 0; @@ -636,7 +615,7 @@ perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr __maybe_unused, static inline int auxtrace_record__options(struct auxtrace_record *itr __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, struct record_opts *opts __maybe_unused) { return 0; @@ -733,7 +712,7 @@ void auxtrace_index__free(struct list_head *head __maybe_unused) } static inline -int auxtrace_parse_filters(struct perf_evlist *evlist __maybe_unused) +int auxtrace_parse_filters(struct evlist *evlist __maybe_unused) { return 0; } @@ -747,7 +726,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, unsigned int auxtrace_pages, bool auxtrace_overwrite); void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, - struct perf_evlist *evlist, int idx, + struct evlist *evlist, int idx, bool per_cpu); #define ITRACE_HELP "" diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 2a4a0da35632..7a3d4b125323 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -8,12 +8,14 @@ #include <linux/err.h> #include "bpf-event.h" #include "debug.h" +#include "dso.h" #include "symbol.h" #include "machine.h" #include "env.h" #include "session.h" #include "map.h" #include "evlist.h" +#include "record.h" #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) @@ -34,7 +36,7 @@ static int machine__process_bpf_event_load(struct machine *machine, struct bpf_prog_info_linear *info_linear; struct bpf_prog_info_node *info_node; struct perf_env *env = machine->env; - int id = event->bpf_event.id; + int id = event->bpf.id; unsigned int i; /* perf-record, no need to handle bpf-event */ @@ -63,14 +65,13 @@ static int machine__process_bpf_event_load(struct machine *machine, return 0; } -int machine__process_bpf_event(struct machine *machine __maybe_unused, - union perf_event *event, - struct perf_sample *sample __maybe_unused) +int machine__process_bpf(struct machine *machine, union perf_event *event, + struct perf_sample *sample) { if (dump_trace) - perf_event__fprintf_bpf_event(event, stdout); + perf_event__fprintf_bpf(event, stdout); - switch (event->bpf_event.type) { + switch (event->bpf.type) { case PERF_BPF_EVENT_PROG_LOAD: return machine__process_bpf_event_load(machine, event, sample); @@ -82,8 +83,7 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused, */ break; default: - pr_debug("unexpected bpf_event type of %d\n", - event->bpf_event.type); + pr_debug("unexpected bpf event type of %d\n", event->bpf.type); break; } return 0; @@ -160,8 +160,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, union perf_event *event, struct record_opts *opts) { - struct ksymbol_event *ksymbol_event = &event->ksymbol_event; - struct bpf_event *bpf_event = &event->bpf_event; + struct perf_record_ksymbol *ksymbol_event = &event->ksymbol; + struct perf_record_bpf_event *bpf_event = &event->bpf; struct bpf_prog_info_linear *info_linear; struct perf_tool *tool = session->tool; struct bpf_prog_info_node *info_node; @@ -229,10 +229,10 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms); int name_len; - *ksymbol_event = (struct ksymbol_event){ + *ksymbol_event = (struct perf_record_ksymbol) { .header = { .type = PERF_RECORD_KSYMBOL, - .size = offsetof(struct ksymbol_event, name), + .size = offsetof(struct perf_record_ksymbol, name), }, .addr = prog_addrs[i], .len = prog_lens[i], @@ -253,10 +253,10 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, if (!opts->no_bpf_event) { /* Synthesize PERF_RECORD_BPF_EVENT */ - *bpf_event = (struct bpf_event){ + *bpf_event = (struct perf_record_bpf_event) { .header = { .type = PERF_RECORD_BPF_EVENT, - .size = sizeof(struct bpf_event), + .size = sizeof(struct perf_record_bpf_event), }, .type = PERF_BPF_EVENT_PROG_LOAD, .flags = 0, @@ -301,7 +301,7 @@ int perf_event__synthesize_bpf_events(struct perf_session *session, int err; int fd; - event = malloc(sizeof(event->bpf_event) + KSYM_NAME_LEN + machine->id_hdr_size); + event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size); if (!event) return -1; while (true) { @@ -398,9 +398,9 @@ static int bpf_event__sb_cb(union perf_event *event, void *data) if (event->header.type != PERF_RECORD_BPF_EVENT) return -1; - switch (event->bpf_event.type) { + switch (event->bpf.type) { case PERF_BPF_EVENT_PROG_LOAD: - perf_env__add_bpf_info(env, event->bpf_event.id); + perf_env__add_bpf_info(env, event->bpf.id); case PERF_BPF_EVENT_PROG_UNLOAD: /* @@ -410,15 +410,14 @@ static int bpf_event__sb_cb(union perf_event *event, void *data) */ break; default: - pr_debug("unexpected bpf_event type of %d\n", - event->bpf_event.type); + pr_debug("unexpected bpf event type of %d\n", event->bpf.type); break; } return 0; } -int bpf_event__add_sb_event(struct perf_evlist **evlist, +int bpf_event__add_sb_event(struct evlist **evlist, struct perf_env *env) { struct perf_event_attr attr = { diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h index 04c33b3bfe28..a01c2fd68c03 100644 --- a/tools/perf/util/bpf-event.h +++ b/tools/perf/util/bpf-event.h @@ -13,6 +13,7 @@ struct machine; union perf_event; struct perf_env; struct perf_sample; +struct perf_session; struct record_opts; struct evlist; struct target; @@ -30,22 +31,22 @@ struct btf_node { }; #ifdef HAVE_LIBBPF_SUPPORT -int machine__process_bpf_event(struct machine *machine, union perf_event *event, - struct perf_sample *sample); +int machine__process_bpf(struct machine *machine, union perf_event *event, + struct perf_sample *sample); int perf_event__synthesize_bpf_events(struct perf_session *session, perf_event__handler_t process, struct machine *machine, struct record_opts *opts); -int bpf_event__add_sb_event(struct perf_evlist **evlist, +int bpf_event__add_sb_event(struct evlist **evlist, struct perf_env *env); void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info, struct perf_env *env, FILE *fp); #else -static inline int machine__process_bpf_event(struct machine *machine __maybe_unused, - union perf_event *event __maybe_unused, - struct perf_sample *sample __maybe_unused) +static inline int machine__process_bpf(struct machine *machine __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_sample *sample __maybe_unused) { return 0; } @@ -58,7 +59,7 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session return 0; } -static inline int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused, +static inline int bpf_event__add_sb_event(struct evlist **evlist __maybe_unused, struct perf_env *env __maybe_unused) { return 0; diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index c61974a50aa5..37283e865352 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -14,7 +14,7 @@ #include <linux/string.h> #include <linux/zalloc.h> #include <errno.h> -#include "perf.h" +#include <stdlib.h> #include "debug.h" #include "evlist.h" #include "bpf-loader.h" @@ -23,9 +23,12 @@ #include "probe-finder.h" // for MAX_PROBES #include "parse-events.h" #include "strfilter.h" +#include "util.h" #include "llvm-utils.h" #include "c++/clang-c.h" +#include <internal/xyarray.h> + static int libbpf_perf_print(enum libbpf_print_level level __attribute__((unused)), const char *fmt, va_list args) { @@ -763,7 +766,7 @@ int bpf__foreach_event(struct bpf_object *obj, if (priv->is_tp) { fd = bpf_program__fd(prog); - err = (*func)(priv->sys_name, priv->evt_name, fd, arg); + err = (*func)(priv->sys_name, priv->evt_name, fd, obj, arg); if (err) { pr_debug("bpf: tracepoint call back failed, stop iterate\n"); return err; @@ -788,7 +791,7 @@ int bpf__foreach_event(struct bpf_object *obj, return fd; } - err = (*func)(tev->group, tev->event, fd, arg); + err = (*func)(tev->group, tev->event, fd, obj, arg); if (err) { pr_debug("bpf: call back failed, stop iterate\n"); return err; @@ -817,7 +820,7 @@ struct bpf_map_op { } k; union { u64 value; - struct perf_evsel *evsel; + struct evsel *evsel; } v; }; @@ -1043,7 +1046,7 @@ __bpf_map__config_value(struct bpf_map *map, static int bpf_map__config_value(struct bpf_map *map, struct parse_events_term *term, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { if (!term->err_val) { pr_debug("Config value not set\n"); @@ -1061,9 +1064,9 @@ bpf_map__config_value(struct bpf_map *map, static int __bpf_map__config_event(struct bpf_map *map, struct parse_events_term *term, - struct perf_evlist *evlist) + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; const struct bpf_map_def *def; struct bpf_map_op *op; const char *map_name = bpf_map__name(map); @@ -1103,7 +1106,7 @@ __bpf_map__config_event(struct bpf_map *map, static int bpf_map__config_event(struct bpf_map *map, struct parse_events_term *term, - struct perf_evlist *evlist) + struct evlist *evlist) { if (!term->err_val) { pr_debug("Config value not set\n"); @@ -1121,7 +1124,7 @@ bpf_map__config_event(struct bpf_map *map, struct bpf_obj_config__map_func { const char *config_opt; int (*config_func)(struct bpf_map *, struct parse_events_term *, - struct perf_evlist *); + struct evlist *); }; struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = { @@ -1169,7 +1172,7 @@ config_map_indices_range_check(struct parse_events_term *term, static int bpf__obj_config_map(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, + struct evlist *evlist, int *key_scan_pos) { /* key is "map:<mapname>.<config opt>" */ @@ -1228,7 +1231,7 @@ out: int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, + struct evlist *evlist, int *error_pos) { int key_scan_pos = 0; @@ -1401,9 +1404,9 @@ apply_config_value_for_key(int map_fd, void *pkey, static int apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, - struct perf_evsel *evsel) + struct evsel *evsel) { - struct xyarray *xy = evsel->fd; + struct xyarray *xy = evsel->core.fd; struct perf_event_attr *attr; unsigned int key, events; bool check_pass = false; @@ -1421,7 +1424,7 @@ apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM; } - attr = &evsel->attr; + attr = &evsel->core.attr; if (attr->inherit) { pr_debug("ERROR: Can't put inherit event into map %s\n", name); return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH; @@ -1523,11 +1526,11 @@ int bpf__apply_obj_config(void) (strcmp(name, \ bpf_map__name(pos)) == 0)) -struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name) +struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name) { struct bpf_map_priv *tmpl_priv = NULL; struct bpf_object *obj, *tmp; - struct perf_evsel *evsel = NULL; + struct evsel *evsel = NULL; struct bpf_map *map; int err; bool need_init = false; @@ -1600,9 +1603,9 @@ struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const cha return evsel; } -int bpf__setup_stdout(struct perf_evlist *evlist) +int bpf__setup_stdout(struct evlist *evlist) { - struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); + struct evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); return PTR_ERR_OR_ZERO(evsel); } @@ -1756,7 +1759,7 @@ int bpf__strerror_load(struct bpf_object *obj, int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, struct parse_events_term *term __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int *error_pos __maybe_unused, int err, char *buf, size_t size) { @@ -1780,7 +1783,7 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) return 0; } -int bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, +int bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused, int err, char *buf, size_t size) { bpf__strerror_head(err, buf, size); diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 3f46856e3330..25251d63164c 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -39,14 +39,14 @@ enum bpf_loader_errno { __BPF_LOADER_ERRNO__END, }; -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct bpf_object; struct parse_events_term; #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" typedef int (*bpf_prog_iter_callback_t)(const char *group, const char *event, - int fd, void *arg); + int fd, struct bpf_object *obj, void *arg); #ifdef HAVE_LIBBPF_SUPPORT struct bpf_object *bpf__prepare_load(const char *filename, bool source); @@ -70,18 +70,18 @@ int bpf__foreach_event(struct bpf_object *obj, bpf_prog_iter_callback_t func, void *arg); int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, int *error_pos); + struct evlist *evlist, int *error_pos); int bpf__strerror_config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, + struct evlist *evlist, int *error_pos, int err, char *buf, size_t size); int bpf__apply_obj_config(void); int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); -int bpf__setup_stdout(struct perf_evlist *evlist); -struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name); -int bpf__strerror_setup_output_event(struct perf_evlist *evlist, int err, char *buf, size_t size); +int bpf__setup_stdout(struct evlist *evlist); +struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name); +int bpf__strerror_setup_output_event(struct evlist *evlist, int err, char *buf, size_t size); #else #include <errno.h> #include <string.h> @@ -119,7 +119,7 @@ bpf__foreach_event(struct bpf_object *obj __maybe_unused, static inline int bpf__config_obj(struct bpf_object *obj __maybe_unused, struct parse_events_term *term __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int *error_pos __maybe_unused) { return 0; @@ -132,13 +132,13 @@ bpf__apply_obj_config(void) } static inline int -bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) +bpf__setup_stdout(struct evlist *evlist __maybe_unused) { return 0; } -static inline struct perf_evsel * -bpf__setup_output_event(struct perf_evlist *evlist __maybe_unused, const char *name __maybe_unused) +static inline struct evsel * +bpf__setup_output_event(struct evlist *evlist __maybe_unused, const char *name __maybe_unused) { return NULL; } @@ -182,7 +182,7 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused, static inline int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, struct parse_events_term *term __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int *error_pos __maybe_unused, int err __maybe_unused, char *buf, size_t size) @@ -198,7 +198,7 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, } static inline int -bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, +bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused, int err __maybe_unused, char *buf, size_t size) { return __bpf_strerror(buf, size); @@ -206,7 +206,7 @@ bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, #endif -static inline int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, char *buf, size_t size) +static inline int bpf__strerror_setup_stdout(struct evlist *evlist, int err, char *buf, size_t size) { return bpf__strerror_setup_output_event(evlist, err, buf, size); } diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c index 77e4891e17b0..b020a8678eb9 100644 --- a/tools/perf/util/bpf-prologue.c +++ b/tools/perf/util/bpf-prologue.c @@ -8,12 +8,12 @@ */ #include <bpf/libbpf.h> -#include "perf.h" #include "debug.h" #include "bpf-loader.h" #include "bpf-prologue.h" #include "probe-finder.h" #include <errno.h> +#include <stdlib.h> #include <dwarf-regs.h> #include <linux/filter.h> diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c index a4fce2729e50..9d1e090084a2 100644 --- a/tools/perf/util/branch.c +++ b/tools/perf/util/branch.c @@ -1,7 +1,8 @@ -#include "perf.h" #include "util/util.h" #include "util/debug.h" +#include "util/map_symbol.h" #include "util/branch.h" +#include <linux/kernel.h> static bool cross_area(u64 addr1, u64 addr2, int size) { diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h index 64f96b79f1d7..06f66dad0b79 100644 --- a/tools/perf/util/branch.h +++ b/tools/perf/util/branch.h @@ -16,6 +16,14 @@ struct branch_flags { u64 reserved:40; }; +struct branch_info { + struct addr_map_symbol from; + struct addr_map_symbol to; + struct branch_flags flags; + char *srcline_from; + char *srcline_to; +}; + struct branch_entry { u64 from; u64 to; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index f1abfab7aa8c..e5fb77755d9e 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -13,6 +13,7 @@ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> +#include "dso.h" #include "build-id.h" #include "event.h" #include "namespaces.h" @@ -37,7 +38,7 @@ static bool no_buildid_cache; int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct machine *machine) { struct addr_location al; @@ -295,7 +296,7 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id, pid_t pid, u16 misc, struct feat_fd *fd) { int err; - struct build_id_event b; + struct perf_record_header_build_id b; size_t len; len = name_len + 1; diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 93668f38f1ed..aad419bb165c 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -24,7 +24,7 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size, bool is_debug); int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct machine *machine); int dsos__hit_all(struct perf_session *session); diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h index e513366f2ee0..2df8a45bd088 100644 --- a/tools/perf/util/c++/clang-c.h +++ b/tools/perf/util/c++/clang-c.h @@ -3,7 +3,6 @@ #define PERF_UTIL_CLANG_C_H #include <stddef.h> /* for size_t */ -#include <util-cxx.h> /* for __maybe_unused */ #ifdef __cplusplus extern "C" { @@ -22,6 +21,7 @@ extern int perf_clang__compile_bpf(const char *filename, #else #include <errno.h> +#include <linux/compiler.h> /* for __maybe_unused */ static inline void perf_clang__init(void) { } static inline void perf_clang__cleanup(void) { } diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp index 7b042a5ebc68..21b23605f78b 100644 --- a/tools/perf/util/c++/clang-test.cpp +++ b/tools/perf/util/c++/clang-test.cpp @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include "clang.h" #include "clang-c.h" +extern "C" { +#include "../util.h" +} #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" -#include <util-cxx.h> #include <tests/llvm.h> #include <string> diff --git a/tools/perf/util/cacheline.c b/tools/perf/util/cacheline.c new file mode 100644 index 000000000000..e98b5250a517 --- /dev/null +++ b/tools/perf/util/cacheline.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "cacheline.h" +#include <unistd.h> + +#ifdef _SC_LEVEL1_DCACHE_LINESIZE +#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) +#else +#include <api/fs/fs.h> +#include "debug.h" +static void cache_line_size(int *cacheline_sizep) +{ + if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) + pr_debug("cannot determine cache line size"); +} +#endif + +int cacheline_size(void) +{ + static int size; + + if (!size) + cache_line_size(&size); + + return size; +} diff --git a/tools/perf/util/cacheline.h b/tools/perf/util/cacheline.h new file mode 100644 index 000000000000..dec8c0fb1f4a --- /dev/null +++ b/tools/perf/util/cacheline.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef PERF_CACHELINE_H +#define PERF_CACHELINE_H + +#include <linux/compiler.h> + +int __pure cacheline_size(void); + +static inline u64 cl_address(u64 address) +{ + /* return the cacheline of the address */ + return (address & ~(cacheline_size() - 1)); +} + +static inline u64 cl_offset(u64 address) +{ + /* return the cacheline of the address */ + return (address & (cacheline_size() - 1)); +} + +#endif // PERF_CACHELINE_H diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 8d7d8f62fcca..c14646c1f2eb 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -16,10 +16,13 @@ #include <stdbool.h> #include <errno.h> #include <math.h> +#include <linux/string.h> #include <linux/zalloc.h> #include "asm/bug.h" +#include "debug.h" +#include "dso.h" #include "hist.h" #include "sort.h" #include "machine.h" @@ -27,6 +30,7 @@ #include "callchain.h" #include "branch.h" #include "symbol.h" +#include "../perf.h" #define CALLCHAIN_PARAM_DEFAULT \ .mode = CHAIN_GRAPH_ABS, \ @@ -1077,7 +1081,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, int sample__resolve_callchain(struct perf_sample *sample, struct callchain_cursor *cursor, struct symbol **parent, - struct perf_evsel *evsel, struct addr_location *al, + struct evsel *evsel, struct addr_location *al, int max_stack) { if (sample->callchain == NULL && !symbol_conf.show_branchflag_count) diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 80e056a3d882..b042ceef4114 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -8,6 +8,7 @@ #include "map_symbol.h" #include "branch.h" +struct evsel; struct map; #define HELP_PAD "\t\t\t\t" @@ -236,7 +237,7 @@ int record_opts__parse_callchain(struct record_opts *record, int sample__resolve_callchain(struct perf_sample *sample, struct callchain_cursor *cursor, struct symbol **parent, - struct perf_evsel *evsel, struct addr_location *al, + struct evsel *evsel, struct addr_location *al, int max_stack); int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node, diff --git a/tools/perf/util/cap.c b/tools/perf/util/cap.c new file mode 100644 index 000000000000..c3ba841bbf37 --- /dev/null +++ b/tools/perf/util/cap.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Capability utilities + */ + +#ifdef HAVE_LIBCAP_SUPPORT + +#include "cap.h" +#include <stdbool.h> +#include <sys/capability.h> + +bool perf_cap__capable(cap_value_t cap) +{ + cap_flag_value_t val; + cap_t caps = cap_get_proc(); + + if (!caps) + return false; + + if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) != 0) + val = CAP_CLEAR; + + if (cap_free(caps) != 0) + return false; + + return val == CAP_SET; +} + +#endif /* HAVE_LIBCAP_SUPPORT */ diff --git a/tools/perf/util/cap.h b/tools/perf/util/cap.h new file mode 100644 index 000000000000..051dc590ceee --- /dev/null +++ b/tools/perf/util/cap.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_CAP_H +#define __PERF_CAP_H + +#include <stdbool.h> +#include <linux/capability.h> +#include <linux/compiler.h> + +#ifdef HAVE_LIBCAP_SUPPORT + +#include <sys/capability.h> + +bool perf_cap__capable(cap_value_t cap); + +#else + +#include <unistd.h> +#include <sys/types.h> + +static inline bool perf_cap__capable(int cap __maybe_unused) +{ + return geteuid() == 0; +} + +#endif /* HAVE_LIBCAP_SUPPORT */ + +/* For older systems */ +#ifndef CAP_SYSLOG +#define CAP_SYSLOG 34 +#endif + +#endif /* __PERF_CAP_H */ diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 484c29830a81..4881d4af3381 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../perf.h" #include <subcmd/parse-options.h> #include "evsel.h" #include "cgroup.h" @@ -9,6 +8,8 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <stdlib.h> +#include <string.h> int nr_cgroups; @@ -90,9 +91,9 @@ static int open_cgroup(const char *name) return fd; } -static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str) +static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str) { - struct perf_evsel *counter; + struct evsel *counter; /* * check if cgrp is already defined, if so we reuse it */ @@ -130,16 +131,16 @@ out_err: return NULL; } -struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name) +struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name) { struct cgroup *cgroup = evlist__find_cgroup(evlist, name); return cgroup ?: cgroup__new(name); } -static int add_cgroup(struct perf_evlist *evlist, const char *str) +static int add_cgroup(struct evlist *evlist, const char *str) { - struct perf_evsel *counter; + struct evsel *counter; struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str); int n; @@ -184,15 +185,15 @@ struct cgroup *cgroup__get(struct cgroup *cgroup) return cgroup; } -static void evsel__set_default_cgroup(struct perf_evsel *evsel, struct cgroup *cgroup) +static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup) { if (evsel->cgrp == NULL) evsel->cgrp = cgroup__get(cgroup); } -void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup) +void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel__set_default_cgroup(evsel, cgroup); @@ -201,14 +202,14 @@ void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgrou int parse_cgroups(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; - struct perf_evsel *counter; + struct evlist *evlist = *(struct evlist **)opt->value; + struct evsel *counter; struct cgroup *cgrp = NULL; const char *p, *e, *eos = str + strlen(str); char *s; int ret, i; - if (list_empty(&evlist->entries)) { + if (list_empty(&evlist->core.entries)) { fprintf(stderr, "must define events before cgroups\n"); return -1; } diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h index f033a80c1b14..2ec11f01090d 100644 --- a/tools/perf/util/cgroup.h +++ b/tools/perf/util/cgroup.h @@ -18,11 +18,11 @@ extern int nr_cgroups; /* number of explicit cgroups defined */ struct cgroup *cgroup__get(struct cgroup *cgroup); void cgroup__put(struct cgroup *cgroup); -struct perf_evlist; +struct evlist; -struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name); +struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name); -void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup); +void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup); int parse_cgroups(const struct option *opt, const char *str, int unset); diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 06f48312c5ed..4e904fcb2783 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -2,12 +2,14 @@ #include <errno.h> #include <sched.h> #include "util.h" -#include "../perf.h" +#include "../perf-sys.h" #include "cloexec.h" +#include "event.h" #include "asm/bug.h" #include "debug.h" #include <unistd.h> #include <sys/syscall.h> +#include <linux/string.h> static unsigned long flag = PERF_FLAG_FD_CLOEXEC; diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 39b8c4ec4e2e..bffbdd216a6a 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> -#include "cache.h" +#include <subcmd/pager.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "color.h" #include <math.h> #include <unistd.h> diff --git a/tools/perf/util/color_config.c b/tools/perf/util/color_config.c index 817dc56e7e95..dc09ba7cb31e 100644 --- a/tools/perf/util/color_config.c +++ b/tools/perf/util/color_config.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> -#include "cache.h" +#include <subcmd/pager.h> +#include <string.h> #include "config.h" #include <stdlib.h> #include <stdio.h> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 042ffbc8c53f..0bc9c4d7fdc5 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -17,9 +17,13 @@ #include "util/event.h" /* proc_map_timeout */ #include "util/hist.h" /* perf_hist_config */ #include "util/llvm-utils.h" /* perf_llvm_config */ +#include "build-id.h" +#include "debug.h" #include "config.h" +#include "debug.h" #include <sys/types.h> #include <sys/stat.h> +#include <stdlib.h> #include <unistd.h> #include <linux/string.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/counts.c b/tools/perf/util/counts.c index 88be9c4365e0..f94e1a23dad6 100644 --- a/tools/perf/util/counts.c +++ b/tools/perf/util/counts.c @@ -19,6 +19,15 @@ struct perf_counts *perf_counts__new(int ncpus, int nthreads) } counts->values = values; + + values = xyarray__new(ncpus, nthreads, sizeof(bool)); + if (!values) { + xyarray__delete(counts->values); + free(counts); + return NULL; + } + + counts->loaded = values; } return counts; @@ -27,6 +36,7 @@ struct perf_counts *perf_counts__new(int ncpus, int nthreads) void perf_counts__delete(struct perf_counts *counts) { if (counts) { + xyarray__delete(counts->loaded); xyarray__delete(counts->values); free(counts); } @@ -34,21 +44,22 @@ void perf_counts__delete(struct perf_counts *counts) static void perf_counts__reset(struct perf_counts *counts) { + xyarray__reset(counts->loaded); xyarray__reset(counts->values); } -void perf_evsel__reset_counts(struct perf_evsel *evsel) +void perf_evsel__reset_counts(struct evsel *evsel) { perf_counts__reset(evsel->counts); } -int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads) +int perf_evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads) { evsel->counts = perf_counts__new(ncpus, nthreads); return evsel->counts != NULL ? 0 : -ENOMEM; } -void perf_evsel__free_counts(struct perf_evsel *evsel) +void perf_evsel__free_counts(struct evsel *evsel) { perf_counts__delete(evsel->counts); evsel->counts = NULL; diff --git a/tools/perf/util/counts.h b/tools/perf/util/counts.h index 0d1050ccc586..92196df4945f 100644 --- a/tools/perf/util/counts.h +++ b/tools/perf/util/counts.h @@ -2,24 +2,18 @@ #ifndef __PERF_COUNTS_H #define __PERF_COUNTS_H -#include "xyarray.h" - -struct perf_counts_values { - union { - struct { - u64 val; - u64 ena; - u64 run; - }; - u64 values[3]; - }; - bool loaded; -}; +#include <linux/types.h> +#include <internal/xyarray.h> +#include <perf/evsel.h> +#include <stdbool.h> + +struct evsel; struct perf_counts { s8 scaled; struct perf_counts_values aggr; struct xyarray *values; + struct xyarray *loaded; }; @@ -29,11 +23,23 @@ perf_counts(struct perf_counts *counts, int cpu, int thread) return xyarray__entry(counts->values, cpu, thread); } +static inline bool +perf_counts__is_loaded(struct perf_counts *counts, int cpu, int thread) +{ + return *((bool *) xyarray__entry(counts->loaded, cpu, thread)); +} + +static inline void +perf_counts__set_loaded(struct perf_counts *counts, int cpu, int thread, bool loaded) +{ + *((bool *) xyarray__entry(counts->loaded, cpu, thread)) = loaded; +} + struct perf_counts *perf_counts__new(int ncpus, int nthreads); void perf_counts__delete(struct perf_counts *counts); -void perf_evsel__reset_counts(struct perf_evsel *evsel); -int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads); -void perf_evsel__free_counts(struct perf_evsel *evsel); +void perf_evsel__reset_counts(struct evsel *evsel); +int perf_evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads); +void perf_evsel__free_counts(struct evsel *evsel); #endif /* __PERF_COUNTS_H */ diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 39cce66b4ebc..a22c1114e880 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include <api/fs/fs.h> -#include "../perf.h" #include "cpumap.h" +#include "debug.h" +#include "event.h" #include <assert.h> #include <dirent.h> #include <stdio.h> @@ -17,190 +18,11 @@ static int max_present_cpu_num; static int max_node_num; static int *cpunode_map; -static struct cpu_map *cpu_map__default_new(void) +static struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) { - struct cpu_map *cpus; - int nr_cpus; + struct perf_cpu_map *map; - nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if (nr_cpus < 0) - return NULL; - - cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int)); - if (cpus != NULL) { - int i; - for (i = 0; i < nr_cpus; ++i) - cpus->map[i] = i; - - cpus->nr = nr_cpus; - refcount_set(&cpus->refcnt, 1); - } - - return cpus; -} - -static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) -{ - size_t payload_size = nr_cpus * sizeof(int); - struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size); - - if (cpus != NULL) { - cpus->nr = nr_cpus; - memcpy(cpus->map, tmp_cpus, payload_size); - refcount_set(&cpus->refcnt, 1); - } - - return cpus; -} - -struct cpu_map *cpu_map__read(FILE *file) -{ - struct cpu_map *cpus = NULL; - int nr_cpus = 0; - int *tmp_cpus = NULL, *tmp; - int max_entries = 0; - int n, cpu, prev; - char sep; - - sep = 0; - prev = -1; - for (;;) { - n = fscanf(file, "%u%c", &cpu, &sep); - if (n <= 0) - break; - if (prev >= 0) { - int new_max = nr_cpus + cpu - prev - 1; - - if (new_max >= max_entries) { - max_entries = new_max + MAX_NR_CPUS / 2; - tmp = realloc(tmp_cpus, max_entries * sizeof(int)); - if (tmp == NULL) - goto out_free_tmp; - tmp_cpus = tmp; - } - - while (++prev < cpu) - tmp_cpus[nr_cpus++] = prev; - } - if (nr_cpus == max_entries) { - max_entries += MAX_NR_CPUS; - tmp = realloc(tmp_cpus, max_entries * sizeof(int)); - if (tmp == NULL) - goto out_free_tmp; - tmp_cpus = tmp; - } - - tmp_cpus[nr_cpus++] = cpu; - if (n == 2 && sep == '-') - prev = cpu; - else - prev = -1; - if (n == 1 || sep == '\n') - break; - } - - if (nr_cpus > 0) - cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); - else - cpus = cpu_map__default_new(); -out_free_tmp: - free(tmp_cpus); - return cpus; -} - -static struct cpu_map *cpu_map__read_all_cpu_map(void) -{ - struct cpu_map *cpus = NULL; - FILE *onlnf; - - onlnf = fopen("/sys/devices/system/cpu/online", "r"); - if (!onlnf) - return cpu_map__default_new(); - - cpus = cpu_map__read(onlnf); - fclose(onlnf); - return cpus; -} - -struct cpu_map *cpu_map__new(const char *cpu_list) -{ - struct cpu_map *cpus = NULL; - unsigned long start_cpu, end_cpu = 0; - char *p = NULL; - int i, nr_cpus = 0; - int *tmp_cpus = NULL, *tmp; - int max_entries = 0; - - if (!cpu_list) - return cpu_map__read_all_cpu_map(); - - /* - * must handle the case of empty cpumap to cover - * TOPOLOGY header for NUMA nodes with no CPU - * ( e.g., because of CPU hotplug) - */ - if (!isdigit(*cpu_list) && *cpu_list != '\0') - goto out; - - while (isdigit(*cpu_list)) { - p = NULL; - start_cpu = strtoul(cpu_list, &p, 0); - if (start_cpu >= INT_MAX - || (*p != '\0' && *p != ',' && *p != '-')) - goto invalid; - - if (*p == '-') { - cpu_list = ++p; - p = NULL; - end_cpu = strtoul(cpu_list, &p, 0); - - if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) - goto invalid; - - if (end_cpu < start_cpu) - goto invalid; - } else { - end_cpu = start_cpu; - } - - for (; start_cpu <= end_cpu; start_cpu++) { - /* check for duplicates */ - for (i = 0; i < nr_cpus; i++) - if (tmp_cpus[i] == (int)start_cpu) - goto invalid; - - if (nr_cpus == max_entries) { - max_entries += MAX_NR_CPUS; - tmp = realloc(tmp_cpus, max_entries * sizeof(int)); - if (tmp == NULL) - goto invalid; - tmp_cpus = tmp; - } - tmp_cpus[nr_cpus++] = (int)start_cpu; - } - if (*p) - ++p; - - cpu_list = p; - } - - if (nr_cpus > 0) - cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); - else if (*cpu_list != '\0') - cpus = cpu_map__default_new(); - else - cpus = cpu_map__dummy_new(); -invalid: - free(tmp_cpus); -out: - return cpus; -} - -static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) -{ - struct cpu_map *map; - - map = cpu_map__empty_new(cpus->nr); + map = perf_cpu_map__empty_new(cpus->nr); if (map) { unsigned i; @@ -220,14 +42,14 @@ static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) return map; } -static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask) +static struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask) { - struct cpu_map *map; + struct perf_cpu_map *map; int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE; nr = bitmap_weight(mask->mask, nbits); - map = cpu_map__empty_new(nr); + map = perf_cpu_map__empty_new(nr); if (map) { int cpu, i = 0; @@ -238,15 +60,15 @@ static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask) } -struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) +struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data) { if (data->type == PERF_CPU_MAP__CPUS) return cpu_map__from_entries((struct cpu_map_entries *)data->data); else - return cpu_map__from_mask((struct cpu_map_mask *)data->data); + return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data); } -size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) +size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp) { #define BUFSIZE 1024 char buf[BUFSIZE]; @@ -256,22 +78,9 @@ size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) #undef BUFSIZE } -struct cpu_map *cpu_map__dummy_new(void) +struct perf_cpu_map *perf_cpu_map__empty_new(int nr) { - struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); - - if (cpus != NULL) { - cpus->nr = 1; - cpus->map[0] = -1; - refcount_set(&cpus->refcnt, 1); - } - - return cpus; -} - -struct cpu_map *cpu_map__empty_new(int nr) -{ - struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); + struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); if (cpus != NULL) { int i; @@ -286,28 +95,6 @@ struct cpu_map *cpu_map__empty_new(int nr) return cpus; } -static void cpu_map__delete(struct cpu_map *map) -{ - if (map) { - WARN_ONCE(refcount_read(&map->refcnt) != 0, - "cpu_map refcnt unbalanced\n"); - free(map); - } -} - -struct cpu_map *cpu_map__get(struct cpu_map *map) -{ - if (map) - refcount_inc(&map->refcnt); - return map; -} - -void cpu_map__put(struct cpu_map *map) -{ - if (map && refcount_dec_and_test(&map->refcnt)) - cpu_map__delete(map); -} - static int cpu__get_topology_int(int cpu, const char *name, int *value) { char path[PATH_MAX]; @@ -324,7 +111,7 @@ int cpu_map__get_socket_id(int cpu) return ret ?: value; } -int cpu_map__get_socket(struct cpu_map *map, int idx, void *data __maybe_unused) +int cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data __maybe_unused) { int cpu; @@ -341,11 +128,11 @@ static int cmp_ids(const void *a, const void *b) return *(int *)a - *(int *)b; } -int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu, void *data), +int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, + int (*f)(struct perf_cpu_map *map, int cpu, void *data), void *data) { - struct cpu_map *c; + struct perf_cpu_map *c; int nr = cpus->nr; int cpu, s1, s2; @@ -380,7 +167,7 @@ int cpu_map__get_die_id(int cpu) return ret ?: value; } -int cpu_map__get_die(struct cpu_map *map, int idx, void *data) +int cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data) { int cpu, die_id, s; @@ -419,7 +206,7 @@ int cpu_map__get_core_id(int cpu) return ret ?: value; } -int cpu_map__get_core(struct cpu_map *map, int idx, void *data) +int cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data) { int cpu, s_die; @@ -448,17 +235,17 @@ int cpu_map__get_core(struct cpu_map *map, int idx, void *data) return (s_die << 16) | (cpu & 0xffff); } -int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) +int cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp) { return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL); } -int cpu_map__build_die_map(struct cpu_map *cpus, struct cpu_map **diep) +int cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep) { return cpu_map__build_map(cpus, diep, cpu_map__get_die, NULL); } -int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) +int cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep) { return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL); } @@ -670,29 +457,17 @@ int cpu__setup_cpunode_map(void) return 0; } -bool cpu_map__has(struct cpu_map *cpus, int cpu) +bool cpu_map__has(struct perf_cpu_map *cpus, int cpu) { - return cpu_map__idx(cpus, cpu) != -1; -} - -int cpu_map__idx(struct cpu_map *cpus, int cpu) -{ - int i; - - for (i = 0; i < cpus->nr; ++i) { - if (cpus->map[i] == cpu) - return i; - } - - return -1; + return perf_cpu_map__idx(cpus, cpu) != -1; } -int cpu_map__cpu(struct cpu_map *cpus, int idx) +int cpu_map__cpu(struct perf_cpu_map *cpus, int idx) { return cpus->map[idx]; } -size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size) +size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size) { int i, cpu, start = -1; bool first = true; @@ -744,7 +519,7 @@ static char hex_char(unsigned char val) return '?'; } -size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size) +size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size) { int i, cpu; char *ptr = buf; @@ -784,12 +559,12 @@ size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size) return ptr - buf; } -const struct cpu_map *cpu_map__online(void) /* thread unsafe */ +const struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */ { - static const struct cpu_map *online = NULL; + static const struct perf_cpu_map *online = NULL; if (!online) - online = cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ + online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ return online; } diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 1265f0e33920..2553bef1279d 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -4,40 +4,28 @@ #include <stdio.h> #include <stdbool.h> -#include <linux/refcount.h> +#include <internal/cpumap.h> +#include <perf/cpumap.h> -#include "perf.h" -#include "util/debug.h" +struct perf_record_cpu_map_data; -struct cpu_map { - refcount_t refcnt; - int nr; - int map[]; -}; - -struct cpu_map *cpu_map__new(const char *cpu_list); -struct cpu_map *cpu_map__empty_new(int nr); -struct cpu_map *cpu_map__dummy_new(void); -struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); -struct cpu_map *cpu_map__read(FILE *file); -size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size); -size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size); -size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); +struct perf_cpu_map *perf_cpu_map__empty_new(int nr); +struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data); +size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size); +size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size); +size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu); -int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); +int cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data); int cpu_map__get_die_id(int cpu); -int cpu_map__get_die(struct cpu_map *map, int idx, void *data); +int cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data); int cpu_map__get_core_id(int cpu); -int cpu_map__get_core(struct cpu_map *map, int idx, void *data); -int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); -int cpu_map__build_die_map(struct cpu_map *cpus, struct cpu_map **diep); -int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); -const struct cpu_map *cpu_map__online(void); /* thread unsafe */ - -struct cpu_map *cpu_map__get(struct cpu_map *map); -void cpu_map__put(struct cpu_map *map); +int cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data); +int cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp); +int cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep); +int cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep); +const struct perf_cpu_map *cpu_map__online(void); /* thread unsafe */ -static inline int cpu_map__socket(struct cpu_map *sock, int s) +static inline int cpu_map__socket(struct perf_cpu_map *sock, int s) { if (!sock || s > sock->nr || s < 0) return 0; @@ -59,16 +47,6 @@ static inline int cpu_map__id_to_cpu(int id) return id & 0xffff; } -static inline int cpu_map__nr(const struct cpu_map *map) -{ - return map ? map->nr : 1; -} - -static inline bool cpu_map__empty(const struct cpu_map *map) -{ - return map ? map->map[0] == -1 : true; -} - int cpu__setup_cpunode_map(void); int cpu__max_node(void); @@ -76,11 +54,10 @@ int cpu__max_cpu(void); int cpu__max_present_cpu(void); int cpu__get_node(int cpu); -int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu, void *data), +int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, + int (*f)(struct perf_cpu_map *map, int cpu, void *data), void *data); -int cpu_map__cpu(struct cpu_map *cpus, int idx); -bool cpu_map__has(struct cpu_map *cpus, int cpu); -int cpu_map__idx(struct cpu_map *cpus, int cpu); +int cpu_map__cpu(struct perf_cpu_map *cpus, int idx); +bool cpu_map__has(struct perf_cpu_map *cpus, int cpu); #endif /* __PERF_CPUMAP_H */ diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c index 64336a280967..1b52402a8923 100644 --- a/tools/perf/util/cputopo.c +++ b/tools/perf/util/cputopo.c @@ -3,11 +3,14 @@ #include <sys/utsname.h> #include <inttypes.h> #include <stdlib.h> +#include <string.h> #include <api/fs/fs.h> #include <linux/zalloc.h> +#include <perf/cpumap.h> #include "cputopo.h" #include "cpumap.h" +#include "debug.h" #include "env.h" #define CORE_SIB_FMT \ @@ -176,13 +179,13 @@ struct cpu_topology *cpu_topology__new(void) size_t sz; long ncpus; int ret = -1; - struct cpu_map *map; + struct perf_cpu_map *map; bool has_die = has_die_topology(); ncpus = cpu__max_present_cpu(); /* build online CPU map */ - map = cpu_map__new(NULL); + map = perf_cpu_map__new(NULL); if (map == NULL) { pr_debug("failed to get system cpumap\n"); return NULL; @@ -219,7 +222,7 @@ struct cpu_topology *cpu_topology__new(void) } out_free: - cpu_map__put(map); + perf_cpu_map__put(map); if (ret) { cpu_topology__delete(tp); tp = NULL; @@ -289,7 +292,7 @@ err: struct numa_topology *numa_topology__new(void) { - struct cpu_map *node_map = NULL; + struct perf_cpu_map *node_map = NULL; struct numa_topology *tp = NULL; char path[MAXPATHLEN]; char *buf = NULL; @@ -312,7 +315,7 @@ struct numa_topology *numa_topology__new(void) if (c) *c = '\0'; - node_map = cpu_map__new(buf); + node_map = perf_cpu_map__new(buf); if (!node_map) goto out; @@ -335,7 +338,7 @@ struct numa_topology *numa_topology__new(void) out: free(buf); fclose(fp); - cpu_map__put(node_map); + perf_cpu_map__put(node_map); return tp; } diff --git a/tools/perf/util/cputopo.h b/tools/perf/util/cputopo.h index bae2f1d41856..7bf6b811f715 100644 --- a/tools/perf/util/cputopo.h +++ b/tools/perf/util/cputopo.h @@ -3,7 +3,6 @@ #define __PERF_CPUTOPO_H #include <linux/types.h> -#include "env.h" struct cpu_topology { u32 core_sib; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 3d1c34fc4d68..707afdbd9529 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -21,14 +21,18 @@ #include "cs-etm.h" #include "cs-etm-decoder/cs-etm-decoder.h" #include "debug.h" +#include "dso.h" #include "evlist.h" #include "intlist.h" #include "machine.h" #include "map.h" #include "perf.h" +#include "session.h" +#include "map_symbol.h" +#include "branch.h" #include "symbol.h" +#include "tool.h" #include "thread.h" -#include "thread_map.h" #include "thread-stack.h" #include <tools/libc_compat.h> #include "util.h" @@ -1076,6 +1080,35 @@ bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq) return !!etmq->etm->timeless_decoding; } +static void cs_etm__copy_insn(struct cs_etm_queue *etmq, + u64 trace_chan_id, + const struct cs_etm_packet *packet, + struct perf_sample *sample) +{ + /* + * It's pointless to read instructions for the CS_ETM_DISCONTINUITY + * packet, so directly bail out with 'insn_len' = 0. + */ + if (packet->sample_type == CS_ETM_DISCONTINUITY) { + sample->insn_len = 0; + return; + } + + /* + * T32 instruction size might be 32-bit or 16-bit, decide by calling + * cs_etm__t32_instr_size(). + */ + if (packet->isa == CS_ETM_ISA_T32) + sample->insn_len = cs_etm__t32_instr_size(etmq, trace_chan_id, + sample->ip); + /* Otherwise, A64 and A32 instruction size are always 32-bit. */ + else + sample->insn_len = 4; + + cs_etm__mem_access(etmq, trace_chan_id, sample->ip, + sample->insn_len, (void *)sample->insn); +} + static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, struct cs_etm_traceid_queue *tidq, u64 addr, u64 period) @@ -1097,9 +1130,10 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, sample.period = period; sample.cpu = tidq->packet->cpu; sample.flags = tidq->prev_packet->flags; - sample.insn_len = 1; sample.cpumode = event->sample.header.misc; + cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample); + if (etm->synth_opts.last_branch) { cs_etm__copy_last_branch_rb(etmq, tidq); sample.branch_stack = tidq->last_branch; @@ -1159,6 +1193,9 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, sample.flags = tidq->prev_packet->flags; sample.cpumode = event->sample.header.misc; + cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->prev_packet, + &sample); + /* * perf report cannot handle events without a branch stack */ @@ -1222,15 +1259,15 @@ static int cs_etm__synth_event(struct perf_session *session, static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; struct perf_event_attr attr; bool found = false; u64 id; int err; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == etm->pmu_type) { + if (evsel->core.attr.type == etm->pmu_type) { found = true; break; } @@ -1244,7 +1281,7 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, memset(&attr, 0, sizeof(struct perf_event_attr)); attr.size = sizeof(struct perf_event_attr); attr.type = PERF_TYPE_HARDWARE; - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; if (etm->timeless_decoding) @@ -1252,13 +1289,13 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, else attr.sample_type |= PERF_SAMPLE_TIME; - attr.exclude_user = evsel->attr.exclude_user; - attr.exclude_kernel = evsel->attr.exclude_kernel; - attr.exclude_hv = evsel->attr.exclude_hv; - attr.exclude_host = evsel->attr.exclude_host; - attr.exclude_guest = evsel->attr.exclude_guest; - attr.sample_id_all = evsel->attr.sample_id_all; - attr.read_format = evsel->attr.read_format; + attr.exclude_user = evsel->core.attr.exclude_user; + attr.exclude_kernel = evsel->core.attr.exclude_kernel; + attr.exclude_hv = evsel->core.attr.exclude_hv; + attr.exclude_host = evsel->core.attr.exclude_host; + attr.exclude_guest = evsel->core.attr.exclude_guest; + attr.sample_id_all = evsel->core.attr.sample_id_all; + attr.read_format = evsel->core.attr.read_format; /* create new id val to be a fixed offset from evsel id */ id = evsel->id[0] + 1000000000; @@ -2294,8 +2331,8 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session, static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm) { - struct perf_evsel *evsel; - struct perf_evlist *evlist = etm->session->evlist; + struct evsel *evsel; + struct evlist *evlist = etm->session->evlist; bool timeless_decoding = true; /* @@ -2303,7 +2340,7 @@ static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm) * with the time bit set. */ evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.sample_type & PERF_SAMPLE_TIME)) + if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME)) timeless_decoding = false; } @@ -2337,7 +2374,7 @@ static const char * const cs_etmv4_priv_fmts[] = { [CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n", }; -static void cs_etm__print_auxtrace_info(u64 *val, int num) +static void cs_etm__print_auxtrace_info(__u64 *val, int num) { int i, j, cpu = 0; @@ -2360,7 +2397,7 @@ static void cs_etm__print_auxtrace_info(u64 *val, int num) int cs_etm__process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; struct cs_etm_auxtrace *etm = NULL; struct int_node *inode; unsigned int pmu_type; diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index bc848fd095f4..650ecc2a6349 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -8,9 +8,10 @@ #define INCLUDE__UTIL_PERF_CS_ETM_H__ #include "util/event.h" -#include "util/session.h" #include <linux/bits.h> +struct perf_session; + /* Versionning header in case things need tro change in the future. That way * decoding of old snapshot is still possible. */ diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index ddbcd59f2d9b..0c268449959c 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -413,7 +413,7 @@ static int add_tracepoint_fields_values(struct ctf_writer *cw, static int add_tracepoint_values(struct ctf_writer *cw, struct bt_ctf_event_class *event_class, struct bt_ctf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { struct tep_format_field *common_fields = evsel->tp_format->format.common_fields; @@ -584,10 +584,10 @@ put_len_type: static int add_generic_values(struct ctf_writer *cw, struct bt_ctf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { - u64 type = evsel->attr.sample_type; + u64 type = evsel->core.attr.sample_type; int ret; /* @@ -753,11 +753,11 @@ static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu) } static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { int cpu = 0; - if (evsel->attr.sample_type & PERF_SAMPLE_CPU) + if (evsel->core.attr.sample_type & PERF_SAMPLE_CPU) cpu = sample->cpu; if (cpu > cw->stream_cnt) { @@ -785,7 +785,7 @@ static bool is_flush_needed(struct ctf_stream *cs) static int process_sample_event(struct perf_tool *tool, union perf_event *_event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine __maybe_unused) { struct convert *c = container_of(tool, struct convert, tool); @@ -795,7 +795,7 @@ static int process_sample_event(struct perf_tool *tool, struct bt_ctf_event_class *event_class; struct bt_ctf_event *event; int ret; - unsigned long type = evsel->attr.sample_type; + unsigned long type = evsel->core.attr.sample_type; if (WARN_ONCE(!priv, "Failed to setup all events.\n")) return 0; @@ -820,7 +820,7 @@ static int process_sample_event(struct perf_tool *tool, if (ret) return -1; - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { ret = add_tracepoint_values(cw, event_class, event, evsel, sample); if (ret) @@ -1051,7 +1051,7 @@ static int add_tracepoint_fields_types(struct ctf_writer *cw, } static int add_tracepoint_types(struct ctf_writer *cw, - struct perf_evsel *evsel, + struct evsel *evsel, struct bt_ctf_event_class *class) { struct tep_format_field *common_fields = evsel->tp_format->format.common_fields; @@ -1084,10 +1084,10 @@ static int add_bpf_output_types(struct ctf_writer *cw, return bt_ctf_event_class_add_field(class, seq_type, "raw_data"); } -static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, +static int add_generic_types(struct ctf_writer *cw, struct evsel *evsel, struct bt_ctf_event_class *event_class) { - u64 type = evsel->attr.sample_type; + u64 type = evsel->core.attr.sample_type; /* * missing: @@ -1150,14 +1150,14 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, return 0; } -static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) +static int add_event(struct ctf_writer *cw, struct evsel *evsel) { struct bt_ctf_event_class *event_class; struct evsel_priv *priv; const char *name = perf_evsel__name(evsel); int ret; - pr("Adding event '%s' (type %d)\n", name, evsel->attr.type); + pr("Adding event '%s' (type %d)\n", name, evsel->core.attr.type); event_class = bt_ctf_event_class_create(name); if (!event_class) @@ -1167,7 +1167,7 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) if (ret) goto err; - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { ret = add_tracepoint_types(cw, evsel, event_class); if (ret) goto err; @@ -1201,8 +1201,8 @@ err: static int setup_events(struct ctf_writer *cw, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; int ret; evlist__for_each_entry(evlist, evsel) { @@ -1308,8 +1308,8 @@ static int setup_non_sample_events(struct ctf_writer *cw, static void cleanup_events(struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { struct evsel_priv *priv; @@ -1319,7 +1319,7 @@ static void cleanup_events(struct perf_session *session) zfree(&evsel->priv); } - perf_evlist__delete(evlist); + evlist__delete(evlist); session->evlist = NULL; } diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 1d1b97a92c3f..e75c3a279fe8 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> #include <linux/kernel.h> +#include <linux/string.h> #include <linux/zalloc.h> #include <sys/types.h> #include <sys/stat.h> @@ -9,7 +10,6 @@ #include <unistd.h> #include <string.h> #include <asm/bug.h> -#include <sys/types.h> #include <dirent.h> #include "data.h" diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index ffbb3e7d3288..752227b265e7 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -7,6 +7,7 @@ #include <errno.h> #include <stdlib.h> +#include "dso.h" #include "evsel.h" #include "machine.h" #include "thread.h" @@ -32,7 +33,7 @@ void db_export__exit(struct db_export *dbe) dbe->crp = NULL; } -int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel) +int db_export__evsel(struct db_export *dbe, struct evsel *evsel) { if (evsel->db_id) return 0; @@ -209,7 +210,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe, struct machine *machine, struct thread *thread, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { u64 kernel_start = machine__kernel_start(machine); struct call_path *current = &dbe->cpr->call_path; @@ -341,7 +342,7 @@ static int db_export__threads(struct db_export *dbe, struct thread *thread, } int db_export__sample(struct db_export *dbe, union perf_event *event, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct addr_location *al) { struct thread *thread = al->thread; @@ -388,8 +389,8 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, } } - if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && - sample_addr_correlates_sym(&evsel->attr)) { + if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && + sample_addr_correlates_sym(&evsel->core.attr)) { struct addr_location addr_al; thread__resolve(thread, &addr_al, sample); diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h index ba1f62a5fe10..9c3d38f5a40d 100644 --- a/tools/perf/util/db-export.h +++ b/tools/perf/util/db-export.h @@ -10,7 +10,7 @@ #include <linux/types.h> #include <linux/list.h> -struct perf_evsel; +struct evsel; struct machine; struct thread; struct comm; @@ -25,7 +25,7 @@ struct call_return; struct export_sample { union perf_event *event; struct perf_sample *sample; - struct perf_evsel *evsel; + struct evsel *evsel; struct addr_location *al; u64 db_id; u64 comm_db_id; @@ -39,7 +39,7 @@ struct export_sample { }; struct db_export { - int (*export_evsel)(struct db_export *dbe, struct perf_evsel *evsel); + int (*export_evsel)(struct db_export *dbe, struct evsel *evsel); int (*export_machine)(struct db_export *dbe, struct machine *machine); int (*export_thread)(struct db_export *dbe, struct thread *thread, u64 main_thread_db_id, struct machine *machine); @@ -79,7 +79,7 @@ struct db_export { int db_export__init(struct db_export *dbe); void db_export__exit(struct db_export *dbe); -int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel); +int db_export__evsel(struct db_export *dbe, struct evsel *evsel); int db_export__machine(struct db_export *dbe, struct machine *machine); int db_export__thread(struct db_export *dbe, struct thread *thread, struct machine *machine, struct thread *main_thread); @@ -96,7 +96,7 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym, int db_export__branch_type(struct db_export *dbe, u32 branch_type, const char *name); int db_export__sample(struct db_export *dbe, union perf_event *event, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct addr_location *al); int db_export__branch_types(struct db_export *dbe); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 3780fe42453b..a1b59bd35519 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* For general debugging purposes */ -#include "../perf.h" - #include <inttypes.h> #include <string.h> #include <stdarg.h> @@ -10,17 +8,19 @@ #include <stdlib.h> #include <sys/wait.h> #include <api/debug.h> +#include <linux/kernel.h> #include <linux/time64.h> #ifdef HAVE_BACKTRACE_SUPPORT #include <execinfo.h> #endif -#include "cache.h" #include "color.h" #include "event.h" #include "debug.h" #include "print_binary.h" #include "util.h" #include "target.h" +#include "ui/helpline.h" +#include "ui/ui.h" #include <linux/ctype.h> diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 77445dfc5c7d..b2deee987ffa 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -4,11 +4,7 @@ #define __PERF_DEBUG_H #include <stdbool.h> -#include <string.h> #include <linux/compiler.h> -#include "event.h" -#include "../ui/helpline.h" -#include "../ui/progress.h" #include "../ui/util.h" extern int verbose; @@ -42,6 +38,8 @@ extern int debug_data_convert; #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ +union perf_event; + int dump_printf(const char *fmt, ...) __printf(1, 2); void trace_event(union perf_event *event); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index ebc9d46c15a7..e11ddf86f2b3 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -10,16 +10,18 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> -#include <libgen.h> +#include <stdlib.h> #include <bpf/libbpf.h> #include "bpf-event.h" #include "compress.h" +#include "env.h" #include "namespaces.h" #include "path.h" #include "map.h" #include "symbol.h" #include "srcline.h" #include "dso.h" +#include "dsos.h" #include "machine.h" #include "auxtrace.h" #include "util.h" /* O_CLOEXEC for older systems */ @@ -1094,66 +1096,6 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name, return dso; } -/* - * Find a matching entry and/or link current entry to RB tree. - * Either one of the dso or name parameter must be non-NULL or the - * function will not work. - */ -static struct dso *__dso__findlink_by_longname(struct rb_root *root, - struct dso *dso, const char *name) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - - if (!name) - name = dso->long_name; - /* - * Find node with the matching name - */ - while (*p) { - struct dso *this = rb_entry(*p, struct dso, rb_node); - int rc = strcmp(name, this->long_name); - - parent = *p; - if (rc == 0) { - /* - * In case the new DSO is a duplicate of an existing - * one, print a one-time warning & put the new entry - * at the end of the list of duplicates. - */ - if (!dso || (dso == this)) - return this; /* Find matching dso */ - /* - * The core kernel DSOs may have duplicated long name. - * In this case, the short name should be different. - * Comparing the short names to differentiate the DSOs. - */ - rc = strcmp(dso->short_name, this->short_name); - if (rc == 0) { - pr_err("Duplicated dso name: %s\n", name); - return NULL; - } - } - if (rc < 0) - p = &parent->rb_left; - else - p = &parent->rb_right; - } - if (dso) { - /* Add new node and rebalance tree */ - rb_link_node(&dso->rb_node, parent, p); - rb_insert_color(&dso->rb_node, root); - dso->root = root; - } - return NULL; -} - -static inline struct dso *__dso__find_by_longname(struct rb_root *root, - const char *name) -{ - return __dso__findlink_by_longname(root, NULL, name); -} - void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) { struct rb_root *root = dso->root; @@ -1167,7 +1109,7 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) if (root) { rb_erase(&dso->rb_node, root); /* - * __dso__findlink_by_longname() isn't guaranteed to add it + * __dsos__findnew_link_by_longname() isn't guaranteed to add it * back, so a clean removal is required here. */ RB_CLEAR_NODE(&dso->rb_node); @@ -1179,7 +1121,7 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) dso->long_name_allocated = name_allocated; if (root) - __dso__findlink_by_longname(root, dso, NULL); + __dsos__findnew_link_by_longname(root, dso, NULL); } void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) @@ -1195,38 +1137,6 @@ void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) dso->short_name_allocated = name_allocated; } -static void dso__set_basename(struct dso *dso) -{ - char *base, *lname; - int tid; - - if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) { - if (asprintf(&base, "[JIT] tid %d", tid) < 0) - return; - } else { - /* - * basename() may modify path buffer, so we must pass - * a copy. - */ - lname = strdup(dso->long_name); - if (!lname) - return; - - /* - * basename() may return a pointer to internal - * storage which is reused in subsequent calls - * so copy the result. - */ - base = strdup(basename(lname)); - - free(lname); - - if (!base) - return; - } - dso__set_short_name(dso, base, true); -} - int dso__name_len(const struct dso *dso) { if (!dso) @@ -1377,143 +1287,6 @@ int dso__kernel_module_get_build_id(struct dso *dso, return 0; } -bool __dsos__read_build_ids(struct list_head *head, bool with_hits) -{ - bool have_build_id = false; - struct dso *pos; - struct nscookie nsc; - - list_for_each_entry(pos, head, node) { - if (with_hits && !pos->hit && !dso__is_vdso(pos)) - continue; - if (pos->has_build_id) { - have_build_id = true; - continue; - } - nsinfo__mountns_enter(pos->nsinfo, &nsc); - if (filename__read_build_id(pos->long_name, pos->build_id, - sizeof(pos->build_id)) > 0) { - have_build_id = true; - pos->has_build_id = true; - } - nsinfo__mountns_exit(&nsc); - } - - return have_build_id; -} - -void __dsos__add(struct dsos *dsos, struct dso *dso) -{ - list_add_tail(&dso->node, &dsos->head); - __dso__findlink_by_longname(&dsos->root, dso, NULL); - /* - * It is now in the linked list, grab a reference, then garbage collect - * this when needing memory, by looking at LRU dso instances in the - * list with atomic_read(&dso->refcnt) == 1, i.e. no references - * anywhere besides the one for the list, do, under a lock for the - * list: remove it from the list, then a dso__put(), that probably will - * be the last and will then call dso__delete(), end of life. - * - * That, or at the end of the 'struct machine' lifetime, when all - * 'struct dso' instances will be removed from the list, in - * dsos__exit(), if they have no other reference from some other data - * structure. - * - * E.g.: after processing a 'perf.data' file and storing references - * to objects instantiated while processing events, we will have - * references to the 'thread', 'map', 'dso' structs all from 'struct - * hist_entry' instances, but we may not need anything not referenced, - * so we might as well call machines__exit()/machines__delete() and - * garbage collect it. - */ - dso__get(dso); -} - -void dsos__add(struct dsos *dsos, struct dso *dso) -{ - down_write(&dsos->lock); - __dsos__add(dsos, dso); - up_write(&dsos->lock); -} - -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) -{ - struct dso *pos; - - if (cmp_short) { - list_for_each_entry(pos, &dsos->head, node) - if (strcmp(pos->short_name, name) == 0) - return pos; - return NULL; - } - return __dso__find_by_longname(&dsos->root, name); -} - -struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) -{ - struct dso *dso; - down_read(&dsos->lock); - dso = __dsos__find(dsos, name, cmp_short); - up_read(&dsos->lock); - return dso; -} - -struct dso *__dsos__addnew(struct dsos *dsos, const char *name) -{ - struct dso *dso = dso__new(name); - - if (dso != NULL) { - __dsos__add(dsos, dso); - dso__set_basename(dso); - /* Put dso here because __dsos_add already got it */ - dso__put(dso); - } - return dso; -} - -struct dso *__dsos__findnew(struct dsos *dsos, const char *name) -{ - struct dso *dso = __dsos__find(dsos, name, false); - - return dso ? dso : __dsos__addnew(dsos, name); -} - -struct dso *dsos__findnew(struct dsos *dsos, const char *name) -{ - struct dso *dso; - down_write(&dsos->lock); - dso = dso__get(__dsos__findnew(dsos, name)); - up_write(&dsos->lock); - return dso; -} - -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm) -{ - struct dso *pos; - size_t ret = 0; - - list_for_each_entry(pos, head, node) { - if (skip && skip(pos, parm)) - continue; - ret += dso__fprintf_buildid(pos, fp); - ret += fprintf(fp, " %s\n", pos->long_name); - } - return ret; -} - -size_t __dsos__fprintf(struct list_head *head, FILE *fp) -{ - struct dso *pos; - size_t ret = 0; - - list_for_each_entry(pos, head, node) { - ret += dso__fprintf(pos, fp); - } - - return ret; -} - size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) { char sbuild_id[SBUILD_ID_SIZE]; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 6e3f63781e51..e4dddb76770d 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -2,13 +2,13 @@ #ifndef __PERF_DSO #define __PERF_DSO +#include <pthread.h> #include <linux/refcount.h> #include <linux/types.h> #include <linux/rbtree.h> #include <sys/types.h> #include <stdbool.h> #include <stdio.h> -#include "rwsem.h" #include <linux/bitops.h> #include "build-id.h" @@ -16,6 +16,9 @@ struct machine; struct map; struct perf_env; +#define DSO__NAME_KALLSYMS "[kernel.kallsyms]" +#define DSO__NAME_KCORE "[kernel.kcore]" + enum dso_binary_type { DSO_BINARY_TYPE__KALLSYMS = 0, DSO_BINARY_TYPE__GUEST_KALLSYMS, @@ -126,16 +129,6 @@ struct dso_cache { char data[0]; }; -/* - * DSOs are put into both a list for fast iteration and rbtree for fast - * long name lookup. - */ -struct dsos { - struct list_head head; - struct rb_root root; /* rbtree root sorted by long name */ - struct rw_semaphore lock; -}; - struct auxtrace_cache; struct dso { @@ -344,21 +337,8 @@ struct map *dso__new_map(const char *name); struct dso *machine__findnew_kernel(struct machine *machine, const char *name, const char *short_name, int dso_type); -void __dsos__add(struct dsos *dsos, struct dso *dso); -void dsos__add(struct dsos *dsos, struct dso *dso); -struct dso *__dsos__addnew(struct dsos *dsos, const char *name); -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); -struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); -struct dso *__dsos__findnew(struct dsos *dsos, const char *name); -struct dso *dsos__findnew(struct dsos *dsos, const char *name); -bool __dsos__read_build_ids(struct list_head *head, bool with_hits); - void dso__reset_find_symbol_cache(struct dso *dso); -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm); -size_t __dsos__fprintf(struct list_head *head, FILE *fp); - size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); size_t dso__fprintf_symbols_by_name(struct dso *dso, FILE *fp); size_t dso__fprintf(struct dso *dso, FILE *fp); diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c new file mode 100644 index 000000000000..3ea80d203587 --- /dev/null +++ b/tools/perf/util/dsos.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "debug.h" +#include "dsos.h" +#include "dso.h" +#include "vdso.h" +#include "namespaces.h" +#include <libgen.h> +#include <stdlib.h> +#include <string.h> +#include <symbol.h> // filename__read_build_id + +bool __dsos__read_build_ids(struct list_head *head, bool with_hits) +{ + bool have_build_id = false; + struct dso *pos; + struct nscookie nsc; + + list_for_each_entry(pos, head, node) { + if (with_hits && !pos->hit && !dso__is_vdso(pos)) + continue; + if (pos->has_build_id) { + have_build_id = true; + continue; + } + nsinfo__mountns_enter(pos->nsinfo, &nsc); + if (filename__read_build_id(pos->long_name, pos->build_id, + sizeof(pos->build_id)) > 0) { + have_build_id = true; + pos->has_build_id = true; + } + nsinfo__mountns_exit(&nsc); + } + + return have_build_id; +} + +/* + * Find a matching entry and/or link current entry to RB tree. + * Either one of the dso or name parameter must be non-NULL or the + * function will not work. + */ +struct dso *__dsos__findnew_link_by_longname(struct rb_root *root, struct dso *dso, const char *name) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + + if (!name) + name = dso->long_name; + /* + * Find node with the matching name + */ + while (*p) { + struct dso *this = rb_entry(*p, struct dso, rb_node); + int rc = strcmp(name, this->long_name); + + parent = *p; + if (rc == 0) { + /* + * In case the new DSO is a duplicate of an existing + * one, print a one-time warning & put the new entry + * at the end of the list of duplicates. + */ + if (!dso || (dso == this)) + return this; /* Find matching dso */ + /* + * The core kernel DSOs may have duplicated long name. + * In this case, the short name should be different. + * Comparing the short names to differentiate the DSOs. + */ + rc = strcmp(dso->short_name, this->short_name); + if (rc == 0) { + pr_err("Duplicated dso name: %s\n", name); + return NULL; + } + } + if (rc < 0) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + if (dso) { + /* Add new node and rebalance tree */ + rb_link_node(&dso->rb_node, parent, p); + rb_insert_color(&dso->rb_node, root); + dso->root = root; + } + return NULL; +} + +void __dsos__add(struct dsos *dsos, struct dso *dso) +{ + list_add_tail(&dso->node, &dsos->head); + __dsos__findnew_link_by_longname(&dsos->root, dso, NULL); + /* + * It is now in the linked list, grab a reference, then garbage collect + * this when needing memory, by looking at LRU dso instances in the + * list with atomic_read(&dso->refcnt) == 1, i.e. no references + * anywhere besides the one for the list, do, under a lock for the + * list: remove it from the list, then a dso__put(), that probably will + * be the last and will then call dso__delete(), end of life. + * + * That, or at the end of the 'struct machine' lifetime, when all + * 'struct dso' instances will be removed from the list, in + * dsos__exit(), if they have no other reference from some other data + * structure. + * + * E.g.: after processing a 'perf.data' file and storing references + * to objects instantiated while processing events, we will have + * references to the 'thread', 'map', 'dso' structs all from 'struct + * hist_entry' instances, but we may not need anything not referenced, + * so we might as well call machines__exit()/machines__delete() and + * garbage collect it. + */ + dso__get(dso); +} + +void dsos__add(struct dsos *dsos, struct dso *dso) +{ + down_write(&dsos->lock); + __dsos__add(dsos, dso); + up_write(&dsos->lock); +} + +struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) +{ + struct dso *pos; + + if (cmp_short) { + list_for_each_entry(pos, &dsos->head, node) + if (strcmp(pos->short_name, name) == 0) + return pos; + return NULL; + } + return __dsos__findnew_by_longname(&dsos->root, name); +} + +struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) +{ + struct dso *dso; + down_read(&dsos->lock); + dso = __dsos__find(dsos, name, cmp_short); + up_read(&dsos->lock); + return dso; +} + +static void dso__set_basename(struct dso *dso) +{ + char *base, *lname; + int tid; + + if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) { + if (asprintf(&base, "[JIT] tid %d", tid) < 0) + return; + } else { + /* + * basename() may modify path buffer, so we must pass + * a copy. + */ + lname = strdup(dso->long_name); + if (!lname) + return; + + /* + * basename() may return a pointer to internal + * storage which is reused in subsequent calls + * so copy the result. + */ + base = strdup(basename(lname)); + + free(lname); + + if (!base) + return; + } + dso__set_short_name(dso, base, true); +} + +struct dso *__dsos__addnew(struct dsos *dsos, const char *name) +{ + struct dso *dso = dso__new(name); + + if (dso != NULL) { + __dsos__add(dsos, dso); + dso__set_basename(dso); + /* Put dso here because __dsos_add already got it */ + dso__put(dso); + } + return dso; +} + +struct dso *__dsos__findnew(struct dsos *dsos, const char *name) +{ + struct dso *dso = __dsos__find(dsos, name, false); + + return dso ? dso : __dsos__addnew(dsos, name); +} + +struct dso *dsos__findnew(struct dsos *dsos, const char *name) +{ + struct dso *dso; + down_write(&dsos->lock); + dso = dso__get(__dsos__findnew(dsos, name)); + up_write(&dsos->lock); + return dso; +} + +size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm) +{ + struct dso *pos; + size_t ret = 0; + + list_for_each_entry(pos, head, node) { + if (skip && skip(pos, parm)) + continue; + ret += dso__fprintf_buildid(pos, fp); + ret += fprintf(fp, " %s\n", pos->long_name); + } + return ret; +} + +size_t __dsos__fprintf(struct list_head *head, FILE *fp) +{ + struct dso *pos; + size_t ret = 0; + + list_for_each_entry(pos, head, node) { + ret += dso__fprintf(pos, fp); + } + + return ret; +} diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h new file mode 100644 index 000000000000..32f1fbee0feb --- /dev/null +++ b/tools/perf/util/dsos.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_DSOS +#define __PERF_DSOS + +#include <stdbool.h> +#include <stdio.h> +#include <linux/list.h> +#include <linux/rbtree.h> +#include "rwsem.h" + +struct dso; + +/* + * DSOs are put into both a list for fast iteration and rbtree for fast + * long name lookup. + */ +struct dsos { + struct list_head head; + struct rb_root root; /* rbtree root sorted by long name */ + struct rw_semaphore lock; +}; + +void __dsos__add(struct dsos *dsos, struct dso *dso); +void dsos__add(struct dsos *dsos, struct dso *dso); +struct dso *__dsos__addnew(struct dsos *dsos, const char *name); +struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); +struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); +struct dso *__dsos__findnew(struct dsos *dsos, const char *name); +struct dso *dsos__findnew(struct dsos *dsos, const char *name); + +struct dso *__dsos__findnew_link_by_longname(struct rb_root *root, struct dso *dso, const char *name); + +static inline struct dso *__dsos__findnew_by_longname(struct rb_root *root, const char *name) +{ + return __dsos__findnew_link_by_longname(root, NULL, name); +} + +bool __dsos__read_build_ids(struct list_head *head, bool with_hits); + +size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm); +size_t __dsos__fprintf(struct list_head *head, FILE *fp); + +#endif /* __PERF_DSOS */ diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 03b2de1f5a35..df6cee5c071f 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -9,6 +9,7 @@ #include <stdlib.h> #include "debug.h" #include "dwarf-aux.h" +#include "strbuf.h" #include "string2.h" /** diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 0489b0cf8e2c..f204e5892403 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -10,6 +10,8 @@ #include <elfutils/libdwfl.h> #include <elfutils/version.h> +struct strbuf; + /* Find the realpath of the target file */ const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname); diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 9909ec40c6d2..3baca06786fb 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "cpumap.h" +#include "debug.h" #include "env.h" #include <linux/ctype.h> #include <linux/zalloc.h> @@ -8,6 +9,7 @@ #include <sys/utsname.h> #include <bpf/libbpf.h> #include <stdlib.h> +#include <string.h> struct perf_env perf_env; @@ -179,7 +181,7 @@ void perf_env__exit(struct perf_env *env) zfree(&env->cpu); for (i = 0; i < env->nr_numa_nodes; i++) - cpu_map__put(env->numa_nodes[i].map); + perf_cpu_map__put(env->numa_nodes[i].map); zfree(&env->numa_nodes); for (i = 0; i < env->caches_cnt; i++) diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index d5d9865aa812..d8e083d42610 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -27,7 +27,7 @@ struct numa_node { u32 node; u64 mem_total; u64 mem_free; - struct cpu_map *map; + struct perf_cpu_map *map; }; struct memory_node { diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index f1f4848947ce..f4afbb858ebb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0 #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -12,6 +11,7 @@ #include <api/fs/fs.h> #include <linux/perf_event.h> #include <linux/zalloc.h> +#include "dso.h" #include "event.h" #include "debug.h" #include "hist.h" @@ -21,6 +21,7 @@ #include "strlist.h" #include "thread.h" #include "thread_map.h" +#include "time-utils.h" #include <linux/ctype.h> #include "map.h" #include "symbol.h" @@ -29,6 +30,8 @@ #include "stat.h" #include "session.h" #include "bpf-event.h" +#include "tool.h" +#include "../perf.h" #define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 @@ -387,7 +390,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool, strcpy(execname, ""); /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n", + n = sscanf(bf, "%"PRI_lx64"-%"PRI_lx64" %s %"PRI_lx64" %x:%x %u %[^\n]\n", &event->mmap2.start, &event->mmap2.len, prot, &event->mmap2.pgoff, &event->mmap2.maj, &event->mmap2.min, @@ -616,7 +619,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, } int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool mmap_data) @@ -647,7 +650,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, fork_event, namespaces_event, - thread_map__pid(threads, thread), 0, + perf_thread_map__pid(threads, thread), 0, process, tool, machine, mmap_data)) { err = -1; @@ -658,12 +661,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, * comm.pid is set to thread group id by * perf_event__synthesize_comm */ - if ((int) comm_event->comm.pid != thread_map__pid(threads, thread)) { + if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { bool need_leader = true; /* is thread group leader in thread_map? */ for (j = 0; j < threads->nr; ++j) { - if ((int) comm_event->comm.pid == thread_map__pid(threads, j)) { + if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { need_leader = false; break; } @@ -913,11 +916,13 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, int err; union perf_event *event; - if (symbol_conf.kptr_restrict) - return -1; if (map == NULL) return -1; + kmap = map__kmap(map); + if (!kmap->ref_reloc_sym) + return -1; + /* * We should get this from /sys/kernel/sections/.text, but till that is * available use this, and after it is use this as a fallback for older @@ -940,7 +945,6 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; } - kmap = map__kmap(map); size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; size = PERF_ALIGN(size, sizeof(u64)); @@ -972,7 +976,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, } int perf_event__synthesize_thread_map2(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine) { @@ -991,13 +995,13 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, event->thread_map.nr = threads->nr; for (i = 0; i < threads->nr; i++) { - struct thread_map_event_entry *entry = &event->thread_map.entries[i]; - char *comm = thread_map__comm(threads, i); + struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; + char *comm = perf_thread_map__comm(threads, i); if (!comm) comm = (char *) ""; - entry->pid = thread_map__pid(threads, i); + entry->pid = perf_thread_map__pid(threads, i); strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); } @@ -1008,7 +1012,7 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, } static void synthesize_cpus(struct cpu_map_entries *cpus, - struct cpu_map *map) + struct perf_cpu_map *map) { int i; @@ -1018,8 +1022,8 @@ static void synthesize_cpus(struct cpu_map_entries *cpus, cpus->cpu[i] = map->map[i]; } -static void synthesize_mask(struct cpu_map_mask *mask, - struct cpu_map *map, int max) +static void synthesize_mask(struct perf_record_record_cpu_map *mask, + struct perf_cpu_map *map, int max) { int i; @@ -1030,12 +1034,12 @@ static void synthesize_mask(struct cpu_map_mask *mask, set_bit(map->map[i], mask->mask); } -static size_t cpus_size(struct cpu_map *map) +static size_t cpus_size(struct perf_cpu_map *map) { return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); } -static size_t mask_size(struct cpu_map *map, int *max) +static size_t mask_size(struct perf_cpu_map *map, int *max) { int i; @@ -1049,26 +1053,26 @@ static size_t mask_size(struct cpu_map *map, int *max) *max = bit; } - return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long); + return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); } -void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max) +void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) { size_t size_cpus, size_mask; - bool is_dummy = cpu_map__empty(map); + bool is_dummy = perf_cpu_map__empty(map); /* * Both array and mask data have variable size based * on the number of cpus and their actual values. - * The size of the 'struct cpu_map_data' is: + * The size of the 'struct perf_record_cpu_map_data' is: * * array = size of 'struct cpu_map_entries' + * number of cpus * sizeof(u64) * - * mask = size of 'struct cpu_map_mask' + + * mask = size of 'struct perf_record_record_cpu_map' + * maximum cpu bit converted to size of longs * - * and finaly + the size of 'struct cpu_map_data'. + * and finaly + the size of 'struct perf_record_cpu_map_data'. */ size_cpus = cpus_size(map); size_mask = mask_size(map, max); @@ -1081,12 +1085,12 @@ void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max *type = PERF_CPU_MAP__MASK; } - *size += sizeof(struct cpu_map_data); + *size += sizeof(struct perf_record_cpu_map_data); *size = PERF_ALIGN(*size, sizeof(u64)); return zalloc(*size); } -void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, +void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, u16 type, int max) { data->type = type; @@ -1096,16 +1100,16 @@ void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, synthesize_cpus((struct cpu_map_entries *) data->data, map); break; case PERF_CPU_MAP__MASK: - synthesize_mask((struct cpu_map_mask *) data->data, map, max); + synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); default: break; }; } -static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) +static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) { - size_t size = sizeof(struct cpu_map_event); - struct cpu_map_event *event; + size_t size = sizeof(struct perf_record_cpu_map); + struct perf_record_cpu_map *event; int max; u16 type; @@ -1122,11 +1126,11 @@ static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) } int perf_event__synthesize_cpu_map(struct perf_tool *tool, - struct cpu_map *map, + struct perf_cpu_map *map, perf_event__handler_t process, struct machine *machine) { - struct cpu_map_event *event; + struct perf_record_cpu_map *event; int err; event = cpu_map_event__new(map); @@ -1144,7 +1148,7 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - struct stat_config_event *event; + struct perf_record_stat_config *event; int size, i = 0, err; size = sizeof(*event); @@ -1183,7 +1187,7 @@ int perf_event__synthesize_stat(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - struct stat_event event; + struct perf_record_stat event; event.header.type = PERF_RECORD_STAT; event.header.size = sizeof(event); @@ -1204,7 +1208,7 @@ int perf_event__synthesize_stat_round(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - struct stat_round_event event; + struct perf_record_stat_round event; event.header.type = PERF_RECORD_STAT_ROUND; event.header.size = sizeof(event); @@ -1217,7 +1221,7 @@ int perf_event__synthesize_stat_round(struct perf_tool *tool, } void perf_event__read_stat_config(struct perf_stat_config *config, - struct stat_config_event *event) + struct perf_record_stat_config *event) { unsigned i; @@ -1234,7 +1238,7 @@ void perf_event__read_stat_config(struct perf_stat_config *config, CASE(INTERVAL, interval) #undef CASE default: - pr_warning("unknown stat config term %" PRIu64 "\n", + pr_warning("unknown stat config term %" PRI_lu64 "\n", event->data[i].tag); } } @@ -1343,17 +1347,17 @@ int perf_event__process_ksymbol(struct perf_tool *tool __maybe_unused, return machine__process_ksymbol(machine, event, sample); } -int perf_event__process_bpf_event(struct perf_tool *tool __maybe_unused, - union perf_event *event, - struct perf_sample *sample __maybe_unused, - struct machine *machine) +int perf_event__process_bpf(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine) { - return machine__process_bpf_event(machine, event, sample); + return machine__process_bpf(machine, event, sample); } size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) { - return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", + return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64 "]: %c %s\n", event->mmap.pid, event->mmap.tid, event->mmap.start, event->mmap.len, event->mmap.pgoff, (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', @@ -1362,8 +1366,8 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) { - return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 - " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n", + return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64 + " %02x:%02x %"PRI_lu64" %"PRI_lu64"]: %c%c%c%c %s\n", event->mmap2.pid, event->mmap2.tid, event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, event->mmap2.min, event->mmap2.ino, @@ -1377,7 +1381,7 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) { - struct thread_map *threads = thread_map__new_event(&event->thread_map); + struct perf_thread_map *threads = thread_map__new_event(&event->thread_map); size_t ret; ret = fprintf(fp, " nr: "); @@ -1387,13 +1391,13 @@ size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) else ret += fprintf(fp, "failed to get threads from event\n"); - thread_map__put(threads); + perf_thread_map__put(threads); return ret; } size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) { - struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); + struct perf_cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); size_t ret; ret = fprintf(fp, ": "); @@ -1403,7 +1407,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) else ret += fprintf(fp, "failed to get cpumap from event\n"); - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return ret; } @@ -1448,7 +1452,7 @@ int perf_event__process_exit(struct perf_tool *tool __maybe_unused, size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) { - return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s%s]\n", + return fprintf(fp, " offset: %#"PRI_lx64" size: %#"PRI_lx64" flags: %#"PRI_lx64" [%s%s%s]\n", event->aux.aux_offset, event->aux.aux_size, event->aux.flags, event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "", @@ -1480,22 +1484,21 @@ size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp) static size_t perf_event__fprintf_lost(union perf_event *event, FILE *fp) { - return fprintf(fp, " lost %" PRIu64 "\n", event->lost.lost); + return fprintf(fp, " lost %" PRI_lu64 "\n", event->lost.lost); } size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp) { - return fprintf(fp, " addr %" PRIx64 " len %u type %u flags 0x%x name %s\n", - event->ksymbol_event.addr, event->ksymbol_event.len, - event->ksymbol_event.ksym_type, - event->ksymbol_event.flags, event->ksymbol_event.name); + return fprintf(fp, " addr %" PRI_lx64 " len %u type %u flags 0x%x name %s\n", + event->ksymbol.addr, event->ksymbol.len, + event->ksymbol.ksym_type, + event->ksymbol.flags, event->ksymbol.name); } -size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp) +size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp) { return fprintf(fp, " type %u, flags %u, id %u\n", - event->bpf_event.type, event->bpf_event.flags, - event->bpf_event.id); + event->bpf.type, event->bpf.flags, event->bpf.id); } size_t perf_event__fprintf(union perf_event *event, FILE *fp) @@ -1537,7 +1540,7 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) ret += perf_event__fprintf_ksymbol(event, fp); break; case PERF_RECORD_BPF_EVENT: - ret += perf_event__fprintf_bpf_event(event, fp); + ret += perf_event__fprintf_bpf(event, fp); break; default: ret += fprintf(fp, "\n"); diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1f1da6082806..47ad81d47b1a 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -1,114 +1,39 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __PERF_RECORD_H #define __PERF_RECORD_H - -#include <limits.h> +/* + * The linux/stddef.h isn't need here, but is needed for __always_inline used + * in files included from uapi/linux/perf_event.h such as + * /usr/include/linux/swab.h and /usr/include/linux/byteorder/little_endian.h, + * detected in at least musl libc, used in Alpine Linux. -acme + */ #include <stdio.h> -#include <linux/kernel.h> -#include <linux/bpf.h> -#include <linux/perf_event.h> +#include <linux/stddef.h> +#include <perf/event.h> +#include <linux/types.h> -#include "../perf.h" -#include "build-id.h" #include "perf_regs.h" -struct mmap_event { - struct perf_event_header header; - u32 pid, tid; - u64 start; - u64 len; - u64 pgoff; - char filename[PATH_MAX]; -}; - -struct mmap2_event { - struct perf_event_header header; - u32 pid, tid; - u64 start; - u64 len; - u64 pgoff; - u32 maj; - u32 min; - u64 ino; - u64 ino_generation; - u32 prot; - u32 flags; - char filename[PATH_MAX]; -}; - -struct comm_event { - struct perf_event_header header; - u32 pid, tid; - char comm[16]; -}; - -struct namespaces_event { - struct perf_event_header header; - u32 pid, tid; - u64 nr_namespaces; - struct perf_ns_link_info link_info[]; -}; - -struct fork_event { - struct perf_event_header header; - u32 pid, ppid; - u32 tid, ptid; - u64 time; -}; - -struct lost_event { - struct perf_event_header header; - u64 id; - u64 lost; -}; - -struct lost_samples_event { - struct perf_event_header header; - u64 lost; -}; +struct dso; +struct machine; +struct perf_event_attr; +#ifdef __LP64__ /* - * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID + * /usr/include/inttypes.h uses just 'lu' for PRIu64, but we end up defining + * __u64 as long long unsigned int, and then -Werror=format= kicks in and + * complains of the mismatched types, so use these two special extra PRI + * macros to overcome that. */ -struct read_event { - struct perf_event_header header; - u32 pid, tid; - u64 value; - u64 time_enabled; - u64 time_running; - u64 id; -}; - -struct throttle_event { - struct perf_event_header header; - u64 time; - u64 id; - u64 stream_id; -}; - -#ifndef KSYM_NAME_LEN -#define KSYM_NAME_LEN 256 +#define PRI_lu64 "l" PRIu64 +#define PRI_lx64 "l" PRIx64 +#define PRI_ld64 "l" PRId64 +#else +#define PRI_lu64 PRIu64 +#define PRI_lx64 PRIx64 +#define PRI_ld64 PRId64 #endif -struct ksymbol_event { - struct perf_event_header header; - u64 addr; - u32 len; - u16 ksym_type; - u16 flags; - char name[KSYM_NAME_LEN]; -}; - -struct bpf_event { - struct perf_event_header header; - u16 type; - u16 flags; - u32 id; - - /* for bpf_prog types */ - u8 tag[BPF_TAG_SIZE]; // prog tag -}; - #define PERF_SAMPLE_MASK \ (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ @@ -119,11 +44,6 @@ struct bpf_event { /* perf sample has 16 bits size limit */ #define PERF_SAMPLE_MAX_SIZE (1 << 16) -struct sample_event { - struct perf_event_header header; - u64 array[]; -}; - struct regs_dump { u64 abi; u64 mask; @@ -231,41 +151,6 @@ struct perf_sample { PERF_MEM_S(LOCK, NA) |\ PERF_MEM_S(TLB, NA)) -struct build_id_event { - struct perf_event_header header; - pid_t pid; - u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; - char filename[]; -}; - -enum perf_user_event_type { /* above any possible kernel type */ - PERF_RECORD_USER_TYPE_START = 64, - PERF_RECORD_HEADER_ATTR = 64, - PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */ - PERF_RECORD_HEADER_TRACING_DATA = 66, - PERF_RECORD_HEADER_BUILD_ID = 67, - PERF_RECORD_FINISHED_ROUND = 68, - PERF_RECORD_ID_INDEX = 69, - PERF_RECORD_AUXTRACE_INFO = 70, - PERF_RECORD_AUXTRACE = 71, - PERF_RECORD_AUXTRACE_ERROR = 72, - PERF_RECORD_THREAD_MAP = 73, - PERF_RECORD_CPU_MAP = 74, - PERF_RECORD_STAT_CONFIG = 75, - PERF_RECORD_STAT = 76, - PERF_RECORD_STAT_ROUND = 77, - PERF_RECORD_EVENT_UPDATE = 78, - PERF_RECORD_TIME_CONV = 79, - PERF_RECORD_HEADER_FEATURE = 80, - PERF_RECORD_COMPRESSED = 81, - PERF_RECORD_HEADER_MAX -}; - -enum auxtrace_error_type { - PERF_AUXTRACE_ERROR_ITRACE = 1, - PERF_AUXTRACE_ERROR_MAX -}; - /* Attribute type for custom synthesized events */ #define PERF_TYPE_SYNTH (INT_MAX + 1U) @@ -387,295 +272,16 @@ static inline void *perf_synth__raw_data(void *p) #define perf_sample__bad_synth_size(s, d) ((s)->raw_size < sizeof(d) - 4) -/* - * The kernel collects the number of events it couldn't send in a stretch and - * when possible sends this number in a PERF_RECORD_LOST event. The number of - * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while - * total_lost tells exactly how many events the kernel in fact lost, i.e. it is - * the sum of all struct lost_event.lost fields reported. - * - * The kernel discards mixed up samples and sends the number in a - * PERF_RECORD_LOST_SAMPLES event. The number of lost-samples events is stored - * in .nr_events[PERF_RECORD_LOST_SAMPLES] while total_lost_samples tells - * exactly how many samples the kernel in fact dropped, i.e. it is the sum of - * all struct lost_samples_event.lost fields reported. - * - * The total_period is needed because by default auto-freq is used, so - * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get - * the total number of low level events, it is necessary to to sum all struct - * sample_event.period and stash the result in total_period. - */ -struct events_stats { - u64 total_period; - u64 total_non_filtered_period; - u64 total_lost; - u64 total_lost_samples; - u64 total_aux_lost; - u64 total_aux_partial; - u64 total_invalid_chains; - u32 nr_events[PERF_RECORD_HEADER_MAX]; - u32 nr_non_filtered_samples; - u32 nr_lost_warned; - u32 nr_unknown_events; - u32 nr_invalid_chains; - u32 nr_unknown_id; - u32 nr_unprocessable_samples; - u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX]; - u32 nr_proc_map_timeout; -}; - -enum { - PERF_CPU_MAP__CPUS = 0, - PERF_CPU_MAP__MASK = 1, -}; - -struct cpu_map_entries { - u16 nr; - u16 cpu[]; -}; - -struct cpu_map_mask { - u16 nr; - u16 long_size; - unsigned long mask[]; -}; - -struct cpu_map_data { - u16 type; - char data[]; -}; - -struct cpu_map_event { - struct perf_event_header header; - struct cpu_map_data data; -}; - -struct attr_event { - struct perf_event_header header; - struct perf_event_attr attr; - u64 id[]; -}; - -enum { - PERF_EVENT_UPDATE__UNIT = 0, - PERF_EVENT_UPDATE__SCALE = 1, - PERF_EVENT_UPDATE__NAME = 2, - PERF_EVENT_UPDATE__CPUS = 3, -}; - -struct event_update_event_cpus { - struct cpu_map_data cpus; -}; - -struct event_update_event_scale { - double scale; -}; - -struct event_update_event { - struct perf_event_header header; - u64 type; - u64 id; - - char data[]; -}; - -#define MAX_EVENT_NAME 64 - -struct perf_trace_event_type { - u64 event_id; - char name[MAX_EVENT_NAME]; -}; - -struct event_type_event { - struct perf_event_header header; - struct perf_trace_event_type event_type; -}; - -struct tracing_data_event { - struct perf_event_header header; - u32 size; -}; - -struct id_index_entry { - u64 id; - u64 idx; - u64 cpu; - u64 tid; -}; - -struct id_index_event { - struct perf_event_header header; - u64 nr; - struct id_index_entry entries[0]; -}; - -struct auxtrace_info_event { - struct perf_event_header header; - u32 type; - u32 reserved__; /* For alignment */ - u64 priv[]; -}; - -struct auxtrace_event { - struct perf_event_header header; - u64 size; - u64 offset; - u64 reference; - u32 idx; - u32 tid; - u32 cpu; - u32 reserved__; /* For alignment */ -}; - -#define MAX_AUXTRACE_ERROR_MSG 64 - -struct auxtrace_error_event { - struct perf_event_header header; - u32 type; - u32 code; - u32 cpu; - u32 pid; - u32 tid; - u32 fmt; - u64 ip; - u64 time; - char msg[MAX_AUXTRACE_ERROR_MSG]; -}; - -struct aux_event { - struct perf_event_header header; - u64 aux_offset; - u64 aux_size; - u64 flags; -}; - -struct itrace_start_event { - struct perf_event_header header; - u32 pid, tid; -}; - -struct context_switch_event { - struct perf_event_header header; - u32 next_prev_pid; - u32 next_prev_tid; -}; - -struct thread_map_event_entry { - u64 pid; - char comm[16]; -}; - -struct thread_map_event { - struct perf_event_header header; - u64 nr; - struct thread_map_event_entry entries[]; -}; - -enum { - PERF_STAT_CONFIG_TERM__AGGR_MODE = 0, - PERF_STAT_CONFIG_TERM__INTERVAL = 1, - PERF_STAT_CONFIG_TERM__SCALE = 2, - PERF_STAT_CONFIG_TERM__MAX = 3, -}; - -struct stat_config_event_entry { - u64 tag; - u64 val; -}; - -struct stat_config_event { - struct perf_event_header header; - u64 nr; - struct stat_config_event_entry data[]; -}; - -struct stat_event { - struct perf_event_header header; - - u64 id; - u32 cpu; - u32 thread; - - union { - struct { - u64 val; - u64 ena; - u64 run; - }; - u64 values[3]; - }; -}; - enum { PERF_STAT_ROUND_TYPE__INTERVAL = 0, PERF_STAT_ROUND_TYPE__FINAL = 1, }; -struct stat_round_event { - struct perf_event_header header; - u64 type; - u64 time; -}; - -struct time_conv_event { - struct perf_event_header header; - u64 time_shift; - u64 time_mult; - u64 time_zero; -}; - -struct feature_event { - struct perf_event_header header; - u64 feat_id; - char data[]; -}; - -struct compressed_event { - struct perf_event_header header; - char data[]; -}; - -union perf_event { - struct perf_event_header header; - struct mmap_event mmap; - struct mmap2_event mmap2; - struct comm_event comm; - struct namespaces_event namespaces; - struct fork_event fork; - struct lost_event lost; - struct lost_samples_event lost_samples; - struct read_event read; - struct throttle_event throttle; - struct sample_event sample; - struct attr_event attr; - struct event_update_event event_update; - struct event_type_event event_type; - struct tracing_data_event tracing_data; - struct build_id_event build_id; - struct id_index_event id_index; - struct auxtrace_info_event auxtrace_info; - struct auxtrace_event auxtrace; - struct auxtrace_error_event auxtrace_error; - struct aux_event aux; - struct itrace_start_event itrace_start; - struct context_switch_event context_switch; - struct thread_map_event thread_map; - struct cpu_map_event cpu_map; - struct stat_config_event stat_config; - struct stat_event stat; - struct stat_round_event stat_round; - struct time_conv_event time_conv; - struct feature_event feat; - struct ksymbol_event ksymbol_event; - struct bpf_event bpf_event; - struct compressed_event pack; -}; - void perf_event__print_totals(void); struct perf_tool; -struct thread_map; -struct cpu_map; +struct perf_thread_map; +struct perf_cpu_map; struct perf_stat_config; struct perf_counts_values; @@ -685,15 +291,15 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool, struct machine *machine); int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool mmap_data); int perf_event__synthesize_thread_map2(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine); int perf_event__synthesize_cpu_map(struct perf_tool *tool, - struct cpu_map *cpus, + struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine); int perf_event__synthesize_threads(struct perf_tool *tool, @@ -708,7 +314,7 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); void perf_event__read_stat_config(struct perf_stat_config *config, - struct stat_config_event *event); + struct perf_record_stat_config *event); int perf_event__synthesize_stat(struct perf_tool *tool, u32 cpu, u32 thread, u64 id, struct perf_counts_values *count, @@ -770,10 +376,10 @@ int perf_event__process_ksymbol(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process_bpf_event(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); +int perf_event__process_bpf(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine); int perf_tool__process_synth_event(struct perf_tool *tool, union perf_event *event, struct machine *machine, @@ -838,19 +444,20 @@ size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp); size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp); -size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); int kallsyms__get_function_start(const char *kallsyms_filename, const char *symbol_name, u64 *addr); -void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max); -void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, +void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max); +void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, u16 type, int max); void event_attr_init(struct perf_event_attr *attr); int perf_event_paranoid(void); +bool perf_event_paranoid_check(int max_level); extern int sysctl_perf_event_max_stack; extern int sysctl_perf_event_max_contexts_per_stack; diff --git a/tools/perf/util/events_stats.h b/tools/perf/util/events_stats.h new file mode 100644 index 000000000000..859cb34fcff2 --- /dev/null +++ b/tools/perf/util/events_stats.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_EVENTS_STATS_ +#define __PERF_EVENTS_STATS_ + +#include <stdio.h> +#include <perf/event.h> +#include <linux/types.h> +#include "auxtrace.h" + +/* + * The kernel collects the number of events it couldn't send in a stretch and + * when possible sends this number in a PERF_RECORD_LOST event. The number of + * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while + * total_lost tells exactly how many events the kernel in fact lost, i.e. it is + * the sum of all struct perf_record_lost.lost fields reported. + * + * The kernel discards mixed up samples and sends the number in a + * PERF_RECORD_LOST_SAMPLES event. The number of lost-samples events is stored + * in .nr_events[PERF_RECORD_LOST_SAMPLES] while total_lost_samples tells + * exactly how many samples the kernel in fact dropped, i.e. it is the sum of + * all struct perf_record_lost_samples.lost fields reported. + * + * The total_period is needed because by default auto-freq is used, so + * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get + * the total number of low level events, it is necessary to to sum all struct + * perf_record_sample.period and stash the result in total_period. + */ +struct events_stats { + u64 total_period; + u64 total_non_filtered_period; + u64 total_lost; + u64 total_lost_samples; + u64 total_aux_lost; + u64 total_aux_partial; + u64 total_invalid_chains; + u32 nr_events[PERF_RECORD_HEADER_MAX]; + u32 nr_non_filtered_samples; + u32 nr_lost_warned; + u32 nr_unknown_events; + u32 nr_invalid_chains; + u32 nr_unknown_id; + u32 nr_unprocessable_samples; + u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX]; + u32 nr_proc_map_timeout; +}; + +void events_stats__inc(struct events_stats *stats, u32 type); + +size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); + +#endif /* __PERF_EVENTS_STATS_ */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b0364d923f76..095924aa186b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -16,10 +16,14 @@ #include "evsel.h" #include "debug.h" #include "units.h" +#include "util.h" +#include "../perf.h" #include "asm/bug.h" #include "bpf-event.h" #include <signal.h> #include <unistd.h> +#include <sched.h> +#include <stdlib.h> #include "parse-events.h" #include <subcmd/parse-options.h> @@ -32,57 +36,63 @@ #include <linux/hash.h> #include <linux/log2.h> #include <linux/err.h> +#include <linux/string.h> #include <linux/zalloc.h> +#include <perf/evlist.h> +#include <perf/evsel.h> +#include <perf/cpumap.h> + +#include <internal/xyarray.h> #ifdef LACKS_SIGQUEUE_PROTOTYPE int sigqueue(pid_t pid, int sig, const union sigval value); #endif -#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) -void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads) +void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) { int i; for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) INIT_HLIST_HEAD(&evlist->heads[i]); - INIT_LIST_HEAD(&evlist->entries); - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__init(&evlist->core); + perf_evlist__set_maps(&evlist->core, cpus, threads); fdarray__init(&evlist->pollfd, 64); evlist->workload.pid = -1; evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; } -struct perf_evlist *perf_evlist__new(void) +struct evlist *evlist__new(void) { - struct perf_evlist *evlist = zalloc(sizeof(*evlist)); + struct evlist *evlist = zalloc(sizeof(*evlist)); if (evlist != NULL) - perf_evlist__init(evlist, NULL, NULL); + evlist__init(evlist, NULL, NULL); return evlist; } -struct perf_evlist *perf_evlist__new_default(void) +struct evlist *perf_evlist__new_default(void) { - struct perf_evlist *evlist = perf_evlist__new(); + struct evlist *evlist = evlist__new(); if (evlist && perf_evlist__add_default(evlist)) { - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; } return evlist; } -struct perf_evlist *perf_evlist__new_dummy(void) +struct evlist *perf_evlist__new_dummy(void) { - struct perf_evlist *evlist = perf_evlist__new(); + struct evlist *evlist = evlist__new(); if (evlist && perf_evlist__add_dummy(evlist)) { - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; } @@ -96,17 +106,17 @@ struct perf_evlist *perf_evlist__new_dummy(void) * Events with compatible sample types all have the same id_pos * and is_pos. For convenience, put a copy on evlist. */ -void perf_evlist__set_id_pos(struct perf_evlist *evlist) +void perf_evlist__set_id_pos(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); evlist->id_pos = first->id_pos; evlist->is_pos = first->is_pos; } -static void perf_evlist__update_id_pos(struct perf_evlist *evlist) +static void perf_evlist__update_id_pos(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) perf_evsel__calc_id_pos(evsel); @@ -114,161 +124,132 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) perf_evlist__set_id_pos(evlist); } -static void perf_evlist__purge(struct perf_evlist *evlist) +static void perf_evlist__purge(struct evlist *evlist) { - struct perf_evsel *pos, *n; + struct evsel *pos, *n; evlist__for_each_entry_safe(evlist, n, pos) { - list_del_init(&pos->node); + list_del_init(&pos->core.node); pos->evlist = NULL; - perf_evsel__delete(pos); + evsel__delete(pos); } - evlist->nr_entries = 0; + evlist->core.nr_entries = 0; } -void perf_evlist__exit(struct perf_evlist *evlist) +void perf_evlist__exit(struct evlist *evlist) { zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); fdarray__exit(&evlist->pollfd); } -void perf_evlist__delete(struct perf_evlist *evlist) +void evlist__delete(struct evlist *evlist) { if (evlist == NULL) return; perf_evlist__munmap(evlist); - perf_evlist__close(evlist); - cpu_map__put(evlist->cpus); - thread_map__put(evlist->threads); - evlist->cpus = NULL; - evlist->threads = NULL; + evlist__close(evlist); + perf_cpu_map__put(evlist->core.cpus); + perf_thread_map__put(evlist->core.threads); + evlist->core.cpus = NULL; + evlist->core.threads = NULL; perf_evlist__purge(evlist); perf_evlist__exit(evlist); free(evlist); } -static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, - struct perf_evsel *evsel) -{ - /* - * We already have cpus for evsel (via PMU sysfs) so - * keep it, if there's no target cpu list defined. - */ - if (!evsel->own_cpus || evlist->has_user_cpus) { - cpu_map__put(evsel->cpus); - evsel->cpus = cpu_map__get(evlist->cpus); - } else if (evsel->cpus != evsel->own_cpus) { - cpu_map__put(evsel->cpus); - evsel->cpus = cpu_map__get(evsel->own_cpus); - } - - thread_map__put(evsel->threads); - evsel->threads = thread_map__get(evlist->threads); -} - -static void perf_evlist__propagate_maps(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - evlist__for_each_entry(evlist, evsel) - __perf_evlist__propagate_maps(evlist, evsel); -} - -void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) +void evlist__add(struct evlist *evlist, struct evsel *entry) { entry->evlist = evlist; - list_add_tail(&entry->node, &evlist->entries); - entry->idx = evlist->nr_entries; + entry->idx = evlist->core.nr_entries; entry->tracking = !entry->idx; - if (!evlist->nr_entries++) - perf_evlist__set_id_pos(evlist); + perf_evlist__add(&evlist->core, &entry->core); - __perf_evlist__propagate_maps(evlist, entry); + if (evlist->core.nr_entries == 1) + perf_evlist__set_id_pos(evlist); } -void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel) +void evlist__remove(struct evlist *evlist, struct evsel *evsel) { evsel->evlist = NULL; - list_del_init(&evsel->node); - evlist->nr_entries -= 1; + perf_evlist__remove(&evlist->core, &evsel->core); } -void perf_evlist__splice_list_tail(struct perf_evlist *evlist, +void perf_evlist__splice_list_tail(struct evlist *evlist, struct list_head *list) { - struct perf_evsel *evsel, *temp; + struct evsel *evsel, *temp; __evlist__for_each_entry_safe(list, temp, evsel) { - list_del_init(&evsel->node); - perf_evlist__add(evlist, evsel); + list_del_init(&evsel->core.node); + evlist__add(evlist, evsel); } } void __perf_evlist__set_leader(struct list_head *list) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - leader = list_entry(list->next, struct perf_evsel, node); - evsel = list_entry(list->prev, struct perf_evsel, node); + leader = list_entry(list->next, struct evsel, core.node); + evsel = list_entry(list->prev, struct evsel, core.node); - leader->nr_members = evsel->idx - leader->idx + 1; + leader->core.nr_members = evsel->idx - leader->idx + 1; __evlist__for_each_entry(list, evsel) { evsel->leader = leader; } } -void perf_evlist__set_leader(struct perf_evlist *evlist) +void perf_evlist__set_leader(struct evlist *evlist) { - if (evlist->nr_entries) { - evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; - __perf_evlist__set_leader(&evlist->entries); + if (evlist->core.nr_entries) { + evlist->nr_groups = evlist->core.nr_entries > 1 ? 1 : 0; + __perf_evlist__set_leader(&evlist->core.entries); } } -int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) +int __perf_evlist__add_default(struct evlist *evlist, bool precise) { - struct perf_evsel *evsel = perf_evsel__new_cycles(precise); + struct evsel *evsel = perf_evsel__new_cycles(precise); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); return 0; } -int perf_evlist__add_dummy(struct perf_evlist *evlist) +int perf_evlist__add_dummy(struct evlist *evlist) { struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_DUMMY, .size = sizeof(attr), /* to capture ABI version */ }; - struct perf_evsel *evsel = perf_evsel__new_idx(&attr, evlist->nr_entries); + struct evsel *evsel = perf_evsel__new_idx(&attr, evlist->core.nr_entries); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); return 0; } -static int perf_evlist__add_attrs(struct perf_evlist *evlist, +static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs) { - struct perf_evsel *evsel, *n; + struct evsel *evsel, *n; LIST_HEAD(head); size_t i; for (i = 0; i < nr_attrs; i++) { - evsel = perf_evsel__new_idx(attrs + i, evlist->nr_entries + i); + evsel = perf_evsel__new_idx(attrs + i, evlist->core.nr_entries + i); if (evsel == NULL) goto out_delete_partial_list; - list_add_tail(&evsel->node, &head); + list_add_tail(&evsel->core.node, &head); } perf_evlist__splice_list_tail(evlist, &head); @@ -277,11 +258,11 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, out_delete_partial_list: __evlist__for_each_entry_safe(&head, n, evsel) - perf_evsel__delete(evsel); + evsel__delete(evsel); return -1; } -int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, +int __perf_evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs) { size_t i; @@ -289,31 +270,31 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, for (i = 0; i < nr_attrs; i++) event_attr_init(attrs + i); - return perf_evlist__add_attrs(evlist, attrs, nr_attrs); + return evlist__add_attrs(evlist, attrs, nr_attrs); } -struct perf_evsel * -perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) +struct evsel * +perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == PERF_TYPE_TRACEPOINT && - (int)evsel->attr.config == id) + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT && + (int)evsel->core.attr.config == id) return evsel; } return NULL; } -struct perf_evsel * -perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, +struct evsel * +perf_evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && + if ((evsel->core.attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; } @@ -321,66 +302,66 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, return NULL; } -int perf_evlist__add_newtp(struct perf_evlist *evlist, +int perf_evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler) { - struct perf_evsel *evsel = perf_evsel__newtp(sys, name); + struct evsel *evsel = perf_evsel__newtp(sys, name); if (IS_ERR(evsel)) return -1; evsel->handler = handler; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); return 0; } -static int perf_evlist__nr_threads(struct perf_evlist *evlist, - struct perf_evsel *evsel) +static int perf_evlist__nr_threads(struct evlist *evlist, + struct evsel *evsel) { if (evsel->system_wide) return 1; else - return thread_map__nr(evlist->threads); + return perf_thread_map__nr(evlist->core.threads); } -void perf_evlist__disable(struct perf_evlist *evlist) +void evlist__disable(struct evlist *evlist) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(evlist, pos) { - if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->fd) + if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->core.fd) continue; - perf_evsel__disable(pos); + evsel__disable(pos); } evlist->enabled = false; } -void perf_evlist__enable(struct perf_evlist *evlist) +void evlist__enable(struct evlist *evlist) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(evlist, pos) { - if (!perf_evsel__is_group_leader(pos) || !pos->fd) + if (!perf_evsel__is_group_leader(pos) || !pos->core.fd) continue; - perf_evsel__enable(pos); + evsel__enable(pos); } evlist->enabled = true; } -void perf_evlist__toggle_enable(struct perf_evlist *evlist) +void perf_evlist__toggle_enable(struct evlist *evlist) { - (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); + (evlist->enabled ? evlist__disable : evlist__enable)(evlist); } -static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, - struct perf_evsel *evsel, int cpu) +static int perf_evlist__enable_event_cpu(struct evlist *evlist, + struct evsel *evsel, int cpu) { int thread; int nr_threads = perf_evlist__nr_threads(evlist, evsel); - if (!evsel->fd) + if (!evsel->core.fd) return -EINVAL; for (thread = 0; thread < nr_threads; thread++) { @@ -391,14 +372,14 @@ static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, return 0; } -static int perf_evlist__enable_event_thread(struct perf_evlist *evlist, - struct perf_evsel *evsel, +static int perf_evlist__enable_event_thread(struct evlist *evlist, + struct evsel *evsel, int thread) { int cpu; - int nr_cpus = cpu_map__nr(evlist->cpus); + int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); - if (!evsel->fd) + if (!evsel->core.fd) return -EINVAL; for (cpu = 0; cpu < nr_cpus; cpu++) { @@ -409,10 +390,10 @@ static int perf_evlist__enable_event_thread(struct perf_evlist *evlist, return 0; } -int perf_evlist__enable_event_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx) +int perf_evlist__enable_event_idx(struct evlist *evlist, + struct evsel *evsel, int idx) { - bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus); + bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.cpus); if (per_cpu_mmaps) return perf_evlist__enable_event_cpu(evlist, evsel, idx); @@ -420,12 +401,12 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist, return perf_evlist__enable_event_thread(evlist, evsel, idx); } -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) +int perf_evlist__alloc_pollfd(struct evlist *evlist) { - int nr_cpus = cpu_map__nr(evlist->cpus); - int nr_threads = thread_map__nr(evlist->threads); + int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); + int nr_threads = perf_thread_map__nr(evlist->core.threads); int nfds = 0; - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->system_wide) @@ -441,7 +422,7 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) return 0; } -static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, +static int __perf_evlist__add_pollfd(struct evlist *evlist, int fd, struct perf_mmap *map, short revent) { int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); @@ -458,7 +439,7 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, return pos; } -int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) +int perf_evlist__add_pollfd(struct evlist *evlist, int fd) { return __perf_evlist__add_pollfd(evlist, fd, NULL, POLLIN); } @@ -472,19 +453,19 @@ static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, perf_mmap__put(map); } -int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) +int perf_evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask) { return fdarray__filter(&evlist->pollfd, revents_and_mask, perf_evlist__munmap_filtered, NULL); } -int perf_evlist__poll(struct perf_evlist *evlist, int timeout) +int perf_evlist__poll(struct evlist *evlist, int timeout) { return fdarray__poll(&evlist->pollfd, timeout); } -static void perf_evlist__id_hash(struct perf_evlist *evlist, - struct perf_evsel *evsel, +static void perf_evlist__id_hash(struct evlist *evlist, + struct evsel *evsel, int cpu, int thread, u64 id) { int hash; @@ -496,15 +477,15 @@ static void perf_evlist__id_hash(struct perf_evlist *evlist, hlist_add_head(&sid->node, &evlist->heads[hash]); } -void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, +void perf_evlist__id_add(struct evlist *evlist, struct evsel *evsel, int cpu, int thread, u64 id) { perf_evlist__id_hash(evlist, evsel, cpu, thread, id); evsel->id[evsel->ids++] = id; } -int perf_evlist__id_add_fd(struct perf_evlist *evlist, - struct perf_evsel *evsel, +int perf_evlist__id_add_fd(struct evlist *evlist, + struct evsel *evsel, int cpu, int thread, int fd) { u64 read_data[4] = { 0, }; @@ -528,13 +509,13 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) return -1; - if (!(evsel->attr.read_format & PERF_FORMAT_ID) || + if (!(evsel->core.attr.read_format & PERF_FORMAT_ID) || read(fd, &read_data, sizeof(read_data)) == -1) return -1; - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) ++id_idx; - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) ++id_idx; id = read_data[id_idx]; @@ -544,23 +525,23 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, return 0; } -static void perf_evlist__set_sid_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx, int cpu, +static void perf_evlist__set_sid_idx(struct evlist *evlist, + struct evsel *evsel, int idx, int cpu, int thread) { struct perf_sample_id *sid = SID(evsel, cpu, thread); sid->idx = idx; - if (evlist->cpus && cpu >= 0) - sid->cpu = evlist->cpus->map[cpu]; + if (evlist->core.cpus && cpu >= 0) + sid->cpu = evlist->core.cpus->map[cpu]; else sid->cpu = -1; - if (!evsel->system_wide && evlist->threads && thread >= 0) - sid->tid = thread_map__pid(evlist->threads, thread); + if (!evsel->system_wide && evlist->core.threads && thread >= 0) + sid->tid = perf_thread_map__pid(evlist->core.threads, thread); else sid->tid = -1; } -struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id) +struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id) { struct hlist_head *head; struct perf_sample_id *sid; @@ -576,11 +557,11 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id) return NULL; } -struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) +struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id) { struct perf_sample_id *sid; - if (evlist->nr_entries == 1 || !id) + if (evlist->core.nr_entries == 1 || !id) return perf_evlist__first(evlist); sid = perf_evlist__id2sid(evlist, id); @@ -593,7 +574,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) return NULL; } -struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, +struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist, u64 id) { struct perf_sample_id *sid; @@ -608,10 +589,10 @@ struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, return NULL; } -static int perf_evlist__event2id(struct perf_evlist *evlist, +static int perf_evlist__event2id(struct evlist *evlist, union perf_event *event, u64 *id) { - const u64 *array = event->sample.array; + const __u64 *array = event->sample.array; ssize_t n; n = (event->header.size - sizeof(event->header)) >> 3; @@ -629,19 +610,19 @@ static int perf_evlist__event2id(struct perf_evlist *evlist, return 0; } -struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, +struct evsel *perf_evlist__event2evsel(struct evlist *evlist, union perf_event *event) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); struct hlist_head *head; struct perf_sample_id *sid; int hash; u64 id; - if (evlist->nr_entries == 1) + if (evlist->core.nr_entries == 1) return first; - if (!first->attr.sample_id_all && + if (!first->core.attr.sample_id_all && event->header.type != PERF_RECORD_SAMPLE) return first; @@ -662,7 +643,7 @@ struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, return NULL; } -static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) +static int perf_evlist__set_paused(struct evlist *evlist, bool value) { int i; @@ -682,17 +663,17 @@ static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) return 0; } -static int perf_evlist__pause(struct perf_evlist *evlist) +static int perf_evlist__pause(struct evlist *evlist) { return perf_evlist__set_paused(evlist, true); } -static int perf_evlist__resume(struct perf_evlist *evlist) +static int perf_evlist__resume(struct evlist *evlist) { return perf_evlist__set_paused(evlist, false); } -static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) +static void perf_evlist__munmap_nofree(struct evlist *evlist) { int i; @@ -705,22 +686,22 @@ static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) perf_mmap__munmap(&evlist->overwrite_mmap[i]); } -void perf_evlist__munmap(struct perf_evlist *evlist) +void perf_evlist__munmap(struct evlist *evlist) { perf_evlist__munmap_nofree(evlist); zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); } -static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist, +static struct perf_mmap *perf_evlist__alloc_mmap(struct evlist *evlist, bool overwrite) { int i; struct perf_mmap *map; - evlist->nr_mmaps = cpu_map__nr(evlist->cpus); - if (cpu_map__empty(evlist->cpus)) - evlist->nr_mmaps = thread_map__nr(evlist->threads); + evlist->nr_mmaps = perf_cpu_map__nr(evlist->core.cpus); + if (perf_cpu_map__empty(evlist->core.cpus)) + evlist->nr_mmaps = perf_thread_map__nr(evlist->core.threads); map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); if (!map) return NULL; @@ -743,21 +724,21 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist, } static bool -perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, - struct perf_evsel *evsel) +perf_evlist__should_poll(struct evlist *evlist __maybe_unused, + struct evsel *evsel) { - if (evsel->attr.write_backward) + if (evsel->core.attr.write_backward) return false; return true; } -static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, +static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, struct mmap_params *mp, int cpu_idx, int thread, int *_output, int *_output_overwrite) { - struct perf_evsel *evsel; + struct evsel *evsel; int revent; - int evlist_cpu = cpu_map__cpu(evlist->cpus, cpu_idx); + int evlist_cpu = cpu_map__cpu(evlist->core.cpus, cpu_idx); evlist__for_each_entry(evlist, evsel) { struct perf_mmap *maps = evlist->mmap; @@ -766,7 +747,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, int cpu; mp->prot = PROT_READ | PROT_WRITE; - if (evsel->attr.write_backward) { + if (evsel->core.attr.write_backward) { output = _output_overwrite; maps = evlist->overwrite_mmap; @@ -784,7 +765,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (evsel->system_wide && thread) continue; - cpu = cpu_map__idx(evsel->cpus, evlist_cpu); + cpu = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu); if (cpu == -1) continue; @@ -817,7 +798,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, return -1; } - if (evsel->attr.read_format & PERF_FORMAT_ID) { + if (evsel->core.attr.read_format & PERF_FORMAT_ID) { if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) return -1; @@ -829,12 +810,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, return 0; } -static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, +static int perf_evlist__mmap_per_cpu(struct evlist *evlist, struct mmap_params *mp) { int cpu, thread; - int nr_cpus = cpu_map__nr(evlist->cpus); - int nr_threads = thread_map__nr(evlist->threads); + int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); + int nr_threads = perf_thread_map__nr(evlist->core.threads); pr_debug2("perf event ring buffer mmapped per cpu\n"); for (cpu = 0; cpu < nr_cpus; cpu++) { @@ -858,11 +839,11 @@ out_unmap: return -1; } -static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, +static int perf_evlist__mmap_per_thread(struct evlist *evlist, struct mmap_params *mp) { int thread; - int nr_threads = thread_map__nr(evlist->threads); + int nr_threads = perf_thread_map__nr(evlist->core.threads); pr_debug2("perf event ring buffer mmapped per thread\n"); for (thread = 0; thread < nr_threads; thread++) { @@ -1006,14 +987,14 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, * * Return: %0 on success, negative error code otherwise. */ -int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, +int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level) { - struct perf_evsel *evsel; - const struct cpu_map *cpus = evlist->cpus; - const struct thread_map *threads = evlist->threads; + struct evsel *evsel; + const struct perf_cpu_map *cpus = evlist->core.cpus; + const struct perf_thread_map *threads = evlist->core.threads; /* * Delay setting mp.prot: set it before calling perf_mmap__mmap. * Its value is decided by evsel's write_backward. @@ -1038,28 +1019,28 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, auxtrace_pages, auxtrace_overwrite); evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.read_format & PERF_FORMAT_ID) && + if ((evsel->core.attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && - perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) + perf_evsel__alloc_id(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0) return -ENOMEM; } - if (cpu_map__empty(cpus)) + if (perf_cpu_map__empty(cpus)) return perf_evlist__mmap_per_thread(evlist, &mp); return perf_evlist__mmap_per_cpu(evlist, &mp); } -int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages) +int perf_evlist__mmap(struct evlist *evlist, unsigned int pages) { return perf_evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0); } -int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) +int perf_evlist__create_maps(struct evlist *evlist, struct target *target) { bool all_threads = (target->per_thread && target->system_wide); - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; /* * If specify '-a' and '--per-thread' to perf record, perf record @@ -1086,68 +1067,45 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) return -1; if (target__uses_dummy_map(target)) - cpus = cpu_map__dummy_new(); + cpus = perf_cpu_map__dummy_new(); else - cpus = cpu_map__new(target->cpu_list); + cpus = perf_cpu_map__new(target->cpu_list); if (!cpus) goto out_delete_threads; - evlist->has_user_cpus = !!target->cpu_list; + evlist->core.has_user_cpus = !!target->cpu_list; - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); return 0; out_delete_threads: - thread_map__put(threads); + perf_thread_map__put(threads); return -1; } -void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads) -{ - /* - * Allow for the possibility that one or another of the maps isn't being - * changed i.e. don't put it. Note we are assuming the maps that are - * being applied are brand new and evlist is taking ownership of the - * original reference count of 1. If that is not the case it is up to - * the caller to increase the reference count. - */ - if (cpus != evlist->cpus) { - cpu_map__put(evlist->cpus); - evlist->cpus = cpu_map__get(cpus); - } - - if (threads != evlist->threads) { - thread_map__put(evlist->threads); - evlist->threads = thread_map__get(threads); - } - - perf_evlist__propagate_maps(evlist); -} - -void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__set_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) __perf_evsel__set_sample_bit(evsel, bit); } -void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__reset_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) __perf_evsel__reset_sample_bit(evsel, bit); } -int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) +int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel) { - struct perf_evsel *evsel; + struct evsel *evsel; int err = 0; evlist__for_each_entry(evlist, evsel) { @@ -1158,7 +1116,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e * filters only work for tracepoint event, which doesn't have cpu limit. * So evlist and evsel should always be same. */ - err = perf_evsel__apply_filter(evsel, evsel->filter); + err = perf_evsel__apply_filter(&evsel->core, evsel->filter); if (err) { *err_evsel = evsel; break; @@ -1168,13 +1126,13 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e return err; } -int perf_evlist__set_tp_filter(struct perf_evlist *evlist, const char *filter) +int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter) { - struct perf_evsel *evsel; + struct evsel *evsel; int err = 0; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; err = perf_evsel__set_filter(evsel, filter); @@ -1185,7 +1143,7 @@ int perf_evlist__set_tp_filter(struct perf_evlist *evlist, const char *filter) return err; } -int perf_evlist__set_tp_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids) +int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) { char *filter; int ret = -1; @@ -1212,16 +1170,16 @@ out_free: return ret; } -int perf_evlist__set_tp_filter_pid(struct perf_evlist *evlist, pid_t pid) +int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid) { return perf_evlist__set_tp_filter_pids(evlist, 1, &pid); } -bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) +bool perf_evlist__valid_sample_type(struct evlist *evlist) { - struct perf_evsel *pos; + struct evsel *pos; - if (evlist->nr_entries == 1) + if (evlist->core.nr_entries == 1) return true; if (evlist->id_pos < 0 || evlist->is_pos < 0) @@ -1236,43 +1194,43 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) return true; } -u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) +u64 __perf_evlist__combined_sample_type(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; if (evlist->combined_sample_type) return evlist->combined_sample_type; evlist__for_each_entry(evlist, evsel) - evlist->combined_sample_type |= evsel->attr.sample_type; + evlist->combined_sample_type |= evsel->core.attr.sample_type; return evlist->combined_sample_type; } -u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist) +u64 perf_evlist__combined_sample_type(struct evlist *evlist) { evlist->combined_sample_type = 0; return __perf_evlist__combined_sample_type(evlist); } -u64 perf_evlist__combined_branch_type(struct perf_evlist *evlist) +u64 perf_evlist__combined_branch_type(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 branch_type = 0; evlist__for_each_entry(evlist, evsel) - branch_type |= evsel->attr.branch_sample_type; + branch_type |= evsel->core.attr.branch_sample_type; return branch_type; } -bool perf_evlist__valid_read_format(struct perf_evlist *evlist) +bool perf_evlist__valid_read_format(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; - u64 read_format = first->attr.read_format; - u64 sample_type = first->attr.sample_type; + struct evsel *first = perf_evlist__first(evlist), *pos = first; + u64 read_format = first->core.attr.read_format; + u64 sample_type = first->core.attr.sample_type; evlist__for_each_entry(evlist, pos) { - if (read_format != pos->attr.read_format) + if (read_format != pos->core.attr.read_format) return false; } @@ -1285,23 +1243,23 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) return true; } -u64 perf_evlist__read_format(struct perf_evlist *evlist) +u64 perf_evlist__read_format(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); - return first->attr.read_format; + struct evsel *first = perf_evlist__first(evlist); + return first->core.attr.read_format; } -u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) +u16 perf_evlist__id_hdr_size(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); struct perf_sample *data; u64 sample_type; u16 size = 0; - if (!first->attr.sample_id_all) + if (!first->core.attr.sample_id_all) goto out; - sample_type = first->attr.sample_type; + sample_type = first->core.attr.sample_type; if (sample_type & PERF_SAMPLE_TID) size += sizeof(data->tid) * 2; @@ -1324,42 +1282,42 @@ out: return size; } -bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) +bool perf_evlist__valid_sample_id_all(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; + struct evsel *first = perf_evlist__first(evlist), *pos = first; evlist__for_each_entry_continue(evlist, pos) { - if (first->attr.sample_id_all != pos->attr.sample_id_all) + if (first->core.attr.sample_id_all != pos->core.attr.sample_id_all) return false; } return true; } -bool perf_evlist__sample_id_all(struct perf_evlist *evlist) +bool perf_evlist__sample_id_all(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); - return first->attr.sample_id_all; + struct evsel *first = perf_evlist__first(evlist); + return first->core.attr.sample_id_all; } -void perf_evlist__set_selected(struct perf_evlist *evlist, - struct perf_evsel *evsel) +void perf_evlist__set_selected(struct evlist *evlist, + struct evsel *evsel) { evlist->selected = evsel; } -void perf_evlist__close(struct perf_evlist *evlist) +void evlist__close(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry_reverse(evlist, evsel) - perf_evsel__close(evsel); + evsel__close(evsel); } -static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) +static int perf_evlist__create_syswide_maps(struct evlist *evlist) { - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; int err = -ENOMEM; /* @@ -1371,32 +1329,32 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) * error, and we may not want to do that fallback to a * default cpu identity map :-\ */ - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) goto out; - threads = thread_map__new_dummy(); + threads = perf_thread_map__new_dummy(); if (!threads) goto out_put; - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); out: return err; out_put: - cpu_map__put(cpus); + perf_cpu_map__put(cpus); goto out; } -int perf_evlist__open(struct perf_evlist *evlist) +int evlist__open(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; int err; /* * Default: one fd per CPU, all threads, aka systemwide * as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL */ - if (evlist->threads == NULL && evlist->cpus == NULL) { + if (evlist->core.threads == NULL && evlist->core.cpus == NULL) { err = perf_evlist__create_syswide_maps(evlist); if (err < 0) goto out_err; @@ -1405,19 +1363,19 @@ int perf_evlist__open(struct perf_evlist *evlist) perf_evlist__update_id_pos(evlist); evlist__for_each_entry(evlist, evsel) { - err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); + err = evsel__open(evsel, evsel->core.cpus, evsel->core.threads); if (err < 0) goto out_err; } return 0; out_err: - perf_evlist__close(evlist); + evlist__close(evlist); errno = -err; return err; } -int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, +int perf_evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[], bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext)) { @@ -1499,12 +1457,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar } if (target__none(target)) { - if (evlist->threads == NULL) { + if (evlist->core.threads == NULL) { fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n", __func__, __LINE__); goto out_close_pipes; } - thread_map__set_pid(evlist->threads, 0, evlist->workload.pid); + perf_thread_map__set_pid(evlist->core.threads, 0, evlist->workload.pid); } close(child_ready_pipe[1]); @@ -1531,7 +1489,7 @@ out_close_ready_pipe: return -1; } -int perf_evlist__start_workload(struct perf_evlist *evlist) +int perf_evlist__start_workload(struct evlist *evlist) { if (evlist->workload.cork_fd > 0) { char bf = 0; @@ -1550,30 +1508,30 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) return 0; } -int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, +int perf_evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { - struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (!evsel) return -EFAULT; return perf_evsel__parse_sample(evsel, event, sample); } -int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist, +int perf_evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp) { - struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (!evsel) return -EFAULT; return perf_evsel__parse_sample_timestamp(evsel, event, timestamp); } -size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) +size_t perf_evlist__fprintf(struct evlist *evlist, FILE *fp) { - struct perf_evsel *evsel; + struct evsel *evsel; size_t printed = 0; evlist__for_each_entry(evlist, evsel) { @@ -1584,7 +1542,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) return printed + fprintf(fp, "\n"); } -int perf_evlist__strerror_open(struct perf_evlist *evlist, +int perf_evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size) { int printed, value; @@ -1613,20 +1571,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist, "Hint:\tThe current value is %d.", value); break; case EINVAL: { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); int max_freq; if (sysctl__read_int("kernel/perf_event_max_sample_rate", &max_freq) < 0) goto out_default; - if (first->attr.sample_freq < (u64)max_freq) + if (first->core.attr.sample_freq < (u64)max_freq) goto out_default; printed = scnprintf(buf, size, "Error:\t%s.\n" "Hint:\tCheck /proc/sys/kernel/perf_event_max_sample_rate.\n" "Hint:\tThe current value is %d and %" PRIu64 " is being requested.", - emsg, max_freq, first->attr.sample_freq); + emsg, max_freq, first->core.attr.sample_freq); break; } default: @@ -1638,7 +1596,7 @@ out_default: return 0; } -int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size) +int perf_evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size) { char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf)); int pages_attempted = evlist->mmap_len / 1024, pages_max_per_user, printed = 0; @@ -1669,10 +1627,10 @@ int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, s return 0; } -void perf_evlist__to_front(struct perf_evlist *evlist, - struct perf_evsel *move_evsel) +void perf_evlist__to_front(struct evlist *evlist, + struct evsel *move_evsel) { - struct perf_evsel *evsel, *n; + struct evsel *evsel, *n; LIST_HEAD(move); if (move_evsel == perf_evlist__first(evlist)) @@ -1680,16 +1638,16 @@ void perf_evlist__to_front(struct perf_evlist *evlist, evlist__for_each_entry_safe(evlist, n, evsel) { if (evsel->leader == move_evsel->leader) - list_move_tail(&evsel->node, &move); + list_move_tail(&evsel->core.node, &move); } - list_splice(&move, &evlist->entries); + list_splice(&move, &evlist->core.entries); } -void perf_evlist__set_tracking_event(struct perf_evlist *evlist, - struct perf_evsel *tracking_evsel) +void perf_evlist__set_tracking_event(struct evlist *evlist, + struct evsel *tracking_evsel) { - struct perf_evsel *evsel; + struct evsel *evsel; if (tracking_evsel->tracking) return; @@ -1702,11 +1660,11 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist, tracking_evsel->tracking = true; } -struct perf_evsel * -perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, +struct evsel * +perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (!evsel->name) @@ -1718,7 +1676,7 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, return NULL; } -void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, +void perf_evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state) { enum bkw_mmap_state old_state = evlist->bkw_mmap_state; @@ -1776,12 +1734,12 @@ state_err: return; } -bool perf_evlist__exclude_kernel(struct perf_evlist *evlist) +bool perf_evlist__exclude_kernel(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (!evsel->attr.exclude_kernel) + if (!evsel->core.attr.exclude_kernel) return false; } @@ -1793,25 +1751,25 @@ bool perf_evlist__exclude_kernel(struct perf_evlist *evlist) * the group display. Set the artificial group and set the leader's * forced_leader flag to notify the display code. */ -void perf_evlist__force_leader(struct perf_evlist *evlist) +void perf_evlist__force_leader(struct evlist *evlist) { if (!evlist->nr_groups) { - struct perf_evsel *leader = perf_evlist__first(evlist); + struct evsel *leader = perf_evlist__first(evlist); perf_evlist__set_leader(evlist); leader->forced_leader = true; } } -struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list, - struct perf_evsel *evsel) +struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list, + struct evsel *evsel) { - struct perf_evsel *c2, *leader; + struct evsel *c2, *leader; bool is_open = true; leader = evsel->leader; pr_debug("Weak group for %s/%d failed\n", - leader->name, leader->nr_members); + leader->name, leader->core.nr_members); /* * for_each_group_member doesn't work here because it doesn't @@ -1822,24 +1780,24 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list, is_open = false; if (c2->leader == leader) { if (is_open) - perf_evsel__close(c2); + evsel__close(c2); c2->leader = c2; - c2->nr_members = 0; + c2->core.nr_members = 0; } } return leader; } -int perf_evlist__add_sb_event(struct perf_evlist **evlist, +int perf_evlist__add_sb_event(struct evlist **evlist, struct perf_event_attr *attr, perf_evsel__sb_cb_t cb, void *data) { - struct perf_evsel *evsel; + struct evsel *evsel; bool new_evlist = (*evlist) == NULL; if (*evlist == NULL) - *evlist = perf_evlist__new(); + *evlist = evlist__new(); if (*evlist == NULL) return -1; @@ -1848,18 +1806,18 @@ int perf_evlist__add_sb_event(struct perf_evlist **evlist, attr->sample_id_all = 1; } - evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries); + evsel = perf_evsel__new_idx(attr, (*evlist)->core.nr_entries); if (!evsel) goto out_err; evsel->side_band.cb = cb; evsel->side_band.data = data; - perf_evlist__add(*evlist, evsel); + evlist__add(*evlist, evsel); return 0; out_err: if (new_evlist) { - perf_evlist__delete(*evlist); + evlist__delete(*evlist); *evlist = NULL; } return -1; @@ -1867,9 +1825,17 @@ out_err: static void *perf_evlist__poll_thread(void *arg) { - struct perf_evlist *evlist = arg; + struct evlist *evlist = arg; bool draining = false; int i, done = 0; + /* + * In order to read symbols from other namespaces perf to needs to call + * setns(2). This isn't permitted if the struct_fs has multiple users. + * unshare(2) the fs so that we may continue to setns into namespaces + * that we're observing when, for instance, reading the build-ids at + * the end of a 'perf record' session. + */ + unshare(CLONE_FS); while (!done) { bool got_data = false; @@ -1887,7 +1853,7 @@ static void *perf_evlist__poll_thread(void *arg) if (perf_mmap__read_init(map)) continue; while ((event = perf_mmap__read_event(map)) != NULL) { - struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (evsel && evsel->side_band.cb) evsel->side_band.cb(event, evsel->side_band.data); @@ -1906,10 +1872,10 @@ static void *perf_evlist__poll_thread(void *arg) return NULL; } -int perf_evlist__start_sb_thread(struct perf_evlist *evlist, +int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target) { - struct perf_evsel *counter; + struct evsel *counter; if (!evlist) return 0; @@ -1918,8 +1884,8 @@ int perf_evlist__start_sb_thread(struct perf_evlist *evlist, goto out_delete_evlist; evlist__for_each_entry(evlist, counter) { - if (perf_evsel__open(counter, evlist->cpus, - evlist->threads) < 0) + if (evsel__open(counter, evlist->core.cpus, + evlist->core.threads) < 0) goto out_delete_evlist; } @@ -1927,7 +1893,7 @@ int perf_evlist__start_sb_thread(struct perf_evlist *evlist, goto out_delete_evlist; evlist__for_each_entry(evlist, counter) { - if (perf_evsel__enable(counter)) + if (evsel__enable(counter)) goto out_delete_evlist; } @@ -1938,16 +1904,16 @@ int perf_evlist__start_sb_thread(struct perf_evlist *evlist, return 0; out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; return -1; } -void perf_evlist__stop_sb_thread(struct perf_evlist *evlist) +void perf_evlist__stop_sb_thread(struct evlist *evlist) { if (!evlist) return; evlist->thread.done = 1; pthread_join(evlist->thread.th, NULL); - perf_evlist__delete(evlist); + evlist__delete(evlist); } diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 49354fe24d5f..a55f0f2546e5 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -8,30 +8,27 @@ #include <linux/list.h> #include <api/fd/array.h> #include <stdio.h> -#include "../perf.h" -#include "event.h" +#include <internal/evlist.h> +#include "events_stats.h" #include "evsel.h" #include "mmap.h" -#include "util.h" #include <signal.h> #include <unistd.h> struct pollfd; struct thread_map; -struct cpu_map; +struct perf_cpu_map; struct record_opts; #define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) -struct perf_evlist { - struct list_head entries; +struct evlist { + struct perf_evlist core; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; - int nr_entries; int nr_groups; int nr_mmaps; bool enabled; - bool has_user_cpus; size_t mmap_len; int id_pos; int is_pos; @@ -44,12 +41,10 @@ struct perf_evlist { struct fdarray pollfd; struct perf_mmap *mmap; struct perf_mmap *overwrite_mmap; - struct thread_map *threads; - struct cpu_map *cpus; - struct perf_evsel *selected; + struct evsel *selected; struct events_stats stats; struct perf_env *env; - void (*trace_event_sample_raw)(struct perf_evlist *evlist, + void (*trace_event_sample_raw)(struct evlist *evlist, union perf_event *event, struct perf_sample *sample); u64 first_sample_time; @@ -60,51 +55,51 @@ struct perf_evlist { } thread; }; -struct perf_evsel_str_handler { +struct evsel_str_handler { const char *name; void *handler; }; -struct perf_evlist *perf_evlist__new(void); -struct perf_evlist *perf_evlist__new_default(void); -struct perf_evlist *perf_evlist__new_dummy(void); -void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads); -void perf_evlist__exit(struct perf_evlist *evlist); -void perf_evlist__delete(struct perf_evlist *evlist); +struct evlist *evlist__new(void); +struct evlist *perf_evlist__new_default(void); +struct evlist *perf_evlist__new_dummy(void); +void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, + struct perf_thread_map *threads); +void perf_evlist__exit(struct evlist *evlist); +void evlist__delete(struct evlist *evlist); -void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); -void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel); +void evlist__add(struct evlist *evlist, struct evsel *entry); +void evlist__remove(struct evlist *evlist, struct evsel *evsel); -int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise); +int __perf_evlist__add_default(struct evlist *evlist, bool precise); -static inline int perf_evlist__add_default(struct perf_evlist *evlist) +static inline int perf_evlist__add_default(struct evlist *evlist) { return __perf_evlist__add_default(evlist, true); } -int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, +int __perf_evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); #define perf_evlist__add_default_attrs(evlist, array) \ __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) -int perf_evlist__add_dummy(struct perf_evlist *evlist); +int perf_evlist__add_dummy(struct evlist *evlist); -int perf_evlist__add_sb_event(struct perf_evlist **evlist, +int perf_evlist__add_sb_event(struct evlist **evlist, struct perf_event_attr *attr, perf_evsel__sb_cb_t cb, void *data); -int perf_evlist__start_sb_thread(struct perf_evlist *evlist, +int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target); -void perf_evlist__stop_sb_thread(struct perf_evlist *evlist); +void perf_evlist__stop_sb_thread(struct evlist *evlist); -int perf_evlist__add_newtp(struct perf_evlist *evlist, +int perf_evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler); -void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__set_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit); -void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__reset_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit); #define perf_evlist__set_sample_bit(evlist, bit) \ @@ -113,58 +108,58 @@ void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, #define perf_evlist__reset_sample_bit(evlist, bit) \ __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit) -int perf_evlist__set_tp_filter(struct perf_evlist *evlist, const char *filter); -int perf_evlist__set_tp_filter_pid(struct perf_evlist *evlist, pid_t pid); -int perf_evlist__set_tp_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); +int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter); +int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid); +int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids); -struct perf_evsel * -perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); +struct evsel * +perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id); -struct perf_evsel * -perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, +struct evsel * +perf_evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name); -void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, +void perf_evlist__id_add(struct evlist *evlist, struct evsel *evsel, int cpu, int thread, u64 id); -int perf_evlist__id_add_fd(struct perf_evlist *evlist, - struct perf_evsel *evsel, +int perf_evlist__id_add_fd(struct evlist *evlist, + struct evsel *evsel, int cpu, int thread, int fd); -int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); -int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask); +int perf_evlist__add_pollfd(struct evlist *evlist, int fd); +int perf_evlist__alloc_pollfd(struct evlist *evlist); +int perf_evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask); -int perf_evlist__poll(struct perf_evlist *evlist, int timeout); +int perf_evlist__poll(struct evlist *evlist, int timeout); -struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); -struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, +struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id); +struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist, u64 id); -struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); +struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id); -void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, enum bkw_mmap_state state); +void perf_evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state); -void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); +void perf_evlist__mmap_consume(struct evlist *evlist, int idx); -int perf_evlist__open(struct perf_evlist *evlist); -void perf_evlist__close(struct perf_evlist *evlist); +int evlist__open(struct evlist *evlist); +void evlist__close(struct evlist *evlist); struct callchain_param; -void perf_evlist__set_id_pos(struct perf_evlist *evlist); +void perf_evlist__set_id_pos(struct evlist *evlist); bool perf_can_sample_identifier(void); bool perf_can_record_switch_events(void); bool perf_can_record_cpu_wide(void); -void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, +void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain); int record_opts__config(struct record_opts *opts); -int perf_evlist__prepare_workload(struct perf_evlist *evlist, +int perf_evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[], bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext)); -int perf_evlist__start_workload(struct perf_evlist *evlist); +int perf_evlist__start_workload(struct evlist *evlist); struct option; @@ -175,77 +170,75 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, unsigned long perf_event_mlock_kb_in_pages(void); -int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, +int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level); -int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages); -void perf_evlist__munmap(struct perf_evlist *evlist); +int perf_evlist__mmap(struct evlist *evlist, unsigned int pages); +void perf_evlist__munmap(struct evlist *evlist); size_t perf_evlist__mmap_size(unsigned long pages); -void perf_evlist__disable(struct perf_evlist *evlist); -void perf_evlist__enable(struct perf_evlist *evlist); -void perf_evlist__toggle_enable(struct perf_evlist *evlist); +void evlist__disable(struct evlist *evlist); +void evlist__enable(struct evlist *evlist); +void perf_evlist__toggle_enable(struct evlist *evlist); -int perf_evlist__enable_event_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx); +int perf_evlist__enable_event_idx(struct evlist *evlist, + struct evsel *evsel, int idx); -void perf_evlist__set_selected(struct perf_evlist *evlist, - struct perf_evsel *evsel); +void perf_evlist__set_selected(struct evlist *evlist, + struct evsel *evsel); -void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads); -int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); -int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel); +int perf_evlist__create_maps(struct evlist *evlist, struct target *target); +int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel); void __perf_evlist__set_leader(struct list_head *list); -void perf_evlist__set_leader(struct perf_evlist *evlist); +void perf_evlist__set_leader(struct evlist *evlist); -u64 perf_evlist__read_format(struct perf_evlist *evlist); -u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist); -u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist); -u64 perf_evlist__combined_branch_type(struct perf_evlist *evlist); -bool perf_evlist__sample_id_all(struct perf_evlist *evlist); -u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); +u64 perf_evlist__read_format(struct evlist *evlist); +u64 __perf_evlist__combined_sample_type(struct evlist *evlist); +u64 perf_evlist__combined_sample_type(struct evlist *evlist); +u64 perf_evlist__combined_branch_type(struct evlist *evlist); +bool perf_evlist__sample_id_all(struct evlist *evlist); +u16 perf_evlist__id_hdr_size(struct evlist *evlist); -int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, +int perf_evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample); -int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist, +int perf_evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp); -bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); -bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); -bool perf_evlist__valid_read_format(struct perf_evlist *evlist); +bool perf_evlist__valid_sample_type(struct evlist *evlist); +bool perf_evlist__valid_sample_id_all(struct evlist *evlist); +bool perf_evlist__valid_read_format(struct evlist *evlist); -void perf_evlist__splice_list_tail(struct perf_evlist *evlist, +void perf_evlist__splice_list_tail(struct evlist *evlist, struct list_head *list); -static inline bool perf_evlist__empty(struct perf_evlist *evlist) +static inline bool perf_evlist__empty(struct evlist *evlist) { - return list_empty(&evlist->entries); + return list_empty(&evlist->core.entries); } -static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) +static inline struct evsel *perf_evlist__first(struct evlist *evlist) { - return list_entry(evlist->entries.next, struct perf_evsel, node); + return list_entry(evlist->core.entries.next, struct evsel, core.node); } -static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) +static inline struct evsel *perf_evlist__last(struct evlist *evlist) { - return list_entry(evlist->entries.prev, struct perf_evsel, node); + return list_entry(evlist->core.entries.prev, struct evsel, core.node); } -size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); +size_t perf_evlist__fprintf(struct evlist *evlist, FILE *fp); -int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size); -int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size); +int perf_evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size); +int perf_evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size); -bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str); -void perf_evlist__to_front(struct perf_evlist *evlist, - struct perf_evsel *move_evsel); +bool perf_evlist__can_select_event(struct evlist *evlist, const char *str); +void perf_evlist__to_front(struct evlist *evlist, + struct evsel *move_evsel); /** * __evlist__for_each_entry - iterate thru all the evsels @@ -253,7 +246,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry(list, evsel) \ - list_for_each_entry(evsel, list, node) + list_for_each_entry(evsel, list, core.node) /** * evlist__for_each_entry - iterate thru all the evsels @@ -261,7 +254,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define evlist__for_each_entry(evlist, evsel) \ - __evlist__for_each_entry(&(evlist)->entries, evsel) + __evlist__for_each_entry(&(evlist)->core.entries, evsel) /** * __evlist__for_each_entry_continue - continue iteration thru all the evsels @@ -269,7 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry_continue(list, evsel) \ - list_for_each_entry_continue(evsel, list, node) + list_for_each_entry_continue(evsel, list, core.node) /** * evlist__for_each_entry_continue - continue iteration thru all the evsels @@ -277,7 +270,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define evlist__for_each_entry_continue(evlist, evsel) \ - __evlist__for_each_entry_continue(&(evlist)->entries, evsel) + __evlist__for_each_entry_continue(&(evlist)->core.entries, evsel) /** * __evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order @@ -285,7 +278,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry_reverse(list, evsel) \ - list_for_each_entry_reverse(evsel, list, node) + list_for_each_entry_reverse(evsel, list, core.node) /** * evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order @@ -293,7 +286,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define evlist__for_each_entry_reverse(evlist, evsel) \ - __evlist__for_each_entry_reverse(&(evlist)->entries, evsel) + __evlist__for_each_entry_reverse(&(evlist)->core.entries, evsel) /** * __evlist__for_each_entry_safe - safely iterate thru all the evsels @@ -302,7 +295,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry_safe(list, tmp, evsel) \ - list_for_each_entry_safe(evsel, tmp, list, node) + list_for_each_entry_safe(evsel, tmp, list, core.node) /** * evlist__for_each_entry_safe - safely iterate thru all the evsels @@ -311,21 +304,21 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @tmp: struct evsel temp iterator */ #define evlist__for_each_entry_safe(evlist, tmp, evsel) \ - __evlist__for_each_entry_safe(&(evlist)->entries, tmp, evsel) + __evlist__for_each_entry_safe(&(evlist)->core.entries, tmp, evsel) -void perf_evlist__set_tracking_event(struct perf_evlist *evlist, - struct perf_evsel *tracking_evsel); +void perf_evlist__set_tracking_event(struct evlist *evlist, + struct evsel *tracking_evsel); -struct perf_evsel * -perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); +struct evsel * +perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str); -struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, +struct evsel *perf_evlist__event2evsel(struct evlist *evlist, union perf_event *event); -bool perf_evlist__exclude_kernel(struct perf_evlist *evlist); +bool perf_evlist__exclude_kernel(struct evlist *evlist); -void perf_evlist__force_leader(struct perf_evlist *evlist); +void perf_evlist__force_leader(struct evlist *evlist); -struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist, - struct perf_evsel *evsel); +struct evsel *perf_evlist__reset_weak_group(struct evlist *evlist, + struct evsel *evsel); #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 52459dd5ad0c..85825384f9e8 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -22,9 +22,12 @@ #include <sys/resource.h> #include <sys/types.h> #include <dirent.h> +#include <stdlib.h> +#include <perf/evsel.h> #include "asm/bug.h" #include "callchain.h" #include "cgroup.h" +#include "counts.h" #include "event.h" #include "evsel.h" #include "evlist.h" @@ -32,12 +35,16 @@ #include "thread_map.h" #include "target.h" #include "perf_regs.h" +#include "record.h" #include "debug.h" #include "trace-event.h" #include "stat.h" #include "string2.h" #include "memswap.h" +#include "util.h" +#include "../perf-sys.h" #include "util/parse-branch-options.h" +#include <internal/xyarray.h> #include <linux/ctype.h> @@ -45,30 +52,30 @@ struct perf_missing_features perf_missing_features; static clockid_t clockid; -static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) +static int perf_evsel__no_extra_init(struct evsel *evsel __maybe_unused) { return 0; } void __weak test_attr__ready(void) { } -static void perf_evsel__no_extra_fini(struct perf_evsel *evsel __maybe_unused) +static void perf_evsel__no_extra_fini(struct evsel *evsel __maybe_unused) { } static struct { size_t size; - int (*init)(struct perf_evsel *evsel); - void (*fini)(struct perf_evsel *evsel); + int (*init)(struct evsel *evsel); + void (*fini)(struct evsel *evsel); } perf_evsel__object = { - .size = sizeof(struct perf_evsel), + .size = sizeof(struct evsel), .init = perf_evsel__no_extra_init, .fini = perf_evsel__no_extra_fini, }; int perf_evsel__object_config(size_t object_size, - int (*init)(struct perf_evsel *evsel), - void (*fini)(struct perf_evsel *evsel)) + int (*init)(struct evsel *evsel), + void (*fini)(struct evsel *evsel)) { if (object_size == 0) @@ -89,7 +96,7 @@ set_methods: return 0; } -#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) int __perf_evsel__sample_size(u64 sample_type) { @@ -113,7 +120,7 @@ int __perf_evsel__sample_size(u64 sample_type) * * This function returns the position of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct - * sample_event. + * perf_record_sample. */ static int __perf_evsel__calc_id_pos(u64 sample_type) { @@ -167,33 +174,33 @@ static int __perf_evsel__calc_is_pos(u64 sample_type) return idx; } -void perf_evsel__calc_id_pos(struct perf_evsel *evsel) +void perf_evsel__calc_id_pos(struct evsel *evsel) { - evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type); - evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type); + evsel->id_pos = __perf_evsel__calc_id_pos(evsel->core.attr.sample_type); + evsel->is_pos = __perf_evsel__calc_is_pos(evsel->core.attr.sample_type); } -void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__set_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit) { - if (!(evsel->attr.sample_type & bit)) { - evsel->attr.sample_type |= bit; + if (!(evsel->core.attr.sample_type & bit)) { + evsel->core.attr.sample_type |= bit; evsel->sample_size += sizeof(u64); perf_evsel__calc_id_pos(evsel); } } -void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__reset_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit) { - if (evsel->attr.sample_type & bit) { - evsel->attr.sample_type &= ~bit; + if (evsel->core.attr.sample_type & bit) { + evsel->core.attr.sample_type &= ~bit; evsel->sample_size -= sizeof(u64); perf_evsel__calc_id_pos(evsel); } } -void perf_evsel__set_sample_id(struct perf_evsel *evsel, +void perf_evsel__set_sample_id(struct evsel *evsel, bool can_sample_identifier) { if (can_sample_identifier) { @@ -202,7 +209,7 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel, } else { perf_evsel__set_sample_bit(evsel, ID); } - evsel->attr.read_format |= PERF_FORMAT_ID; + evsel->core.attr.read_format |= PERF_FORMAT_ID; } /** @@ -213,7 +220,7 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel, * * Return %true if event is function trace event */ -bool perf_evsel__is_function_event(struct perf_evsel *evsel) +bool perf_evsel__is_function_event(struct evsel *evsel) { #define FUNCTION_EVENT "ftrace:function" @@ -223,19 +230,19 @@ bool perf_evsel__is_function_event(struct perf_evsel *evsel) #undef FUNCTION_EVENT } -void perf_evsel__init(struct perf_evsel *evsel, - struct perf_event_attr *attr, int idx) +void evsel__init(struct evsel *evsel, + struct perf_event_attr *attr, int idx) { + perf_evsel__init(&evsel->core, attr); evsel->idx = idx; evsel->tracking = !idx; - evsel->attr = *attr; evsel->leader = evsel; evsel->unit = ""; evsel->scale = 1.0; evsel->max_events = ULONG_MAX; evsel->evlist = NULL; + evsel->bpf_obj = NULL; evsel->bpf_fd = -1; - INIT_LIST_HEAD(&evsel->node); INIT_LIST_HEAD(&evsel->config_terms); perf_evsel__object.init(evsel); evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); @@ -248,18 +255,18 @@ void perf_evsel__init(struct perf_evsel *evsel, evsel->pmu_name = NULL; } -struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) +struct evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) { - struct perf_evsel *evsel = zalloc(perf_evsel__object.size); + struct evsel *evsel = zalloc(perf_evsel__object.size); if (!evsel) return NULL; - perf_evsel__init(evsel, attr, idx); + evsel__init(evsel, attr, idx); if (perf_evsel__is_bpf_output(evsel)) { - evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | + evsel->core.attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD), - evsel->attr.sample_period = 1; + evsel->core.attr.sample_period = 1; } if (perf_evsel__is_clock(evsel)) { @@ -278,17 +285,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) static bool perf_event_can_profile_kernel(void) { - return geteuid() == 0 || perf_event_paranoid() == -1; + return perf_event_paranoid_check(1); } -struct perf_evsel *perf_evsel__new_cycles(bool precise) +struct evsel *perf_evsel__new_cycles(bool precise) { struct perf_event_attr attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, .exclude_kernel = !perf_event_can_profile_kernel(), }; - struct perf_evsel *evsel; + struct evsel *evsel; event_attr_init(&attr); @@ -300,7 +307,7 @@ struct perf_evsel *perf_evsel__new_cycles(bool precise) * to kick in when we return and before perf_evsel__open() is called. */ new_event: - evsel = perf_evsel__new(&attr); + evsel = evsel__new(&attr); if (evsel == NULL) goto out; @@ -315,7 +322,7 @@ new_event: out: return evsel; error_free: - perf_evsel__delete(evsel); + evsel__delete(evsel); evsel = NULL; goto out; } @@ -323,9 +330,9 @@ error_free: /* * Returns pointer with encoded error via <linux/err.h> interface. */ -struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) +struct evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) { - struct perf_evsel *evsel = zalloc(perf_evsel__object.size); + struct evsel *evsel = zalloc(perf_evsel__object.size); int err = -ENOMEM; if (evsel == NULL) { @@ -349,7 +356,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int event_attr_init(&attr); attr.config = evsel->tp_format->id; attr.sample_period = 1; - perf_evsel__init(evsel, &attr, idx); + evsel__init(evsel, &attr, idx); } return evsel; @@ -382,10 +389,10 @@ static const char *__perf_evsel__hw_name(u64 config) return "unknown-hardware"; } -static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size) { int colon = 0, r = 0; - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; bool exclude_guest_default = false; #define MOD_PRINT(context, mod) do { \ @@ -418,9 +425,9 @@ static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t return r; } -static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__hw_name(struct evsel *evsel, char *bf, size_t size) { - int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); + int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->core.attr.config)); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } @@ -444,9 +451,9 @@ static const char *__perf_evsel__sw_name(u64 config) return "unknown-software"; } -static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__sw_name(struct evsel *evsel, char *bf, size_t size) { - int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); + int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->core.attr.config)); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } @@ -468,9 +475,9 @@ static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) return r; } -static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__bp_name(struct evsel *evsel, char *bf, size_t size) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } @@ -568,15 +575,15 @@ out_err: return scnprintf(bf, size, "%s", err); } -static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__hw_cache_name(struct evsel *evsel, char *bf, size_t size) { - int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); + int ret = __perf_evsel__hw_cache_name(evsel->core.attr.config, bf, size); return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); } -static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__raw_name(struct evsel *evsel, char *bf, size_t size) { - int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); + int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->core.attr.config); return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); } @@ -586,7 +593,7 @@ static int perf_evsel__tool_name(char *bf, size_t size) return ret; } -const char *perf_evsel__name(struct perf_evsel *evsel) +const char *perf_evsel__name(struct evsel *evsel) { char bf[128]; @@ -596,7 +603,7 @@ const char *perf_evsel__name(struct perf_evsel *evsel) if (evsel->name) return evsel->name; - switch (evsel->attr.type) { + switch (evsel->core.attr.type) { case PERF_TYPE_RAW: perf_evsel__raw_name(evsel, bf, sizeof(bf)); break; @@ -626,7 +633,7 @@ const char *perf_evsel__name(struct perf_evsel *evsel) default: scnprintf(bf, sizeof(bf), "unknown attr type: %d", - evsel->attr.type); + evsel->core.attr.type); break; } @@ -638,7 +645,7 @@ out_unknown: return "unknown"; } -const char *perf_evsel__group_name(struct perf_evsel *evsel) +const char *perf_evsel__group_name(struct evsel *evsel) { return evsel->group_name ?: "anon group"; } @@ -653,10 +660,10 @@ const char *perf_evsel__group_name(struct perf_evsel *evsel) * For record -e 'cycles,instructions' and report --group * 'cycles:u, instructions:u' */ -int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) +int perf_evsel__group_desc(struct evsel *evsel, char *buf, size_t size) { int ret = 0; - struct perf_evsel *pos; + struct evsel *pos; const char *group_name = perf_evsel__group_name(evsel); if (!evsel->forced_leader) @@ -675,12 +682,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) return ret; } -static void __perf_evsel__config_callchain(struct perf_evsel *evsel, +static void __perf_evsel__config_callchain(struct evsel *evsel, struct record_opts *opts, struct callchain_param *param) { bool function = perf_evsel__is_function_event(evsel); - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; perf_evsel__set_sample_bit(evsel, CALLCHAIN); @@ -734,7 +741,7 @@ static void __perf_evsel__config_callchain(struct perf_evsel *evsel, } } -void perf_evsel__config_callchain(struct perf_evsel *evsel, +void perf_evsel__config_callchain(struct evsel *evsel, struct record_opts *opts, struct callchain_param *param) { @@ -743,10 +750,10 @@ void perf_evsel__config_callchain(struct perf_evsel *evsel, } static void -perf_evsel__reset_callgraph(struct perf_evsel *evsel, +perf_evsel__reset_callgraph(struct evsel *evsel, struct callchain_param *param) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; perf_evsel__reset_sample_bit(evsel, CALLCHAIN); if (param->record_mode == CALLCHAIN_LBR) { @@ -760,12 +767,12 @@ perf_evsel__reset_callgraph(struct perf_evsel *evsel, } } -static void apply_config_terms(struct perf_evsel *evsel, +static void apply_config_terms(struct evsel *evsel, struct record_opts *opts, bool track) { struct perf_evsel_config_term *term; struct list_head *config_terms = &evsel->config_terms; - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; /* callgraph default */ struct callchain_param param = { .record_mode = callchain_param.record_mode, @@ -832,6 +839,9 @@ static void apply_config_terms(struct perf_evsel *evsel, break; case PERF_EVSEL__CONFIG_TERM_PERCORE: break; + case PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT: + attr->aux_output = term->val.aux_output ? 1 : 0; + break; default: break; } @@ -878,17 +888,17 @@ static void apply_config_terms(struct perf_evsel *evsel, if (sample_address) { perf_evsel__set_sample_bit(evsel, ADDR); perf_evsel__set_sample_bit(evsel, DATA_SRC); - evsel->attr.mmap_data = track; + evsel->core.attr.mmap_data = track; } perf_evsel__config_callchain(evsel, opts, ¶m); } } } -static bool is_dummy_event(struct perf_evsel *evsel) +static bool is_dummy_event(struct evsel *evsel) { - return (evsel->attr.type == PERF_TYPE_SOFTWARE) && - (evsel->attr.config == PERF_COUNT_SW_DUMMY); + return (evsel->core.attr.type == PERF_TYPE_SOFTWARE) && + (evsel->core.attr.config == PERF_COUNT_SW_DUMMY); } /* @@ -919,11 +929,11 @@ static bool is_dummy_event(struct perf_evsel *evsel) * enable/disable events specifically, as there's no * initial traced exec call. */ -void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, +void perf_evsel__config(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain) { - struct perf_evsel *leader = evsel->leader; - struct perf_event_attr *attr = &evsel->attr; + struct evsel *leader = evsel->leader; + struct perf_event_attr *attr = &evsel->core.attr; int track = evsel->tracking; bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; @@ -947,7 +957,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * Apply group format only if we belong to group * with more than one members. */ - if (leader->nr_members > 1) { + if (leader->core.nr_members > 1) { attr->read_format |= PERF_FORMAT_GROUP; attr->inherit = 0; } @@ -984,14 +994,14 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * event to follow the master sample_type to ease up * report. */ - attr->sample_type = leader->attr.sample_type; + attr->sample_type = leader->core.attr.sample_type; } if (opts->no_samples) attr->sample_freq = 0; if (opts->inherit_stat) { - evsel->attr.read_format |= + evsel->core.attr.read_format |= PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; @@ -1009,7 +1019,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * fault handler and its overall trickiness nature. */ if (perf_evsel__is_function_event(evsel)) - evsel->attr.exclude_callchain_user = 1; + evsel->core.attr.exclude_callchain_user = 1; if (callchain && callchain->enabled && !evsel->no_aux_samples) perf_evsel__config_callchain(evsel, opts, callchain); @@ -1065,8 +1075,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, attr->mmap2 = track && !perf_missing_features.mmap2; attr->comm = track; attr->ksymbol = track && !perf_missing_features.ksymbol; - attr->bpf_event = track && !opts->no_bpf_event && - !perf_missing_features.bpf_event; + attr->bpf_event = track && !opts->no_bpf_event && !perf_missing_features.bpf; if (opts->record_namespaces) attr->namespaces = track; @@ -1078,7 +1087,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, perf_evsel__set_sample_bit(evsel, TRANSACTION); if (opts->running_time) { - evsel->attr.read_format |= + evsel->core.attr.read_format |= PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; } @@ -1124,8 +1133,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, attr->exclude_user = 1; } - if (evsel->own_cpus || evsel->unit) - evsel->attr.read_format |= PERF_FORMAT_ID; + if (evsel->core.own_cpus || evsel->unit) + evsel->core.attr.read_format |= PERF_FORMAT_ID; /* * Apply event specific term settings, @@ -1152,48 +1161,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, perf_evsel__reset_sample_bit(evsel, BRANCH_STACK); } -static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) -{ - evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); - - if (evsel->fd) { - int cpu, thread; - for (cpu = 0; cpu < ncpus; cpu++) { - for (thread = 0; thread < nthreads; thread++) { - FD(evsel, cpu, thread) = -1; - } - } - } - - return evsel->fd != NULL ? 0 : -ENOMEM; -} - -static int perf_evsel__run_ioctl(struct perf_evsel *evsel, - int ioc, void *arg) -{ - int cpu, thread; - - for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) { - for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) { - int fd = FD(evsel, cpu, thread), - err = ioctl(fd, ioc, arg); - - if (err) - return err; - } - } - - return 0; -} - -int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter) -{ - return perf_evsel__run_ioctl(evsel, - PERF_EVENT_IOC_SET_FILTER, - (void *)filter); -} - -int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter) +int perf_evsel__set_filter(struct evsel *evsel, const char *filter) { char *new_filter = strdup(filter); @@ -1206,7 +1174,7 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter) return -1; } -static int perf_evsel__append_filter(struct perf_evsel *evsel, +static int perf_evsel__append_filter(struct evsel *evsel, const char *fmt, const char *filter) { char *new_filter; @@ -1223,19 +1191,19 @@ static int perf_evsel__append_filter(struct perf_evsel *evsel, return -1; } -int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter) +int perf_evsel__append_tp_filter(struct evsel *evsel, const char *filter) { return perf_evsel__append_filter(evsel, "(%s) && (%s)", filter); } -int perf_evsel__append_addr_filter(struct perf_evsel *evsel, const char *filter) +int perf_evsel__append_addr_filter(struct evsel *evsel, const char *filter) { return perf_evsel__append_filter(evsel, "%s,%s", filter); } -int perf_evsel__enable(struct perf_evsel *evsel) +int evsel__enable(struct evsel *evsel) { - int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0); + int err = perf_evsel__enable(&evsel->core); if (!err) evsel->disabled = false; @@ -1243,9 +1211,9 @@ int perf_evsel__enable(struct perf_evsel *evsel) return err; } -int perf_evsel__disable(struct perf_evsel *evsel) +int evsel__disable(struct evsel *evsel) { - int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0); + int err = perf_evsel__disable(&evsel->core); /* * We mark it disabled here so that tools that disable a event can * ignore events after they disable it. I.e. the ring buffer may have @@ -1258,7 +1226,7 @@ int perf_evsel__disable(struct perf_evsel *evsel) return err; } -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) +int perf_evsel__alloc_id(struct evsel *evsel, int ncpus, int nthreads) { if (ncpus == 0 || nthreads == 0) return 0; @@ -1280,13 +1248,7 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) return 0; } -static void perf_evsel__free_fd(struct perf_evsel *evsel) -{ - xyarray__delete(evsel->fd); - evsel->fd = NULL; -} - -static void perf_evsel__free_id(struct perf_evsel *evsel) +static void perf_evsel__free_id(struct evsel *evsel) { xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; @@ -1294,7 +1256,7 @@ static void perf_evsel__free_id(struct perf_evsel *evsel) evsel->ids = 0; } -static void perf_evsel__free_config_terms(struct perf_evsel *evsel) +static void perf_evsel__free_config_terms(struct evsel *evsel) { struct perf_evsel_config_term *term, *h; @@ -1304,41 +1266,30 @@ static void perf_evsel__free_config_terms(struct perf_evsel *evsel) } } -void perf_evsel__close_fd(struct perf_evsel *evsel) +void perf_evsel__exit(struct evsel *evsel) { - int cpu, thread; - - for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) - for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) { - close(FD(evsel, cpu, thread)); - FD(evsel, cpu, thread) = -1; - } -} - -void perf_evsel__exit(struct perf_evsel *evsel) -{ - assert(list_empty(&evsel->node)); + assert(list_empty(&evsel->core.node)); assert(evsel->evlist == NULL); perf_evsel__free_counts(evsel); - perf_evsel__free_fd(evsel); + perf_evsel__free_fd(&evsel->core); perf_evsel__free_id(evsel); perf_evsel__free_config_terms(evsel); cgroup__put(evsel->cgrp); - cpu_map__put(evsel->cpus); - cpu_map__put(evsel->own_cpus); - thread_map__put(evsel->threads); + perf_cpu_map__put(evsel->core.cpus); + perf_cpu_map__put(evsel->core.own_cpus); + perf_thread_map__put(evsel->core.threads); zfree(&evsel->group_name); zfree(&evsel->name); perf_evsel__object.fini(evsel); } -void perf_evsel__delete(struct perf_evsel *evsel) +void evsel__delete(struct evsel *evsel) { perf_evsel__exit(evsel); free(evsel); } -void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread, +void perf_evsel__compute_deltas(struct evsel *evsel, int cpu, int thread, struct perf_counts_values *count) { struct perf_counts_values tmp; @@ -1378,57 +1329,16 @@ void perf_counts_values__scale(struct perf_counts_values *count, *pscaled = scaled; } -static int perf_evsel__read_size(struct perf_evsel *evsel) -{ - u64 read_format = evsel->attr.read_format; - int entry = sizeof(u64); /* value */ - int size = 0; - int nr = 1; - - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - size += sizeof(u64); - - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - size += sizeof(u64); - - if (read_format & PERF_FORMAT_ID) - entry += sizeof(u64); - - if (read_format & PERF_FORMAT_GROUP) { - nr = evsel->nr_members; - size += sizeof(u64); - } - - size += entry * nr; - return size; -} - -int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, - struct perf_counts_values *count) -{ - size_t size = perf_evsel__read_size(evsel); - - memset(count, 0, sizeof(*count)); - - if (FD(evsel, cpu, thread) < 0) - return -EINVAL; - - if (readn(FD(evsel, cpu, thread), count->values, size) <= 0) - return -errno; - - return 0; -} - static int -perf_evsel__read_one(struct perf_evsel *evsel, int cpu, int thread) +perf_evsel__read_one(struct evsel *evsel, int cpu, int thread) { struct perf_counts_values *count = perf_counts(evsel->counts, cpu, thread); - return perf_evsel__read(evsel, cpu, thread, count); + return perf_evsel__read(&evsel->core, cpu, thread, count); } static void -perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, +perf_evsel__set_count(struct evsel *counter, int cpu, int thread, u64 val, u64 ena, u64 run) { struct perf_counts_values *count; @@ -1438,20 +1348,21 @@ perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, count->val = val; count->ena = ena; count->run = run; - count->loaded = true; + + perf_counts__set_loaded(counter->counts, cpu, thread, true); } static int -perf_evsel__process_group_data(struct perf_evsel *leader, +perf_evsel__process_group_data(struct evsel *leader, int cpu, int thread, u64 *data) { - u64 read_format = leader->attr.read_format; + u64 read_format = leader->core.attr.read_format; struct sample_read_value *v; u64 nr, ena = 0, run = 0, i; nr = *data++; - if (nr != (u64) leader->nr_members) + if (nr != (u64) leader->core.nr_members) return -EINVAL; if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) @@ -1466,7 +1377,7 @@ perf_evsel__process_group_data(struct perf_evsel *leader, v[0].value, ena, run); for (i = 1; i < nr; i++) { - struct perf_evsel *counter; + struct evsel *counter; counter = perf_evlist__id2evsel(leader->evlist, v[i].id); if (!counter) @@ -1480,11 +1391,11 @@ perf_evsel__process_group_data(struct perf_evsel *leader, } static int -perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) +perf_evsel__read_group(struct evsel *leader, int cpu, int thread) { struct perf_stat_evsel *ps = leader->stats; - u64 read_format = leader->attr.read_format; - int size = perf_evsel__read_size(leader); + u64 read_format = leader->core.attr.read_format; + int size = perf_evsel__read_size(&leader->core); u64 *data = ps->group_data; if (!(read_format & PERF_FORMAT_ID)) @@ -1510,9 +1421,9 @@ perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) return perf_evsel__process_group_data(leader, cpu, thread, data); } -int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread) +int perf_evsel__read_counter(struct evsel *evsel, int cpu, int thread) { - u64 read_format = evsel->attr.read_format; + u64 read_format = evsel->core.attr.read_format; if (read_format & PERF_FORMAT_GROUP) return perf_evsel__read_group(evsel, cpu, thread); @@ -1520,7 +1431,7 @@ int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread) return perf_evsel__read_one(evsel, cpu, thread); } -int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, +int __perf_evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread, bool scale) { struct perf_counts_values count; @@ -1541,9 +1452,9 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, return 0; } -static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) +static int get_group_fd(struct evsel *evsel, int cpu, int thread) { - struct perf_evsel *leader = evsel->leader; + struct evsel *leader = evsel->leader; int fd; if (perf_evsel__is_group_leader(evsel)) @@ -1553,7 +1464,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) * Leader must be already processed/open, * if not it's a bug. */ - BUG_ON(!leader->fd); + BUG_ON(!leader->core.fd); fd = FD(leader, cpu, thread); BUG_ON(fd == -1); @@ -1684,6 +1595,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, PRINT_ATTRf(namespaces, p_unsigned); PRINT_ATTRf(ksymbol, p_unsigned); PRINT_ATTRf(bpf_event, p_unsigned); + PRINT_ATTRf(aux_output, p_unsigned); PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); PRINT_ATTRf(bp_type, p_unsigned); @@ -1706,7 +1618,7 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, " %-32s %s\n", name, val); } -static void perf_evsel__remove_fd(struct perf_evsel *pos, +static void perf_evsel__remove_fd(struct evsel *pos, int nr_cpus, int nr_threads, int thread_idx) { @@ -1715,11 +1627,11 @@ static void perf_evsel__remove_fd(struct perf_evsel *pos, FD(pos, cpu, thread) = FD(pos, cpu, thread + 1); } -static int update_fds(struct perf_evsel *evsel, +static int update_fds(struct evsel *evsel, int nr_cpus, int cpu_idx, int nr_threads, int thread_idx) { - struct perf_evsel *pos; + struct evsel *pos; if (cpu_idx >= nr_cpus || thread_idx >= nr_threads) return -EINVAL; @@ -1739,12 +1651,12 @@ static int update_fds(struct perf_evsel *evsel, return 0; } -static bool ignore_missing_thread(struct perf_evsel *evsel, +static bool ignore_missing_thread(struct evsel *evsel, int nr_cpus, int cpu, - struct thread_map *threads, + struct perf_thread_map *threads, int thread, int err) { - pid_t ignore_pid = thread_map__pid(threads, thread); + pid_t ignore_pid = perf_thread_map__pid(threads, thread); if (!evsel->ignore_missing_thread) return false; @@ -1786,18 +1698,18 @@ static void display_attr(struct perf_event_attr *attr) } } -static int perf_event_open(struct perf_evsel *evsel, +static int perf_event_open(struct evsel *evsel, pid_t pid, int cpu, int group_fd, unsigned long flags) { - int precise_ip = evsel->attr.precise_ip; + int precise_ip = evsel->core.attr.precise_ip; int fd; while (1) { pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", pid, cpu, group_fd, flags); - fd = sys_perf_event_open(&evsel->attr, pid, cpu, group_fd, flags); + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, group_fd, flags); if (fd >= 0) break; @@ -1809,36 +1721,37 @@ static int perf_event_open(struct perf_evsel *evsel, * We tried all the precise_ip values, and it's * still failing, so leave it to standard fallback. */ - if (!evsel->attr.precise_ip) { - evsel->attr.precise_ip = precise_ip; + if (!evsel->core.attr.precise_ip) { + evsel->core.attr.precise_ip = precise_ip; break; } pr_debug2("\nsys_perf_event_open failed, error %d\n", -ENOTSUP); - evsel->attr.precise_ip--; - pr_debug2("decreasing precise_ip by one (%d)\n", evsel->attr.precise_ip); - display_attr(&evsel->attr); + evsel->core.attr.precise_ip--; + pr_debug2("decreasing precise_ip by one (%d)\n", evsel->core.attr.precise_ip); + display_attr(&evsel->core.attr); } return fd; } -int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads) +int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) { int cpu, thread, nthreads; unsigned long flags = PERF_FLAG_FD_CLOEXEC; int pid = -1, err; enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; - if (perf_missing_features.write_backward && evsel->attr.write_backward) + if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) || + (perf_missing_features.aux_output && evsel->core.attr.aux_output)) return -EINVAL; if (cpus == NULL) { - static struct cpu_map *empty_cpu_map; + static struct perf_cpu_map *empty_cpu_map; if (empty_cpu_map == NULL) { - empty_cpu_map = cpu_map__dummy_new(); + empty_cpu_map = perf_cpu_map__dummy_new(); if (empty_cpu_map == NULL) return -ENOMEM; } @@ -1847,7 +1760,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, } if (threads == NULL) { - static struct thread_map *empty_thread_map; + static struct perf_thread_map *empty_thread_map; if (empty_thread_map == NULL) { empty_thread_map = thread_map__new_by_tid(-1); @@ -1863,8 +1776,8 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, else nthreads = threads->nr; - if (evsel->fd == NULL && - perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0) + if (evsel->core.fd == NULL && + perf_evsel__alloc_fd(&evsel->core, cpus->nr, nthreads) < 0) return -ENOMEM; if (evsel->cgrp) { @@ -1874,31 +1787,31 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, fallback_missing_features: if (perf_missing_features.clockid_wrong) - evsel->attr.clockid = CLOCK_MONOTONIC; /* should always work */ + evsel->core.attr.clockid = CLOCK_MONOTONIC; /* should always work */ if (perf_missing_features.clockid) { - evsel->attr.use_clockid = 0; - evsel->attr.clockid = 0; + evsel->core.attr.use_clockid = 0; + evsel->core.attr.clockid = 0; } if (perf_missing_features.cloexec) flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; if (perf_missing_features.mmap2) - evsel->attr.mmap2 = 0; + evsel->core.attr.mmap2 = 0; if (perf_missing_features.exclude_guest) - evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; + evsel->core.attr.exclude_guest = evsel->core.attr.exclude_host = 0; if (perf_missing_features.lbr_flags) - evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | + evsel->core.attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | PERF_SAMPLE_BRANCH_NO_CYCLES); - if (perf_missing_features.group_read && evsel->attr.inherit) - evsel->attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); + if (perf_missing_features.group_read && evsel->core.attr.inherit) + evsel->core.attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); if (perf_missing_features.ksymbol) - evsel->attr.ksymbol = 0; - if (perf_missing_features.bpf_event) - evsel->attr.bpf_event = 0; + evsel->core.attr.ksymbol = 0; + if (perf_missing_features.bpf) + evsel->core.attr.bpf_event = 0; retry_sample_id: if (perf_missing_features.sample_id_all) - evsel->attr.sample_id_all = 0; + evsel->core.attr.sample_id_all = 0; - display_attr(&evsel->attr); + display_attr(&evsel->core.attr); for (cpu = 0; cpu < cpus->nr; cpu++) { @@ -1906,7 +1819,7 @@ retry_sample_id: int fd, group_fd; if (!evsel->cgrp && !evsel->system_wide) - pid = thread_map__pid(threads, thread); + pid = perf_thread_map__pid(threads, thread); group_fd = get_group_fd(evsel, cpu, thread); retry_open: @@ -2005,23 +1918,27 @@ try_fallback: * Must probe features in the order they were added to the * perf_event_attr interface. */ - if (!perf_missing_features.bpf_event && evsel->attr.bpf_event) { - perf_missing_features.bpf_event = true; + if (!perf_missing_features.aux_output && evsel->core.attr.aux_output) { + perf_missing_features.aux_output = true; + pr_debug2("Kernel has no attr.aux_output support, bailing out\n"); + goto out_close; + } else if (!perf_missing_features.bpf && evsel->core.attr.bpf_event) { + perf_missing_features.bpf = true; pr_debug2("switching off bpf_event\n"); goto fallback_missing_features; - } else if (!perf_missing_features.ksymbol && evsel->attr.ksymbol) { + } else if (!perf_missing_features.ksymbol && evsel->core.attr.ksymbol) { perf_missing_features.ksymbol = true; pr_debug2("switching off ksymbol\n"); goto fallback_missing_features; - } else if (!perf_missing_features.write_backward && evsel->attr.write_backward) { + } else if (!perf_missing_features.write_backward && evsel->core.attr.write_backward) { perf_missing_features.write_backward = true; pr_debug2("switching off write_backward\n"); goto out_close; - } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { + } else if (!perf_missing_features.clockid_wrong && evsel->core.attr.use_clockid) { perf_missing_features.clockid_wrong = true; pr_debug2("switching off clockid\n"); goto fallback_missing_features; - } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { + } else if (!perf_missing_features.clockid && evsel->core.attr.use_clockid) { perf_missing_features.clockid = true; pr_debug2("switching off use_clockid\n"); goto fallback_missing_features; @@ -2029,12 +1946,12 @@ try_fallback: perf_missing_features.cloexec = true; pr_debug2("switching off cloexec flag\n"); goto fallback_missing_features; - } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { + } else if (!perf_missing_features.mmap2 && evsel->core.attr.mmap2) { perf_missing_features.mmap2 = true; pr_debug2("switching off mmap2\n"); goto fallback_missing_features; } else if (!perf_missing_features.exclude_guest && - (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { + (evsel->core.attr.exclude_guest || evsel->core.attr.exclude_host)) { perf_missing_features.exclude_guest = true; pr_debug2("switching off exclude_guest, exclude_host\n"); goto fallback_missing_features; @@ -2043,15 +1960,15 @@ try_fallback: pr_debug2("switching off sample_id_all\n"); goto retry_sample_id; } else if (!perf_missing_features.lbr_flags && - (evsel->attr.branch_sample_type & + (evsel->core.attr.branch_sample_type & (PERF_SAMPLE_BRANCH_NO_CYCLES | PERF_SAMPLE_BRANCH_NO_FLAGS))) { perf_missing_features.lbr_flags = true; pr_debug2("switching off branch sample type no (cycles/flags)\n"); goto fallback_missing_features; } else if (!perf_missing_features.group_read && - evsel->attr.inherit && - (evsel->attr.read_format & PERF_FORMAT_GROUP) && + evsel->core.attr.inherit && + (evsel->core.attr.read_format & PERF_FORMAT_GROUP) && perf_evsel__is_group_leader(evsel)) { perf_missing_features.group_read = true; pr_debug2("switching off group read\n"); @@ -2071,34 +1988,30 @@ out_close: return err; } -void perf_evsel__close(struct perf_evsel *evsel) +void evsel__close(struct evsel *evsel) { - if (evsel->fd == NULL) - return; - - perf_evsel__close_fd(evsel); - perf_evsel__free_fd(evsel); + perf_evsel__close(&evsel->core); perf_evsel__free_id(evsel); } -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus) +int perf_evsel__open_per_cpu(struct evsel *evsel, + struct perf_cpu_map *cpus) { - return perf_evsel__open(evsel, cpus, NULL); + return evsel__open(evsel, cpus, NULL); } -int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads) +int perf_evsel__open_per_thread(struct evsel *evsel, + struct perf_thread_map *threads) { - return perf_evsel__open(evsel, NULL, threads); + return evsel__open(evsel, NULL, threads); } -static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, +static int perf_evsel__parse_id_sample(const struct evsel *evsel, const union perf_event *event, struct perf_sample *sample) { - u64 type = evsel->attr.sample_type; - const u64 *array = event->sample.array; + u64 type = evsel->core.attr.sample_type; + const __u64 *array = event->sample.array; bool swapped = evsel->needs_swap; union u64_swap u; @@ -2183,12 +2096,12 @@ perf_event__check_size(union perf_event *event, unsigned int sample_size) return 0; } -int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, +int perf_evsel__parse_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *data) { - u64 type = evsel->attr.sample_type; + u64 type = evsel->core.attr.sample_type; bool swapped = evsel->needs_swap; - const u64 *array; + const __u64 *array; u16 max_size = event->header.size; const void *endp = (void *)event + max_size; u64 sz; @@ -2202,14 +2115,14 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; - data->period = evsel->attr.sample_period; + data->period = evsel->core.attr.sample_period; data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; data->misc = event->header.misc; data->id = -1ULL; data->data_src = PERF_MEM_DATA_SRC_NONE; if (event->header.type != PERF_RECORD_SAMPLE) { - if (!evsel->attr.sample_id_all) + if (!evsel->core.attr.sample_id_all) return 0; return perf_evsel__parse_id_sample(evsel, event, data); } @@ -2282,7 +2195,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, } if (type & PERF_SAMPLE_READ) { - u64 read_format = evsel->attr.read_format; + u64 read_format = evsel->core.attr.read_format; OVERFLOW_CHECK_u64(array); if (read_format & PERF_FORMAT_GROUP) @@ -2387,7 +2300,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; if (data->user_regs.abi) { - u64 mask = evsel->attr.sample_regs_user; + u64 mask = evsel->core.attr.sample_regs_user; sz = hweight64(mask) * sizeof(u64); OVERFLOW_CHECK(array, sz, max_size); @@ -2443,7 +2356,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) { - u64 mask = evsel->attr.sample_regs_intr; + u64 mask = evsel->core.attr.sample_regs_intr; sz = hweight64(mask) * sizeof(u64); OVERFLOW_CHECK(array, sz, max_size); @@ -2462,12 +2375,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, return 0; } -int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, +int perf_evsel__parse_sample_timestamp(struct evsel *evsel, union perf_event *event, u64 *timestamp) { - u64 type = evsel->attr.sample_type; - const u64 *array; + u64 type = evsel->core.attr.sample_type; + const __u64 *array; if (!(type & PERF_SAMPLE_TIME)) return -1; @@ -2477,7 +2390,7 @@ int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, .time = -1ULL, }; - if (!evsel->attr.sample_id_all) + if (!evsel->core.attr.sample_id_all) return -1; if (perf_evsel__parse_id_sample(evsel, event, &data)) return -1; @@ -2509,7 +2422,7 @@ int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) { - size_t sz, result = sizeof(struct sample_event); + size_t sz, result = sizeof(struct perf_record_sample); if (type & PERF_SAMPLE_IDENTIFIER) result += sizeof(u64); @@ -2618,7 +2531,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, const struct perf_sample *sample) { - u64 *array; + __u64 *array; size_t sz; /* * used for cross-endian analysis. See git commit 65014ab3 @@ -2783,12 +2696,12 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, return 0; } -struct tep_format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) +struct tep_format_field *perf_evsel__field(struct evsel *evsel, const char *name) { return tep_find_field(evsel->tp_format, name); } -void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, +void *perf_evsel__rawptr(struct evsel *evsel, struct perf_sample *sample, const char *name) { struct tep_format_field *field = perf_evsel__field(evsel, name); @@ -2846,7 +2759,7 @@ u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sam return 0; } -u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, +u64 perf_evsel__intval(struct evsel *evsel, struct perf_sample *sample, const char *name) { struct tep_format_field *field = perf_evsel__field(evsel, name); @@ -2857,14 +2770,14 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return field ? format_field__intval(field, sample, evsel->needs_swap) : 0; } -bool perf_evsel__fallback(struct perf_evsel *evsel, int err, +bool perf_evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize) { int paranoid; if ((err == ENOENT || err == ENXIO || err == ENODEV) && - evsel->attr.type == PERF_TYPE_HARDWARE && - evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { + evsel->core.attr.type == PERF_TYPE_HARDWARE && + evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES) { /* * If it's cycles then fall back to hrtimer based * cpu-clock-tick sw counter, which is always available even if @@ -2876,12 +2789,12 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, scnprintf(msg, msgsize, "%s", "The cycles event is not supported, trying to fall back to cpu-clock-ticks"); - evsel->attr.type = PERF_TYPE_SOFTWARE; - evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; + evsel->core.attr.type = PERF_TYPE_SOFTWARE; + evsel->core.attr.config = PERF_COUNT_SW_CPU_CLOCK; zfree(&evsel->name); return true; - } else if (err == EACCES && !evsel->attr.exclude_kernel && + } else if (err == EACCES && !evsel->core.attr.exclude_kernel && (paranoid = perf_event_paranoid()) > 1) { const char *name = perf_evsel__name(evsel); char *new_name; @@ -2900,7 +2813,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, evsel->name = new_name; scnprintf(msg, msgsize, "kernel.perf_event_paranoid=%d, trying to fall back to excluding kernel samples", paranoid); - evsel->attr.exclude_kernel = 1; + evsel->core.attr.exclude_kernel = 1; return true; } @@ -2944,7 +2857,7 @@ static bool find_process(const char *name) return ret ? false : true; } -int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, +int perf_evsel__open_strerror(struct evsel *evsel, struct target *target, int err, char *msg, size_t size) { char sbuf[STRERR_BUFSIZE]; @@ -2997,15 +2910,15 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "No such device - did you specify an out-of-range profile CPU?"); break; case EOPNOTSUPP: - if (evsel->attr.sample_period != 0) + if (evsel->core.attr.sample_period != 0) return scnprintf(msg, size, "%s: PMU Hardware doesn't support sampling/overflow-interrupts. Try 'perf stat'", perf_evsel__name(evsel)); - if (evsel->attr.precise_ip) + if (evsel->core.attr.precise_ip) return scnprintf(msg, size, "%s", "\'precise\' request may not be supported. Try removing 'p' modifier."); #if defined(__i386__) || defined(__x86_64__) - if (evsel->attr.type == PERF_TYPE_HARDWARE) + if (evsel->core.attr.type == PERF_TYPE_HARDWARE) return scnprintf(msg, size, "%s", "No hardware sampling interrupt available.\n"); #endif @@ -3017,12 +2930,14 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "We found oprofile daemon running, please stop it and try again."); break; case EINVAL: - if (evsel->attr.write_backward && perf_missing_features.write_backward) + if (evsel->core.attr.write_backward && perf_missing_features.write_backward) return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel."); if (perf_missing_features.clockid) return scnprintf(msg, size, "clockid feature not supported."); if (perf_missing_features.clockid_wrong) return scnprintf(msg, size, "wrong clockid (%d).", clockid); + if (perf_missing_features.aux_output) + return scnprintf(msg, size, "The 'aux_output' feature is not supported, update the kernel."); break; default: break; @@ -3035,19 +2950,19 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, perf_evsel__name(evsel)); } -struct perf_env *perf_evsel__env(struct perf_evsel *evsel) +struct perf_env *perf_evsel__env(struct evsel *evsel) { if (evsel && evsel->evlist) return evsel->evlist->env; return NULL; } -static int store_evsel_ids(struct perf_evsel *evsel, struct perf_evlist *evlist) +static int store_evsel_ids(struct evsel *evsel, struct evlist *evlist) { int cpu, thread; - for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) { - for (thread = 0; thread < xyarray__max_y(evsel->fd); + for (cpu = 0; cpu < xyarray__max_x(evsel->core.fd); cpu++) { + for (thread = 0; thread < xyarray__max_y(evsel->core.fd); thread++) { int fd = FD(evsel, cpu, thread); @@ -3060,10 +2975,10 @@ static int store_evsel_ids(struct perf_evsel *evsel, struct perf_evlist *evlist) return 0; } -int perf_evsel__store_ids(struct perf_evsel *evsel, struct perf_evlist *evlist) +int perf_evsel__store_ids(struct evsel *evsel, struct evlist *evlist) { - struct cpu_map *cpus = evsel->cpus; - struct thread_map *threads = evsel->threads; + struct perf_cpu_map *cpus = evsel->core.cpus; + struct perf_thread_map *threads = evsel->core.threads; if (perf_evsel__alloc_id(evsel, cpus->nr, threads->nr)) return -ENOMEM; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index cad54e8ba522..68321d10eb2d 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -4,15 +4,18 @@ #include <linux/list.h> #include <stdbool.h> -#include <stddef.h> +#include <stdio.h> +#include <sys/types.h> #include <linux/perf_event.h> #include <linux/types.h> -#include "xyarray.h" +#include <internal/evsel.h> +#include <perf/evsel.h> #include "symbol_conf.h" -#include "cpumap.h" -#include "counts.h" +#include <internal/cpumap.h> -struct perf_evsel; +struct addr_location; +struct evsel; +union perf_event; /* * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are @@ -21,7 +24,14 @@ struct perf_evsel; struct perf_sample_id { struct hlist_node node; u64 id; - struct perf_evsel *evsel; + struct evsel *evsel; + /* + * 'idx' will be used for AUX area sampling. A sample will have AUX area + * data that will be queued for decoding, where there are separate + * queues for each CPU (per-cpu tracing) or task (per-thread tracing). + * The sample ID can be used to lookup 'idx' which is effectively the + * queue number. + */ int idx; int cpu; pid_t tid; @@ -51,6 +61,7 @@ enum term_type { PERF_EVSEL__CONFIG_TERM_DRV_CFG, PERF_EVSEL__CONFIG_TERM_BRANCH, PERF_EVSEL__CONFIG_TERM_PERCORE, + PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT, }; struct perf_evsel_config_term { @@ -69,6 +80,7 @@ struct perf_evsel_config_term { char *branch; unsigned long max_events; bool percore; + bool aux_output; } val; bool weak; }; @@ -82,28 +94,29 @@ enum perf_tool_event { PERF_TOOL_DURATION_TIME = 1, }; -/** struct perf_evsel - event selector +struct bpf_object; +struct perf_counts; +struct xyarray; + +/** struct evsel - event selector * * @evlist - evlist this evsel is in, if it is in one. - * @node - To insert it into evlist->entries or in other list_heads, say in - * the event parsing routines. + * @core - libperf evsel object * @name - Can be set to retain the original event name passed by the user, * so that when showing results in tools such as 'perf stat', we * show the name used, not some alias. * @id_pos: the position of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of - * struct sample_event + * struct perf_record_sample * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all * is used there is an id sample appended to non-sample events * @priv: And what is in its containing unnamed union are tool specific */ -struct perf_evsel { - struct list_head node; - struct perf_evlist *evlist; - struct perf_event_attr attr; +struct evsel { + struct perf_evsel core; + struct evlist *evlist; char *filter; - struct xyarray *fd; struct xyarray *sample_id; u64 *id; struct perf_counts *counts; @@ -122,9 +135,6 @@ struct perf_evsel { u64 db_id; struct cgroup *cgrp; void *handler; - struct cpu_map *cpus; - struct cpu_map *own_cpus; - struct thread_map *threads; unsigned int sample_size; int id_pos; int is_pos; @@ -145,19 +155,20 @@ struct perf_evsel { bool use_uncore_alias; /* parse modifier helper */ int exclude_GH; - int nr_members; int sample_read; unsigned long *per_pkg_mask; - struct perf_evsel *leader; + struct evsel *leader; char *group_name; bool cmdline_group_boundary; struct list_head config_terms; + struct bpf_object *bpf_obj; int bpf_fd; bool auto_merge_stats; bool merged_stat; const char * metric_expr; const char * metric_name; - struct perf_evsel **metric_events; + struct evsel **metric_events; + struct evsel *metric_leader; bool collect_stat; bool weak_group; bool percore; @@ -184,73 +195,73 @@ struct perf_missing_features { bool write_backward; bool group_read; bool ksymbol; - bool bpf_event; + bool bpf; + bool aux_output; }; extern struct perf_missing_features perf_missing_features; -struct cpu_map; +struct perf_cpu_map; struct target; struct thread_map; struct record_opts; -static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) +static inline struct perf_cpu_map *evsel__cpus(struct evsel *evsel) { - return evsel->cpus; + return perf_evsel__cpus(&evsel->core); } -static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) +static inline int perf_evsel__nr_cpus(struct evsel *evsel) { - return perf_evsel__cpus(evsel)->nr; + return evsel__cpus(evsel)->nr; } void perf_counts_values__scale(struct perf_counts_values *count, bool scale, s8 *pscaled); -void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread, +void perf_evsel__compute_deltas(struct evsel *evsel, int cpu, int thread, struct perf_counts_values *count); int perf_evsel__object_config(size_t object_size, - int (*init)(struct perf_evsel *evsel), - void (*fini)(struct perf_evsel *evsel)); + int (*init)(struct evsel *evsel), + void (*fini)(struct evsel *evsel)); -struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); +struct evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); -static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) +static inline struct evsel *evsel__new(struct perf_event_attr *attr) { return perf_evsel__new_idx(attr, 0); } -struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx); +struct evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx); /* * Returns pointer with encoded error via <linux/err.h> interface. */ -static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name) +static inline struct evsel *perf_evsel__newtp(const char *sys, const char *name) { return perf_evsel__newtp_idx(sys, name, 0); } -struct perf_evsel *perf_evsel__new_cycles(bool precise); +struct evsel *perf_evsel__new_cycles(bool precise); struct tep_event *event_format__new(const char *sys, const char *name); -void perf_evsel__init(struct perf_evsel *evsel, - struct perf_event_attr *attr, int idx); -void perf_evsel__exit(struct perf_evsel *evsel); -void perf_evsel__delete(struct perf_evsel *evsel); +void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx); +void perf_evsel__exit(struct evsel *evsel); +void evsel__delete(struct evsel *evsel); struct callchain_param; -void perf_evsel__config(struct perf_evsel *evsel, +void perf_evsel__config(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain); -void perf_evsel__config_callchain(struct perf_evsel *evsel, +void perf_evsel__config_callchain(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain); int __perf_evsel__sample_size(u64 sample_type); -void perf_evsel__calc_id_pos(struct perf_evsel *evsel); +void perf_evsel__calc_id_pos(struct evsel *evsel); bool perf_evsel__is_cache_op_valid(u8 type, u8 op); @@ -266,17 +277,16 @@ extern const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX]; extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size); -const char *perf_evsel__name(struct perf_evsel *evsel); +const char *perf_evsel__name(struct evsel *evsel); -const char *perf_evsel__group_name(struct perf_evsel *evsel); -int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); +const char *perf_evsel__group_name(struct evsel *evsel); +int perf_evsel__group_desc(struct evsel *evsel, char *buf, size_t size); -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); -void perf_evsel__close_fd(struct perf_evsel *evsel); +int perf_evsel__alloc_id(struct evsel *evsel, int ncpus, int nthreads); -void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__set_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit); -void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__reset_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit); #define perf_evsel__set_sample_bit(evsel, bit) \ @@ -285,33 +295,32 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, #define perf_evsel__reset_sample_bit(evsel, bit) \ __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) -void perf_evsel__set_sample_id(struct perf_evsel *evsel, +void perf_evsel__set_sample_id(struct evsel *evsel, bool use_sample_identifier); -int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter); -int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter); -int perf_evsel__append_addr_filter(struct perf_evsel *evsel, +int perf_evsel__set_filter(struct evsel *evsel, const char *filter); +int perf_evsel__append_tp_filter(struct evsel *evsel, const char *filter); +int perf_evsel__append_addr_filter(struct evsel *evsel, const char *filter); -int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter); -int perf_evsel__enable(struct perf_evsel *evsel); -int perf_evsel__disable(struct perf_evsel *evsel); - -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus); -int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads); -int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads); -void perf_evsel__close(struct perf_evsel *evsel); +int evsel__enable(struct evsel *evsel); +int evsel__disable(struct evsel *evsel); + +int perf_evsel__open_per_cpu(struct evsel *evsel, + struct perf_cpu_map *cpus); +int perf_evsel__open_per_thread(struct evsel *evsel, + struct perf_thread_map *threads); +int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads); +void evsel__close(struct evsel *evsel); struct perf_sample; -void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, +void *perf_evsel__rawptr(struct evsel *evsel, struct perf_sample *sample, const char *name); -u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, +u64 perf_evsel__intval(struct evsel *evsel, struct perf_sample *sample, const char *name); -static inline char *perf_evsel__strval(struct perf_evsel *evsel, +static inline char *perf_evsel__strval(struct evsel *evsel, struct perf_sample *sample, const char *name) { @@ -322,31 +331,28 @@ struct tep_format_field; u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap); -struct tep_format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); +struct tep_format_field *perf_evsel__field(struct evsel *evsel, const char *name); #define perf_evsel__match(evsel, t, c) \ - (evsel->attr.type == PERF_TYPE_##t && \ - evsel->attr.config == PERF_COUNT_##c) + (evsel->core.attr.type == PERF_TYPE_##t && \ + evsel->core.attr.config == PERF_COUNT_##c) -static inline bool perf_evsel__match2(struct perf_evsel *e1, - struct perf_evsel *e2) +static inline bool perf_evsel__match2(struct evsel *e1, + struct evsel *e2) { - return (e1->attr.type == e2->attr.type) && - (e1->attr.config == e2->attr.config); + return (e1->core.attr.type == e2->core.attr.type) && + (e1->core.attr.config == e2->core.attr.config); } #define perf_evsel__cmp(a, b) \ ((a) && \ (b) && \ - (a)->attr.type == (b)->attr.type && \ - (a)->attr.config == (b)->attr.config) - -int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, - struct perf_counts_values *count); + (a)->core.attr.type == (b)->core.attr.type && \ + (a)->core.attr.config == (b)->core.attr.config) -int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread); +int perf_evsel__read_counter(struct evsel *evsel, int cpu, int thread); -int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, +int __perf_evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread, bool scale); /** @@ -356,7 +362,7 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, * @cpu - CPU of interest * @thread - thread of interest */ -static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel, +static inline int perf_evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread) { return __perf_evsel__read_on_cpu(evsel, cpu, thread, false); @@ -369,27 +375,27 @@ static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel, * @cpu - CPU of interest * @thread - thread of interest */ -static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel, +static inline int perf_evsel__read_on_cpu_scaled(struct evsel *evsel, int cpu, int thread) { return __perf_evsel__read_on_cpu(evsel, cpu, thread, true); } -int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, +int perf_evsel__parse_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *sample); -int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, +int perf_evsel__parse_sample_timestamp(struct evsel *evsel, union perf_event *event, u64 *timestamp); -static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) +static inline struct evsel *perf_evsel__next(struct evsel *evsel) { - return list_entry(evsel->node.next, struct perf_evsel, node); + return list_entry(evsel->core.node.next, struct evsel, core.node); } -static inline struct perf_evsel *perf_evsel__prev(struct perf_evsel *evsel) +static inline struct evsel *perf_evsel__prev(struct evsel *evsel) { - return list_entry(evsel->node.prev, struct perf_evsel, node); + return list_entry(evsel->core.node.prev, struct evsel, core.node); } /** @@ -399,7 +405,7 @@ static inline struct perf_evsel *perf_evsel__prev(struct perf_evsel *evsel) * * Return %true if @evsel is a group leader or a stand-alone event */ -static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) +static inline bool perf_evsel__is_group_leader(const struct evsel *evsel) { return evsel->leader == evsel; } @@ -412,22 +418,22 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) * Return %true iff event group view is enabled and @evsel is a actual group * leader which has other members in the group */ -static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) +static inline bool perf_evsel__is_group_event(struct evsel *evsel) { if (!symbol_conf.event_group) return false; - return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; + return perf_evsel__is_group_leader(evsel) && evsel->core.nr_members > 1; } -bool perf_evsel__is_function_event(struct perf_evsel *evsel); +bool perf_evsel__is_function_event(struct evsel *evsel); -static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel) +static inline bool perf_evsel__is_bpf_output(struct evsel *evsel) { return perf_evsel__match(evsel, SOFTWARE, SW_BPF_OUTPUT); } -static inline bool perf_evsel__is_clock(struct perf_evsel *evsel) +static inline bool perf_evsel__is_clock(struct evsel *evsel) { return perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK); @@ -441,7 +447,7 @@ struct perf_attr_details { bool trace_fields; }; -int perf_evsel__fprintf(struct perf_evsel *evsel, +int perf_evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp); #define EVSEL__PRINT_IP (1<<0) @@ -464,36 +470,36 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, int left_alignment, unsigned int print_opts, struct callchain_cursor *cursor, FILE *fp); -bool perf_evsel__fallback(struct perf_evsel *evsel, int err, +bool perf_evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize); -int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, +int perf_evsel__open_strerror(struct evsel *evsel, struct target *target, int err, char *msg, size_t size); -static inline int perf_evsel__group_idx(struct perf_evsel *evsel) +static inline int perf_evsel__group_idx(struct evsel *evsel) { return evsel->idx - evsel->leader->idx; } /* Iterates group WITHOUT the leader. */ #define for_each_group_member(_evsel, _leader) \ -for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ +for ((_evsel) = list_entry((_leader)->core.node.next, struct evsel, core.node); \ (_evsel) && (_evsel)->leader == (_leader); \ - (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) + (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) /* Iterates group WITH the leader. */ #define for_each_group_evsel(_evsel, _leader) \ for ((_evsel) = _leader; \ (_evsel) && (_evsel)->leader == (_leader); \ - (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) + (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) -static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) +static inline bool perf_evsel__has_branch_callstack(const struct evsel *evsel) { - return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; + return evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; } -static inline bool evsel__has_callchain(const struct perf_evsel *evsel) +static inline bool evsel__has_callchain(const struct evsel *evsel) { - return (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; + return (evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; } typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); @@ -501,7 +507,7 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, attr__fprintf_f attr__fprintf, void *priv); -struct perf_env *perf_evsel__env(struct perf_evsel *evsel); +struct perf_env *perf_evsel__env(struct evsel *evsel); -int perf_evsel__store_ids(struct perf_evsel *evsel, struct perf_evlist *evlist); +int perf_evsel__store_ids(struct evsel *evsel, struct evlist *evlist); #endif /* __PERF_EVSEL_H */ diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 95ea147f9e18..496fec01f5d1 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -33,26 +33,26 @@ static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, vo return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); } -int perf_evsel__fprintf(struct perf_evsel *evsel, +int perf_evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp) { bool first = true; int printed = 0; if (details->event_group) { - struct perf_evsel *pos; + struct evsel *pos; if (!perf_evsel__is_group_leader(evsel)) return 0; - if (evsel->nr_members > 1) + if (evsel->core.nr_members > 1) printed += fprintf(fp, "%s{", evsel->group_name ?: ""); printed += fprintf(fp, "%s", perf_evsel__name(evsel)); for_each_group_member(pos, evsel) printed += fprintf(fp, ",%s", perf_evsel__name(pos)); - if (evsel->nr_members > 1) + if (evsel->core.nr_members > 1) printed += fprintf(fp, "}"); goto out; } @@ -60,22 +60,22 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, printed += fprintf(fp, "%s", perf_evsel__name(evsel)); if (details->verbose) { - printed += perf_event_attr__fprintf(fp, &evsel->attr, + printed += perf_event_attr__fprintf(fp, &evsel->core.attr, __print_attr__fprintf, &first); } else if (details->freq) { const char *term = "sample_freq"; - if (!evsel->attr.freq) + if (!evsel->core.attr.freq) term = "sample_period"; printed += comma_fprintf(fp, &first, " %s=%" PRIu64, - term, (u64)evsel->attr.sample_freq); + term, (u64)evsel->core.attr.sample_freq); } if (details->trace_fields) { struct tep_format_field *field; - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { printed += comma_fprintf(fp, &first, " (not a tracepoint)"); goto out; } diff --git a/tools/perf/util/evswitch.c b/tools/perf/util/evswitch.c new file mode 100644 index 000000000000..3ba72f743d3c --- /dev/null +++ b/tools/perf/util/evswitch.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + +#include "evswitch.h" +#include "evlist.h" + +bool evswitch__discard(struct evswitch *evswitch, struct evsel *evsel) +{ + if (evswitch->on && evswitch->discarding) { + if (evswitch->on != evsel) + return true; + + evswitch->discarding = false; + + if (!evswitch->show_on_off_events) + return true; + + return false; + } + + if (evswitch->off && !evswitch->discarding) { + if (evswitch->off != evsel) + return false; + + evswitch->discarding = true; + + if (!evswitch->show_on_off_events) + return true; + } + + return false; +} + +static int evswitch__fprintf_enoent(FILE *fp, const char *evtype, const char *evname) +{ + int printed = fprintf(fp, "ERROR: switch-%s event not found (%s)\n", evtype, evname); + + return printed += fprintf(fp, "HINT: use 'perf evlist' to see the available event names\n"); +} + +int evswitch__init(struct evswitch *evswitch, struct evlist *evlist, FILE *fp) +{ + if (evswitch->on_name) { + evswitch->on = perf_evlist__find_evsel_by_str(evlist, evswitch->on_name); + if (evswitch->on == NULL) { + evswitch__fprintf_enoent(fp, "on", evswitch->on_name); + return -ENOENT; + } + evswitch->discarding = true; + } + + if (evswitch->off_name) { + evswitch->off = perf_evlist__find_evsel_by_str(evlist, evswitch->off_name); + if (evswitch->off == NULL) { + evswitch__fprintf_enoent(fp, "off", evswitch->off_name); + return -ENOENT; + } + } + + return 0; +} diff --git a/tools/perf/util/evswitch.h b/tools/perf/util/evswitch.h new file mode 100644 index 000000000000..fd30460b6218 --- /dev/null +++ b/tools/perf/util/evswitch.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> +#ifndef __PERF_EVSWITCH_H +#define __PERF_EVSWITCH_H 1 + +#include <stdbool.h> +#include <stdio.h> + +struct evsel; +struct evlist; + +struct evswitch { + struct evsel *on, *off; + const char *on_name, *off_name; + bool discarding; + bool show_on_off_events; +}; + +int evswitch__init(struct evswitch *evswitch, struct evlist *evlist, FILE *fp); + +bool evswitch__discard(struct evswitch *evswitch, struct evsel *evsel); + +#define OPTS_EVSWITCH(evswitch) \ + OPT_STRING(0, "switch-on", &(evswitch)->on_name, \ + "event", "Consider events after the ocurrence of this event"), \ + OPT_STRING(0, "switch-off", &(evswitch)->off_name, \ + "event", "Stop considering events after the ocurrence of this event"), \ + OPT_BOOLEAN(0, "show-on-off-events", &(evswitch)->show_on_off_events, \ + "Show the on/off switch events, used with --switch-on and --switch-off") + +#endif /* __PERF_EVSWITCH_H */ diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 432b8560cf51..f9a20a39b64a 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -2,9 +2,11 @@ %{ #include "util.h" #include "util/debug.h" +#include <stdlib.h> // strtod() #define IN_EXPR_Y 1 #include "expr.h" #include "smt.h" +#include <assert.h> #include <string.h> #define MAXIDLEN 256 diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c index 7001247ebbd6..f9f18b8b1df9 100644 --- a/tools/perf/util/genelf.c +++ b/tools/perf/util/genelf.c @@ -14,6 +14,7 @@ #include <libelf.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> #include <inttypes.h> #include <limits.h> #include <fcntl.h> @@ -22,9 +23,9 @@ #include <dwarf.h> #endif -#include "perf.h" #include "genelf.h" #include "../util/jitdump.h" +#include <linux/compiler.h> #ifndef NT_GNU_BUILD_ID #define NT_GNU_BUILD_ID 3 diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c index 995e490c17fa..30e9f618f6cd 100644 --- a/tools/perf/util/genelf_debug.c +++ b/tools/perf/util/genelf_debug.c @@ -24,7 +24,6 @@ #include <err.h> #include <dwarf.h> -#include "perf.h" #include "genelf.h" #include "../util/jitdump.h" diff --git a/tools/perf/util/get_current_dir_name.c b/tools/perf/util/get_current_dir_name.c index 01f32f26552d..b205d929245f 100644 --- a/tools/perf/util/get_current_dir_name.c +++ b/tools/perf/util/get_current_dir_name.c @@ -5,7 +5,6 @@ #include "get_current_dir_name.h" #include <unistd.h> #include <stdlib.h> -#include <stdlib.h> /* Android's 'bionic' library, for one, doesn't have this */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1903d7ec9797..b0c34dda30a0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -20,12 +20,13 @@ #include <linux/time64.h> #include <dirent.h> #include <bpf/libbpf.h> +#include <perf/cpumap.h> +#include "dso.h" #include "evlist.h" #include "evsel.h" #include "header.h" #include "memswap.h" -#include "../perf.h" #include "trace-event.h" #include "session.h" #include "symbol.h" @@ -41,6 +42,7 @@ #include "tool.h" #include "time-utils.h" #include "units.h" +#include "util.h" #include "cputopo.h" #include "bpf-event.h" @@ -74,7 +76,7 @@ struct feat_fd { void *buf; /* Either buf != NULL or fd >= 0 */ ssize_t offset; size_t size; - struct perf_evsel *events; + struct evsel *events; }; void perf_header__set_feat(struct perf_header *header, int feat) @@ -299,16 +301,16 @@ static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize) } static int write_tracing_data(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) return -1; - return read_tracing_data(ff->fd, &evlist->entries); + return read_tracing_data(ff->fd, &evlist->core.entries); } static int write_build_id(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_session *session; int err; @@ -332,7 +334,7 @@ static int write_build_id(struct feat_fd *ff, } static int write_hostname(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct utsname uts; int ret; @@ -345,7 +347,7 @@ static int write_hostname(struct feat_fd *ff, } static int write_osrelease(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct utsname uts; int ret; @@ -358,7 +360,7 @@ static int write_osrelease(struct feat_fd *ff, } static int write_arch(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct utsname uts; int ret; @@ -371,7 +373,7 @@ static int write_arch(struct feat_fd *ff, } static int write_version(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return do_write_string(ff, perf_version_string); } @@ -432,9 +434,27 @@ done: } static int write_cpudesc(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) -{ + struct evlist *evlist __maybe_unused) +{ +#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__) +#define CPUINFO_PROC { "cpu", } +#elif defined(__s390__) +#define CPUINFO_PROC { "vendor_id", } +#elif defined(__sh__) +#define CPUINFO_PROC { "cpu type", } +#elif defined(__alpha__) || defined(__mips__) +#define CPUINFO_PROC { "cpu model", } +#elif defined(__arm__) +#define CPUINFO_PROC { "model name", "Processor", } +#elif defined(__arc__) +#define CPUINFO_PROC { "Processor", } +#elif defined(__xtensa__) +#define CPUINFO_PROC { "core ID", } +#else +#define CPUINFO_PROC { "model name", } +#endif const char *cpuinfo_procs[] = CPUINFO_PROC; +#undef CPUINFO_PROC unsigned int i; for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) { @@ -448,7 +468,7 @@ static int write_cpudesc(struct feat_fd *ff, static int write_nrcpus(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { long nr; u32 nrc, nra; @@ -470,13 +490,13 @@ static int write_nrcpus(struct feat_fd *ff, } static int write_event_desc(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; u32 nre, nri, sz; int ret; - nre = evlist->nr_entries; + nre = evlist->core.nr_entries; /* * write number of events @@ -488,13 +508,13 @@ static int write_event_desc(struct feat_fd *ff, /* * size of perf_event_attr struct */ - sz = (u32)sizeof(evsel->attr); + sz = (u32)sizeof(evsel->core.attr); ret = do_write(ff, &sz, sizeof(sz)); if (ret < 0) return ret; evlist__for_each_entry(evlist, evsel) { - ret = do_write(ff, &evsel->attr, sz); + ret = do_write(ff, &evsel->core.attr, sz); if (ret < 0) return ret; /* @@ -526,7 +546,7 @@ static int write_event_desc(struct feat_fd *ff, } static int write_cmdline(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { char pbuf[MAXPATHLEN], *buf; int i, ret, n; @@ -555,7 +575,7 @@ static int write_cmdline(struct feat_fd *ff, static int write_cpu_topology(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct cpu_topology *tp; u32 i; @@ -627,7 +647,7 @@ done: static int write_total_mem(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { char *buf = NULL; FILE *fp; @@ -656,7 +676,7 @@ static int write_total_mem(struct feat_fd *ff, } static int write_numa_topology(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct numa_topology *tp; int ret = -1; @@ -710,7 +730,7 @@ err: */ static int write_pmu_mappings(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_pmu *pmu = NULL; u32 pmu_num = 0; @@ -759,10 +779,10 @@ static int write_pmu_mappings(struct feat_fd *ff, * }; */ static int write_group_desc(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { u32 nr_groups = evlist->nr_groups; - struct perf_evsel *evsel; + struct evsel *evsel; int ret; ret = do_write(ff, &nr_groups, sizeof(nr_groups)); @@ -771,10 +791,10 @@ static int write_group_desc(struct feat_fd *ff, evlist__for_each_entry(evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && - evsel->nr_members > 1) { + evsel->core.nr_members > 1) { const char *name = evsel->group_name ?: "{anon_group}"; u32 leader_idx = evsel->idx; - u32 nr_members = evsel->nr_members; + u32 nr_members = evsel->core.nr_members; ret = do_write_string(ff, name); if (ret < 0) @@ -841,7 +861,7 @@ int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) } static int write_cpuid(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { char buffer[64]; int ret; @@ -854,13 +874,13 @@ static int write_cpuid(struct feat_fd *ff, } static int write_branch_stack(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } static int write_auxtrace(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_session *session; int err; @@ -877,14 +897,14 @@ static int write_auxtrace(struct feat_fd *ff, } static int write_clockid(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return do_write(ff, &ff->ph->env.clockid_res_ns, sizeof(ff->ph->env.clockid_res_ns)); } static int write_dir_format(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_session *session; struct perf_data *data; @@ -900,7 +920,7 @@ static int write_dir_format(struct feat_fd *ff, #ifdef HAVE_LIBBPF_SUPPORT static int write_bpf_prog_info(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_env *env = &ff->ph->env; struct rb_root *root; @@ -942,14 +962,14 @@ out: } #else // HAVE_LIBBPF_SUPPORT static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } #endif // HAVE_LIBBPF_SUPPORT static int write_bpf_btf(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_env *env = &ff->ph->env; struct rb_root *root; @@ -1120,16 +1140,17 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) return 0; } -#define MAX_CACHES (MAX_NR_CPUS * 4) +#define MAX_CACHE_LVL 4 static int write_cache(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { - struct cpu_cache_level caches[MAX_CACHES]; + u32 max_caches = cpu__max_cpu() * MAX_CACHE_LVL; + struct cpu_cache_level caches[max_caches]; u32 cnt = 0, i, version = 1; int ret; - ret = build_caches(caches, MAX_CACHES, &cnt); + ret = build_caches(caches, max_caches, &cnt); if (ret) goto out; @@ -1175,13 +1196,13 @@ out: } static int write_stat(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } static int write_sample_time(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { int ret; @@ -1315,7 +1336,7 @@ static int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp) * 48 - bitmap | bitmap of memory indexes that belongs to node */ static int write_mem_topology(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { static struct memory_node nodes[MAX_MEMORY_NODES]; u64 bsize, version = 1, i, nr; @@ -1365,7 +1386,7 @@ out: } static int write_compressed(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { int ret; @@ -1568,14 +1589,14 @@ static void print_bpf_btf(struct feat_fd *ff, FILE *fp) up_read(&env->bpf_progs.lock); } -static void free_event_desc(struct perf_evsel *events) +static void free_event_desc(struct evsel *events) { - struct perf_evsel *evsel; + struct evsel *evsel; if (!events) return; - for (evsel = events; evsel->attr.size; evsel++) { + for (evsel = events; evsel->core.attr.size; evsel++) { zfree(&evsel->name); zfree(&evsel->id); } @@ -1583,9 +1604,9 @@ static void free_event_desc(struct perf_evsel *events) free(events); } -static struct perf_evsel *read_event_desc(struct feat_fd *ff) +static struct evsel *read_event_desc(struct feat_fd *ff) { - struct perf_evsel *evsel, *events = NULL; + struct evsel *evsel, *events = NULL; u64 *id; void *buf = NULL; u32 nre, sz, nr, i, j; @@ -1603,12 +1624,12 @@ static struct perf_evsel *read_event_desc(struct feat_fd *ff) if (!buf) goto error; - /* the last event terminates with evsel->attr.size == 0: */ + /* the last event terminates with evsel->core.attr.size == 0: */ events = calloc(nre + 1, sizeof(*events)); if (!events) goto error; - msz = sizeof(evsel->attr); + msz = sizeof(evsel->core.attr); if (sz < msz) msz = sz; @@ -1625,7 +1646,7 @@ static struct perf_evsel *read_event_desc(struct feat_fd *ff) if (ff->ph->needs_swap) perf_event__attr_swap(buf); - memcpy(&evsel->attr, buf, msz); + memcpy(&evsel->core.attr, buf, msz); if (do_read_u32(ff, &nr)) goto error; @@ -1669,7 +1690,7 @@ static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, static void print_event_desc(struct feat_fd *ff, FILE *fp) { - struct perf_evsel *evsel, *events; + struct evsel *evsel, *events; u32 j; u64 *id; @@ -1683,7 +1704,7 @@ static void print_event_desc(struct feat_fd *ff, FILE *fp) return; } - for (evsel = events; evsel->attr.size; evsel++) { + for (evsel = events; evsel->core.attr.size; evsel++) { fprintf(fp, "# event : name = %s, ", evsel->name); if (evsel->ids) { @@ -1696,7 +1717,7 @@ static void print_event_desc(struct feat_fd *ff, FILE *fp) fprintf(fp, " }"); } - perf_event_attr__fprintf(fp, &evsel->attr, __desc_attr__fprintf, NULL); + perf_event_attr__fprintf(fp, &evsel->core.attr, __desc_attr__fprintf, NULL); fputc('\n', fp); } @@ -1804,18 +1825,18 @@ error: static void print_group_desc(struct feat_fd *ff, FILE *fp) { struct perf_session *session; - struct perf_evsel *evsel; + struct evsel *evsel; u32 nr = 0; session = container_of(ff->ph, struct perf_session, header); evlist__for_each_entry(session->evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && - evsel->nr_members > 1) { + evsel->core.nr_members > 1) { fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", perf_evsel__name(evsel)); - nr = evsel->nr_members - 1; + nr = evsel->core.nr_members - 1; } else if (nr) { fprintf(fp, ",%s", perf_evsel__name(evsel)); @@ -1876,7 +1897,7 @@ static void print_mem_topology(struct feat_fd *ff, FILE *fp) } } -static int __event_process_build_id(struct build_id_event *bev, +static int __event_process_build_id(struct perf_record_header_build_id *bev, char *filename, struct perf_session *session) { @@ -1945,7 +1966,7 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; char filename[0]; } old_bev; - struct build_id_event bev; + struct perf_record_header_build_id bev; char filename[PATH_MAX]; u64 limit = offset + size; @@ -1986,7 +2007,7 @@ static int perf_header__read_build_ids(struct perf_header *header, int input, u64 offset, u64 size) { struct perf_session *session = container_of(header, struct perf_session, header); - struct build_id_event bev; + struct perf_record_header_build_id bev; char filename[PATH_MAX]; u64 limit = offset + size, orig_offset = offset; int err = -1; @@ -2008,7 +2029,7 @@ static int perf_header__read_build_ids(struct perf_header *header, * * "perf: 'perf kvm' tool for monitoring guest performance from host" * - * Added a field to struct build_id_event that broke the file + * Added a field to struct perf_record_header_build_id that broke the file * format. * * Since the kernel build-id is the first entry, process the @@ -2089,10 +2110,10 @@ static int process_total_mem(struct feat_fd *ff, void *data __maybe_unused) return 0; } -static struct perf_evsel * -perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) +static struct evsel * +perf_evlist__find_by_index(struct evlist *evlist, int idx) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->idx == idx) @@ -2103,10 +2124,10 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) } static void -perf_evlist__set_event_name(struct perf_evlist *evlist, - struct perf_evsel *event) +perf_evlist__set_event_name(struct evlist *evlist, + struct evsel *event) { - struct perf_evsel *evsel; + struct evsel *evsel; if (!event->name) return; @@ -2125,7 +2146,7 @@ static int process_event_desc(struct feat_fd *ff, void *data __maybe_unused) { struct perf_session *session; - struct perf_evsel *evsel, *events = read_event_desc(ff); + struct evsel *evsel, *events = read_event_desc(ff); if (!events) return 0; @@ -2138,7 +2159,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused) ff->events = events; } - for (evsel = events; evsel->attr.size; evsel++) + for (evsel = events; evsel->core.attr.size; evsel++) perf_evlist__set_event_name(session->evlist, evsel); if (!session->data->is_pipe) @@ -2251,8 +2272,10 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) /* On s390 the socket_id number is not related to the numbers of cpus. * The socket_id number might be higher than the numbers of cpus. * This depends on the configuration. + * AArch64 is the same. */ - if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4)) + if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4) + || !strncmp(ph->env.arch, "aarch64", 7))) do_core_id_test = false; for (i = 0; i < (u32)cpu_nr; i++) { @@ -2348,7 +2371,7 @@ static int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused) if (!str) goto error; - n->map = cpu_map__new(str); + n->map = perf_cpu_map__new(str); if (!n->map) goto error; @@ -2415,7 +2438,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) size_t ret = -1; u32 i, nr, nr_groups; struct perf_session *session; - struct perf_evsel *evsel, *leader = NULL; + struct evsel *evsel, *leader = NULL; struct group_desc { char *name; u32 leader_idx; @@ -2462,7 +2485,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) evsel->group_name = desc[i].name; desc[i].name = NULL; } - evsel->nr_members = desc[i].nr_members; + evsel->core.nr_members = desc[i].nr_members; if (i >= nr_groups || nr > 0) { pr_debug("invalid group desc\n"); @@ -2470,7 +2493,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) } leader = evsel; - nr = evsel->nr_members - 1; + nr = evsel->core.nr_members - 1; i++; } else if (nr) { /* This is a group member */ @@ -2801,7 +2824,7 @@ static int process_compressed(struct feat_fd *ff, } struct feature_ops { - int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); + int (*write)(struct feat_fd *ff, struct evlist *evlist); void (*print)(struct feat_fd *ff, FILE *fp); int (*process)(struct feat_fd *ff, void *data); const char *name; @@ -2946,7 +2969,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) static int do_write_feat(struct feat_fd *ff, int type, struct perf_file_section **p, - struct perf_evlist *evlist) + struct evlist *evlist) { int err; int ret = 0; @@ -2976,7 +2999,7 @@ static int do_write_feat(struct feat_fd *ff, int type, } static int perf_header__adds_write(struct perf_header *header, - struct perf_evlist *evlist, int fd) + struct evlist *evlist, int fd) { int nr_sections; struct feat_fd ff; @@ -3044,13 +3067,13 @@ int perf_header__write_pipe(int fd) } int perf_session__write_header(struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, int fd, bool at_exit) { struct perf_file_header f_header; struct perf_file_attr f_attr; struct perf_header *header = &session->header; - struct perf_evsel *evsel; + struct evsel *evsel; struct feat_fd ff; u64 attr_offset; int err; @@ -3071,7 +3094,7 @@ int perf_session__write_header(struct perf_session *session, evlist__for_each_entry(evlist, evsel) { f_attr = (struct perf_file_attr){ - .attr = evsel->attr, + .attr = evsel->core.attr, .ids = { .offset = evsel->id_offset, .size = evsel->ids * sizeof(u64), @@ -3100,7 +3123,7 @@ int perf_session__write_header(struct perf_session *session, .attr_size = sizeof(f_attr), .attrs = { .offset = attr_offset, - .size = evlist->nr_entries * sizeof(f_attr), + .size = evlist->core.nr_entries * sizeof(f_attr), }, .data = { .offset = header->data_offset, @@ -3479,7 +3502,7 @@ static int read_attr(int fd, struct perf_header *ph, return ret <= 0 ? -1 : 0; } -static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, +static int perf_evsel__prepare_tracepoint_event(struct evsel *evsel, struct tep_handle *pevent) { struct tep_event *event; @@ -3494,9 +3517,9 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, return -1; } - event = tep_find_event(pevent, evsel->attr.config); + event = tep_find_event(pevent, evsel->core.attr.config); if (event == NULL) { - pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); + pr_debug("cannot find event format for %d\n", (int)evsel->core.attr.config); return -1; } @@ -3511,13 +3534,13 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, return 0; } -static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, +static int perf_evlist__prepare_tracepoint_events(struct evlist *evlist, struct tep_handle *pevent) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(evlist, pos) { - if (pos->attr.type == PERF_TYPE_TRACEPOINT && + if (pos->core.attr.type == PERF_TYPE_TRACEPOINT && perf_evsel__prepare_tracepoint_event(pos, pevent)) return -1; } @@ -3535,7 +3558,7 @@ int perf_session__read_header(struct perf_session *session) int nr_attrs, nr_ids, i, j; int fd = perf_data__fd(data); - session->evlist = perf_evlist__new(); + session->evlist = evlist__new(); if (session->evlist == NULL) return -ENOMEM; @@ -3570,7 +3593,7 @@ int perf_session__read_header(struct perf_session *session) lseek(fd, f_header.attrs.offset, SEEK_SET); for (i = 0; i < nr_attrs; i++) { - struct perf_evsel *evsel; + struct evsel *evsel; off_t tmp; if (read_attr(fd, header, &f_attr) < 0) @@ -3583,7 +3606,7 @@ int perf_session__read_header(struct perf_session *session) } tmp = lseek(fd, 0, SEEK_CUR); - evsel = perf_evsel__new(&f_attr.attr); + evsel = evsel__new(&f_attr.attr); if (evsel == NULL) goto out_delete_evlist; @@ -3591,9 +3614,9 @@ int perf_session__read_header(struct perf_session *session) evsel->needs_swap = header->needs_swap; /* * Do it before so that if perf_evsel__alloc_id fails, this - * entry gets purged too at perf_evlist__delete(). + * entry gets purged too at evlist__delete(). */ - perf_evlist__add(session->evlist, evsel); + evlist__add(session->evlist, evsel); nr_ids = f_attr.ids.size / sizeof(u64); /* @@ -3628,7 +3651,7 @@ out_errno: return -errno; out_delete_evlist: - perf_evlist__delete(session->evlist); + evlist__delete(session->evlist); session->evlist = NULL; return -ENOMEM; } @@ -3669,12 +3692,12 @@ int perf_event__synthesize_attr(struct perf_tool *tool, int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process) { struct perf_header *header = &session->header; struct feat_fd ff; - struct feature_event *fe; + struct perf_record_header_feature *fe; size_t sz, sz_hdr; int feat, ret; @@ -3737,7 +3760,7 @@ int perf_event__process_feature(struct perf_session *session, { struct perf_tool *tool = session->tool; struct feat_fd ff = { .fd = 0 }; - struct feature_event *fe = (struct feature_event *)event; + struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event; int type = fe->header.type; u64 feat = fe->feat_id; @@ -3774,10 +3797,10 @@ int perf_event__process_feature(struct perf_session *session, return 0; } -static struct event_update_event * +static struct perf_record_event_update * event_update_event__new(size_t size, u64 type, u64 id) { - struct event_update_event *ev; + struct perf_record_event_update *ev; size += sizeof(*ev); size = PERF_ALIGN(size, sizeof(u64)); @@ -3794,10 +3817,10 @@ event_update_event__new(size_t size, u64 type, u64 id) int perf_event__synthesize_event_update_unit(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - struct event_update_event *ev; + struct perf_record_event_update *ev; size_t size = strlen(evsel->unit); int err; @@ -3813,18 +3836,18 @@ perf_event__synthesize_event_update_unit(struct perf_tool *tool, int perf_event__synthesize_event_update_scale(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - struct event_update_event *ev; - struct event_update_event_scale *ev_data; + struct perf_record_event_update *ev; + struct perf_record_event_update_scale *ev_data; int err; ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]); if (ev == NULL) return -ENOMEM; - ev_data = (struct event_update_event_scale *) ev->data; + ev_data = (struct perf_record_event_update_scale *)ev->data; ev_data->scale = evsel->scale; err = process(tool, (union perf_event*) ev, NULL, NULL); free(ev); @@ -3833,10 +3856,10 @@ perf_event__synthesize_event_update_scale(struct perf_tool *tool, int perf_event__synthesize_event_update_name(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - struct event_update_event *ev; + struct perf_record_event_update *ev; size_t len = strlen(evsel->name); int err; @@ -3852,18 +3875,18 @@ perf_event__synthesize_event_update_name(struct perf_tool *tool, int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - size_t size = sizeof(struct event_update_event); - struct event_update_event *ev; + size_t size = sizeof(struct perf_record_event_update); + struct perf_record_event_update *ev; int max, err; u16 type; - if (!evsel->own_cpus) + if (!evsel->core.own_cpus) return 0; - ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max); + ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); if (!ev) return -ENOMEM; @@ -3872,8 +3895,8 @@ perf_event__synthesize_event_update_cpus(struct perf_tool *tool, ev->type = PERF_EVENT_UPDATE__CPUS; ev->id = evsel->id[0]; - cpu_map_data__synthesize((struct cpu_map_data *) ev->data, - evsel->own_cpus, + cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, + evsel->core.own_cpus, type, max); err = process(tool, (union perf_event*) ev, NULL, NULL); @@ -3883,17 +3906,17 @@ perf_event__synthesize_event_update_cpus(struct perf_tool *tool, size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) { - struct event_update_event *ev = &event->event_update; - struct event_update_event_scale *ev_scale; - struct event_update_event_cpus *ev_cpus; - struct cpu_map *map; + struct perf_record_event_update *ev = &event->event_update; + struct perf_record_event_update_scale *ev_scale; + struct perf_record_event_update_cpus *ev_cpus; + struct perf_cpu_map *map; size_t ret; - ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id); + ret = fprintf(fp, "\n... id: %" PRI_lu64 "\n", ev->id); switch (ev->type) { case PERF_EVENT_UPDATE__SCALE: - ev_scale = (struct event_update_event_scale *) ev->data; + ev_scale = (struct perf_record_event_update_scale *)ev->data; ret += fprintf(fp, "... scale: %f\n", ev_scale->scale); break; case PERF_EVENT_UPDATE__UNIT: @@ -3903,7 +3926,7 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) ret += fprintf(fp, "... name: %s\n", ev->data); break; case PERF_EVENT_UPDATE__CPUS: - ev_cpus = (struct event_update_event_cpus *) ev->data; + ev_cpus = (struct perf_record_event_update_cpus *)ev->data; ret += fprintf(fp, "... "); map = cpu_map__new_data(&ev_cpus->cpus); @@ -3921,14 +3944,14 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) } int perf_event__synthesize_attrs(struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process) { - struct perf_evsel *evsel; + struct evsel *evsel; int err = 0; evlist__for_each_entry(evlist, evsel) { - err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, + err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->ids, evsel->id, process); if (err) { pr_debug("failed to create perf header attribute\n"); @@ -3939,22 +3962,22 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, return err; } -static bool has_unit(struct perf_evsel *counter) +static bool has_unit(struct evsel *counter) { return counter->unit && *counter->unit; } -static bool has_scale(struct perf_evsel *counter) +static bool has_scale(struct evsel *counter) { return counter->scale != 1; } int perf_event__synthesize_extra_attr(struct perf_tool *tool, - struct perf_evlist *evsel_list, + struct evlist *evsel_list, perf_event__handler_t process, bool is_pipe) { - struct perf_evsel *counter; + struct evsel *counter; int err; /* @@ -3984,7 +4007,7 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool, } } - if (counter->own_cpus) { + if (counter->core.own_cpus) { err = perf_event__synthesize_event_update_cpus(tool, counter, process); if (err < 0) { pr_err("Couldn't synthesize evsel cpus.\n"); @@ -4009,23 +4032,23 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool, int perf_event__process_attr(struct perf_tool *tool __maybe_unused, union perf_event *event, - struct perf_evlist **pevlist) + struct evlist **pevlist) { u32 i, ids, n_ids; - struct perf_evsel *evsel; - struct perf_evlist *evlist = *pevlist; + struct evsel *evsel; + struct evlist *evlist = *pevlist; if (evlist == NULL) { - *pevlist = evlist = perf_evlist__new(); + *pevlist = evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; } - evsel = perf_evsel__new(&event->attr.attr); + evsel = evsel__new(&event->attr.attr); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); ids = event->header.size; ids -= (void *)&event->attr.id - (void *)event; @@ -4047,14 +4070,14 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, union perf_event *event, - struct perf_evlist **pevlist) + struct evlist **pevlist) { - struct event_update_event *ev = &event->event_update; - struct event_update_event_scale *ev_scale; - struct event_update_event_cpus *ev_cpus; - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct cpu_map *map; + struct perf_record_event_update *ev = &event->event_update; + struct perf_record_event_update_scale *ev_scale; + struct perf_record_event_update_cpus *ev_cpus; + struct evlist *evlist; + struct evsel *evsel; + struct perf_cpu_map *map; if (!pevlist || *pevlist == NULL) return -EINVAL; @@ -4073,15 +4096,15 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, evsel->name = strdup(ev->data); break; case PERF_EVENT_UPDATE__SCALE: - ev_scale = (struct event_update_event_scale *) ev->data; + ev_scale = (struct perf_record_event_update_scale *)ev->data; evsel->scale = ev_scale->scale; break; case PERF_EVENT_UPDATE__CPUS: - ev_cpus = (struct event_update_event_cpus *) ev->data; + ev_cpus = (struct perf_record_event_update_cpus *)ev->data; map = cpu_map__new_data(&ev_cpus->cpus); if (map) - evsel->own_cpus = map; + evsel->core.own_cpus = map; else pr_err("failed to get event_update cpus\n"); default: @@ -4092,7 +4115,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, } int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process) { union perf_event ev; @@ -4112,7 +4135,7 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, * - write the tracing data from the temp file * to the pipe */ - tdata = tracing_data_get(&evlist->entries, fd, true); + tdata = tracing_data_get(&evlist->core.entries, fd, true); if (!tdata) return -1; @@ -4149,7 +4172,7 @@ int perf_event__process_tracing_data(struct perf_session *session, char buf[BUFSIZ]; /* setup for reading amidst mmap */ - lseek(fd, offset + sizeof(struct tracing_data_event), + lseek(fd, offset + sizeof(struct perf_record_header_tracing_data), SEEK_SET); size_read = trace_report(fd, &session->tevent, diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 5b3abe4172e2..3e48ae3c49b1 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -92,12 +92,12 @@ struct perf_header { struct perf_env env; }; -struct perf_evlist; +struct evlist; struct perf_session; int perf_session__read_header(struct perf_session *session); int perf_session__write_header(struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, int fd, bool at_exit); int perf_header__write_pipe(int fd); @@ -117,11 +117,11 @@ int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process); int perf_event__synthesize_extra_attr(struct perf_tool *tool, - struct perf_evlist *evsel_list, + struct evlist *evsel_list, perf_event__handler_t process, bool is_pipe); @@ -132,29 +132,29 @@ int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u32 ids, u64 *id, perf_event__handler_t process); int perf_event__synthesize_attrs(struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process); int perf_event__synthesize_event_update_unit(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__synthesize_event_update_scale(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__synthesize_event_update_name(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist); + struct evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist); + struct evlist **pevlist); size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp); int perf_event__synthesize_tracing_data(struct perf_tool *tool, - int fd, struct perf_evlist *evlist, + int fd, struct evlist *evlist, perf_event__handler_t process); int perf_event__process_tracing_data(struct perf_session *session, union perf_event *event); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f24fd1954f6c..679a1d75090c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1,8 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 #include "callchain.h" +#include "debug.h" +#include "dso.h" #include "build-id.h" #include "hist.h" #include "map.h" +#include "map_symbol.h" +#include "branch.h" +#include "mem-events.h" #include "session.h" #include "namespaces.h" #include "sort.h" @@ -18,6 +23,8 @@ #include <math.h> #include <inttypes.h> #include <sys/param.h> +#include <linux/rbtree.h> +#include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> @@ -193,7 +200,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); - hists__new_col_len(hists, HISTC_TIME, 12); + if (symbol_conf.nanosecs) + hists__new_col_len(hists, HISTC_TIME, 16); + else + hists__new_col_len(hists, HISTC_TIME, 12); if (h->srcline) { len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header)); @@ -816,7 +826,7 @@ static int iter_finish_mem_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); struct hist_entry *he = iter->he; int err = -EINVAL; @@ -886,7 +896,7 @@ static int iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al) { struct branch_info *bi; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); struct perf_sample *sample = iter->sample; struct hist_entry *he = NULL; @@ -938,7 +948,7 @@ iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused, static int iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; struct hist_entry *he; @@ -956,7 +966,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { struct hist_entry *he = iter->he; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; if (he == NULL) @@ -996,7 +1006,7 @@ static int iter_add_single_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); struct perf_sample *sample = iter->sample; struct hist_entry **he_cache = iter->priv; @@ -1041,7 +1051,7 @@ static int iter_add_next_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; struct hist_entry **he_cache = iter->priv; struct hist_entry *he; @@ -1873,7 +1883,7 @@ static void output_resort(struct hists *hists, struct ui_progress *prog, } } -void perf_evsel__output_resort_cb(struct perf_evsel *evsel, struct ui_progress *prog, +void perf_evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog, hists__resort_cb_t cb, void *cb_arg) { bool use_callchain; @@ -1888,7 +1898,7 @@ void perf_evsel__output_resort_cb(struct perf_evsel *evsel, struct ui_progress * output_resort(evsel__hists(evsel), prog, use_callchain, cb, cb_arg); } -void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog) +void perf_evsel__output_resort(struct evsel *evsel, struct ui_progress *prog) { return perf_evsel__output_resort_cb(evsel, prog, NULL, NULL); } @@ -2539,6 +2549,25 @@ int hists__link(struct hists *leader, struct hists *other) return 0; } +int hists__unlink(struct hists *hists) +{ + struct rb_root_cached *root; + struct rb_node *nd; + struct hist_entry *pos; + + if (hists__has(hists, need_collapse)) + root = &hists->entries_collapsed; + else + root = hists->entries_in; + + for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node_in); + list_del_init(&pos->pairs.node); + } + + return 0; +} + void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, struct perf_sample *sample, bool nonany_branch_mode) { @@ -2573,9 +2602,9 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, } } -size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp) +size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp) { - struct perf_evsel *pos; + struct evsel *pos; size_t ret = 0; evlist__for_each_entry(evlist, pos) { @@ -2602,7 +2631,7 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh int socket_id = hists->socket_filter; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); const char *ev_name = perf_evsel__name(evsel); char buf[512], sample_freq_str[64] = ""; size_t buflen = sizeof(buf); @@ -2615,7 +2644,7 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh } if (perf_evsel__is_group_event(evsel)) { - struct perf_evsel *pos; + struct evsel *pos; perf_evsel__group_desc(evsel, buf, buflen); ev_name = buf; @@ -2638,12 +2667,12 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh enable_ref = true; if (show_freq) - scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); + scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->core.attr.sample_freq); nr_samples = convert_unit(nr_samples, &unit); printed = scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, - nr_samples, unit, evsel->nr_members > 1 ? "s" : "", + nr_samples, unit, evsel->core.nr_members > 1 ? "s" : "", ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); @@ -2731,7 +2760,7 @@ static void hists__delete_all_entries(struct hists *hists) hists__delete_remaining_entries(&hists->entries_collapsed); } -static void hists_evsel__exit(struct perf_evsel *evsel) +static void hists_evsel__exit(struct evsel *evsel) { struct hists *hists = evsel__hists(evsel); struct perf_hpp_fmt *fmt, *pos; @@ -2749,7 +2778,7 @@ static void hists_evsel__exit(struct perf_evsel *evsel) } } -static int hists_evsel__init(struct perf_evsel *evsel) +static int hists_evsel__init(struct evsel *evsel) { struct hists *hists = evsel__hists(evsel); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 24635f36148d..34803e33dc80 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -6,9 +6,8 @@ #include <linux/types.h> #include <pthread.h> #include "evsel.h" -#include "header.h" #include "color.h" -#include "ui/progress.h" +#include "events_stats.h" struct hist_entry; struct hist_entry_ops; @@ -18,6 +17,7 @@ struct mem_info; struct branch_info; struct block_info; struct symbol; +struct ui_progress; enum hist_filter { HIST_FILTER__DSO, @@ -116,7 +116,7 @@ struct hist_entry_iter { bool hide_unresolved; - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_sample *sample; struct hist_entry *he; struct symbol *parent; @@ -171,9 +171,9 @@ void hist_entry__delete(struct hist_entry *he); typedef int (*hists__resort_cb_t)(struct hist_entry *he, void *arg); -void perf_evsel__output_resort_cb(struct perf_evsel *evsel, struct ui_progress *prog, +void perf_evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog, hists__resort_cb_t cb, void *cb_arg); -void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog); +void perf_evsel__output_resort(struct evsel *evsel, struct ui_progress *prog); void hists__output_resort(struct hists *hists, struct ui_progress *prog); void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog, hists__resort_cb_t cb); @@ -190,13 +190,11 @@ void hists__reset_stats(struct hists *hists); void hists__inc_stats(struct hists *hists, struct hist_entry *h); void hists__inc_nr_events(struct hists *hists, u32 type); void hists__inc_nr_samples(struct hists *hists, bool filtered); -void events_stats__inc(struct events_stats *stats, u32 type); -size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp, bool ignore_callchains); -size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); +size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp); void hists__filter_by_dso(struct hists *hists); void hists__filter_by_thread(struct hists *hists); @@ -217,19 +215,20 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); void hists__match(struct hists *leader, struct hists *other); int hists__link(struct hists *leader, struct hists *other); +int hists__unlink(struct hists *hists); struct hists_evsel { - struct perf_evsel evsel; + struct evsel evsel; struct hists hists; }; -static inline struct perf_evsel *hists_to_evsel(struct hists *hists) +static inline struct evsel *hists_to_evsel(struct hists *hists) { struct hists_evsel *hevsel = container_of(hists, struct hists_evsel, hists); return &hevsel->evsel; } -static inline struct hists *evsel__hists(struct perf_evsel *evsel) +static inline struct hists *evsel__hists(struct evsel *evsel) { struct hists_evsel *hevsel = (struct hists_evsel *)evsel; return &hevsel->hists; @@ -367,7 +366,7 @@ void perf_hpp__setup_output_field(struct perf_hpp_list *list); void perf_hpp__reset_output_field(struct perf_hpp_list *list); void perf_hpp__append_sort_keys(struct perf_hpp_list *list); int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, - struct perf_evlist *evlist); + struct evlist *evlist); bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); @@ -432,7 +431,7 @@ static inline size_t perf_hpp__color_overhead(void) : 0; } -struct perf_evlist; +struct evlist; struct hist_browser_timer { void (*timer)(void *arg); @@ -453,30 +452,30 @@ enum rstype { #include "../ui/keysyms.h" void attr_to_script(char *buf, struct perf_event_attr *attr); -int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *annotation_opts); -int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, +int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *annotation_opts); -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, +int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, bool warn_lost_event, struct annotation_options *annotation_options); -int script_browse(const char *script_opt, struct perf_evsel *evsel); +int script_browse(const char *script_opt, struct evsel *evsel); void run_script(char *cmd); int res_sample_browse(struct res_sample *res_samples, int num_res, - struct perf_evsel *evsel, enum rstype rstype); + struct evsel *evsel, enum rstype rstype); void res_sample_init(void); #else static inline -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, +int perf_evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, const char *help __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, float min_pcnt __maybe_unused, @@ -487,7 +486,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, return 0; } static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, struct annotation_options *annotation_options __maybe_unused) { @@ -495,7 +494,7 @@ static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, } static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, struct annotation_options *annotation_opts __maybe_unused) { @@ -503,14 +502,14 @@ static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, } static inline int script_browse(const char *script_opt __maybe_unused, - struct perf_evsel *evsel __maybe_unused) + struct evsel *evsel __maybe_unused) { return 0; } static inline int res_sample_browse(struct res_sample *res_samples __maybe_unused, int num_res __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, enum rstype rstype __maybe_unused) { return 0; diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 5560e95afdda..aacffa2b0362 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -19,9 +19,9 @@ #include "evsel.h" #include "evlist.h" #include "machine.h" -#include "map.h" #include "symbol.h" #include "session.h" +#include "tool.h" #include "thread.h" #include "thread-stack.h" #include "debug.h" @@ -760,15 +760,15 @@ static int intel_bts_synth_event(struct perf_session *session, static int intel_bts_synth_events(struct intel_bts *bts, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; struct perf_event_attr attr; bool found = false; u64 id; int err; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == bts->pmu_type && evsel->ids) { + if (evsel->core.attr.type == bts->pmu_type && evsel->ids) { found = true; break; } @@ -782,18 +782,18 @@ static int intel_bts_synth_events(struct intel_bts *bts, memset(&attr, 0, sizeof(struct perf_event_attr)); attr.size = sizeof(struct perf_event_attr); attr.type = PERF_TYPE_HARDWARE; - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; - attr.exclude_user = evsel->attr.exclude_user; - attr.exclude_kernel = evsel->attr.exclude_kernel; - attr.exclude_hv = evsel->attr.exclude_hv; - attr.exclude_host = evsel->attr.exclude_host; - attr.exclude_guest = evsel->attr.exclude_guest; - attr.sample_id_all = evsel->attr.sample_id_all; - attr.read_format = evsel->attr.read_format; + attr.exclude_user = evsel->core.attr.exclude_user; + attr.exclude_kernel = evsel->core.attr.exclude_kernel; + attr.exclude_hv = evsel->core.attr.exclude_hv; + attr.exclude_host = evsel->core.attr.exclude_host; + attr.exclude_guest = evsel->core.attr.exclude_guest; + attr.sample_id_all = evsel->core.attr.sample_id_all; + attr.read_format = evsel->core.attr.read_format; id = evsel->id[0] + 1000000000; if (!id) @@ -818,7 +818,7 @@ static int intel_bts_synth_events(struct intel_bts *bts, * We only use sample types from PERF_SAMPLE_MASK so we can use * __perf_evsel__sample_size() here. */ - bts->branches_event_size = sizeof(struct sample_event) + + bts->branches_event_size = sizeof(struct perf_record_sample) + __perf_evsel__sample_size(attr.sample_type); } @@ -834,7 +834,7 @@ static const char * const intel_bts_info_fmts[] = { [INTEL_BTS_SNAPSHOT_MODE] = " Snapshot mode %"PRId64"\n", }; -static void intel_bts_print_info(u64 *arr, int start, int finish) +static void intel_bts_print_info(__u64 *arr, int start, int finish) { int i; @@ -848,12 +848,12 @@ static void intel_bts_print_info(u64 *arr, int start, int finish) int intel_bts_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE; struct intel_bts *bts; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build index 23bf788f84b9..bc629359826f 100644 --- a/tools/perf/util/intel-pt-decoder/Build +++ b/tools/perf/util/intel-pt-decoder/Build @@ -1,7 +1,7 @@ perf-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o intel-pt-insn-decoder.o intel-pt-log.o intel-pt-decoder.o -inat_tables_script = util/intel-pt-decoder/gen-insn-attr-x86.awk -inat_tables_maps = util/intel-pt-decoder/x86-opcode-map.txt +inat_tables_script = $(srctree)/tools/arch/x86/tools/gen-insn-attr-x86.awk +inat_tables_maps = $(srctree)/tools/arch/x86/lib/x86-opcode-map.txt $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) $(call rule_mkdir) @@ -9,23 +9,7 @@ $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_table # Busybox's diff doesn't have -I, avoid warning in the case -$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/intel-pt-insn-decoder.c util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c - @(diff -I 2>&1 | grep -q 'option requires an argument' && \ - test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ - ((diff -B -I'^#include' util/intel-pt-decoder/insn.c ../../arch/x86/lib/insn.c >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder C file at 'tools/perf/util/intel-pt-decoder/insn.c' differs from latest version at 'arch/x86/lib/insn.c'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/inat.c ../../arch/x86/lib/inat.c >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder C file at 'tools/perf/util/intel-pt-decoder/inat.c' differs from latest version at 'arch/x86/lib/inat.c'" >&2)) && \ - ((diff -B util/intel-pt-decoder/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder map file at 'tools/perf/util/intel-pt-decoder/x86-opcode-map.txt' differs from latest version at 'arch/x86/lib/x86-opcode-map.txt'" >&2)) && \ - ((diff -B util/intel-pt-decoder/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder script at 'tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk' differs from latest version at 'arch/x86/tools/gen-insn-attr-x86.awk'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/insn.h ../../arch/x86/include/asm/insn.h >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder header at 'tools/perf/util/intel-pt-decoder/insn.h' differs from latest version at 'arch/x86/include/asm/insn.h'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/inat.h ../../arch/x86/include/asm/inat.h >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder header at 'tools/perf/util/intel-pt-decoder/inat.h' differs from latest version at 'arch/x86/include/asm/inat.h'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder header at 'tools/perf/util/intel-pt-decoder/inat_types.h' differs from latest version at 'arch/x86/include/asm/inat_types.h'" >&2)))) || true +$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/intel-pt-insn-decoder.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(call rule_mkdir) $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk b/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk deleted file mode 100644 index ddd5c4c21129..000000000000 --- a/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk +++ /dev/null @@ -1,392 +0,0 @@ -#!/bin/awk -f -# SPDX-License-Identifier: GPL-2.0 -# gen-insn-attr-x86.awk: Instruction attribute table generator -# Written by Masami Hiramatsu <mhiramat@redhat.com> -# -# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c - -# Awk implementation sanity check -function check_awk_implement() { - if (sprintf("%x", 0) != "0") - return "Your awk has a printf-format problem." - return "" -} - -# Clear working vars -function clear_vars() { - delete table - delete lptable2 - delete lptable1 - delete lptable3 - eid = -1 # escape id - gid = -1 # group id - aid = -1 # AVX id - tname = "" -} - -BEGIN { - # Implementation error checking - awkchecked = check_awk_implement() - if (awkchecked != "") { - print "Error: " awkchecked > "/dev/stderr" - print "Please try to use gawk." > "/dev/stderr" - exit 1 - } - - # Setup generating tables - print "/* x86 opcode map generated from x86-opcode-map.txt */" - print "/* Do not change this code. */\n" - ggid = 1 - geid = 1 - gaid = 0 - delete etable - delete gtable - delete atable - - opnd_expr = "^[A-Za-z/]" - ext_expr = "^\\(" - sep_expr = "^\\|$" - group_expr = "^Grp[0-9A-Za-z]+" - - imm_expr = "^[IJAOL][a-z]" - imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" - imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" - imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" - imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" - imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" - imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" - imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" - imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" - imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" - imm_flag["Ob"] = "INAT_MOFFSET" - imm_flag["Ov"] = "INAT_MOFFSET" - imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" - - modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" - force64_expr = "\\([df]64\\)" - rex_expr = "^REX(\\.[XRWB]+)*" - fpu_expr = "^ESC" # TODO - - lprefix1_expr = "\\((66|!F3)\\)" - lprefix2_expr = "\\(F3\\)" - lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" - lprefix_expr = "\\((66|F2|F3)\\)" - max_lprefix = 4 - - # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript - # accepts VEX prefix - vexok_opcode_expr = "^[vk].*" - vexok_expr = "\\(v1\\)" - # All opcodes with (v) superscript supports *only* VEX prefix - vexonly_expr = "\\(v\\)" - # All opcodes with (ev) superscript supports *only* EVEX prefix - evexonly_expr = "\\(ev\\)" - - prefix_expr = "\\(Prefix\\)" - prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" - prefix_num["REPNE"] = "INAT_PFX_REPNE" - prefix_num["REP/REPE"] = "INAT_PFX_REPE" - prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" - prefix_num["XRELEASE"] = "INAT_PFX_REPE" - prefix_num["LOCK"] = "INAT_PFX_LOCK" - prefix_num["SEG=CS"] = "INAT_PFX_CS" - prefix_num["SEG=DS"] = "INAT_PFX_DS" - prefix_num["SEG=ES"] = "INAT_PFX_ES" - prefix_num["SEG=FS"] = "INAT_PFX_FS" - prefix_num["SEG=GS"] = "INAT_PFX_GS" - prefix_num["SEG=SS"] = "INAT_PFX_SS" - prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" - prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" - prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" - prefix_num["EVEX"] = "INAT_PFX_EVEX" - - clear_vars() -} - -function semantic_error(msg) { - print "Semantic error at " NR ": " msg > "/dev/stderr" - exit 1 -} - -function debug(msg) { - print "DEBUG: " msg -} - -function array_size(arr, i,c) { - c = 0 - for (i in arr) - c++ - return c -} - -/^Table:/ { - print "/* " $0 " */" - if (tname != "") - semantic_error("Hit Table: before EndTable:."); -} - -/^Referrer:/ { - if (NF != 1) { - # escape opcode table - ref = "" - for (i = 2; i <= NF; i++) - ref = ref $i - eid = escape[ref] - tname = sprintf("inat_escape_table_%d", eid) - } -} - -/^AVXcode:/ { - if (NF != 1) { - # AVX/escape opcode table - aid = $2 - if (gaid <= aid) - gaid = aid + 1 - if (tname == "") # AVX only opcode table - tname = sprintf("inat_avx_table_%d", $2) - } - if (aid == -1 && eid == -1) # primary opcode table - tname = "inat_primary_table" -} - -/^GrpTable:/ { - print "/* " $0 " */" - if (!($2 in group)) - semantic_error("No group: " $2 ) - gid = group[$2] - tname = "inat_group_table_" gid -} - -function print_table(tbl,name,fmt,n) -{ - print "const insn_attr_t " name " = {" - for (i = 0; i < n; i++) { - id = sprintf(fmt, i) - if (tbl[id]) - print " [" id "] = " tbl[id] "," - } - print "};" -} - -/^EndTable/ { - if (gid != -1) { - # print group tables - if (array_size(table) != 0) { - print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,0] = tname - } - if (array_size(lptable1) != 0) { - print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,1] = tname "_1" - } - if (array_size(lptable2) != 0) { - print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,2] = tname "_2" - } - if (array_size(lptable3) != 0) { - print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,3] = tname "_3" - } - } else { - # print primary/escaped tables - if (array_size(table) != 0) { - print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,0] = tname - if (aid >= 0) - atable[aid,0] = tname - } - if (array_size(lptable1) != 0) { - print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,1] = tname "_1" - if (aid >= 0) - atable[aid,1] = tname "_1" - } - if (array_size(lptable2) != 0) { - print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,2] = tname "_2" - if (aid >= 0) - atable[aid,2] = tname "_2" - } - if (array_size(lptable3) != 0) { - print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,3] = tname "_3" - if (aid >= 0) - atable[aid,3] = tname "_3" - } - } - print "" - clear_vars() -} - -function add_flags(old,new) { - if (old && new) - return old " | " new - else if (old) - return old - else - return new -} - -# convert operands to flags. -function convert_operands(count,opnd, i,j,imm,mod) -{ - imm = null - mod = null - for (j = 1; j <= count; j++) { - i = opnd[j] - if (match(i, imm_expr) == 1) { - if (!imm_flag[i]) - semantic_error("Unknown imm opnd: " i) - if (imm) { - if (i != "Ib") - semantic_error("Second IMM error") - imm = add_flags(imm, "INAT_SCNDIMM") - } else - imm = imm_flag[i] - } else if (match(i, modrm_expr)) - mod = "INAT_MODRM" - } - return add_flags(imm, mod) -} - -/^[0-9a-f]+\:/ { - if (NR == 1) - next - # get index - idx = "0x" substr($1, 1, index($1,":") - 1) - if (idx in table) - semantic_error("Redefine " idx " in " tname) - - # check if escaped opcode - if ("escape" == $2) { - if ($3 != "#") - semantic_error("No escaped name") - ref = "" - for (i = 4; i <= NF; i++) - ref = ref $i - if (ref in escape) - semantic_error("Redefine escape (" ref ")") - escape[ref] = geid - geid++ - table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" - next - } - - variant = null - # converts - i = 2 - while (i <= NF) { - opcode = $(i++) - delete opnds - ext = null - flags = null - opnd = null - # parse one opcode - if (match($i, opnd_expr)) { - opnd = $i - count = split($(i++), opnds, ",") - flags = convert_operands(count, opnds) - } - if (match($i, ext_expr)) - ext = $(i++) - if (match($i, sep_expr)) - i++ - else if (i < NF) - semantic_error($i " is not a separator") - - # check if group opcode - if (match(opcode, group_expr)) { - if (!(opcode in group)) { - group[opcode] = ggid - ggid++ - } - flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") - } - # check force(or default) 64bit - if (match(ext, force64_expr)) - flags = add_flags(flags, "INAT_FORCE64") - - # check REX prefix - if (match(opcode, rex_expr)) - flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") - - # check coprocessor escape : TODO - if (match(opcode, fpu_expr)) - flags = add_flags(flags, "INAT_MODRM") - - # check VEX codes - if (match(ext, evexonly_expr)) - flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") - else if (match(ext, vexonly_expr)) - flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") - else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) - flags = add_flags(flags, "INAT_VEXOK") - - # check prefixes - if (match(ext, prefix_expr)) { - if (!prefix_num[opcode]) - semantic_error("Unknown prefix: " opcode) - flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") - } - if (length(flags) == 0) - continue - # check if last prefix - if (match(ext, lprefix1_expr)) { - lptable1[idx] = add_flags(lptable1[idx],flags) - variant = "INAT_VARIANT" - } - if (match(ext, lprefix2_expr)) { - lptable2[idx] = add_flags(lptable2[idx],flags) - variant = "INAT_VARIANT" - } - if (match(ext, lprefix3_expr)) { - lptable3[idx] = add_flags(lptable3[idx],flags) - variant = "INAT_VARIANT" - } - if (!match(ext, lprefix_expr)){ - table[idx] = add_flags(table[idx],flags) - } - } - if (variant) - table[idx] = add_flags(table[idx],variant) -} - -END { - if (awkchecked != "") - exit 1 - # print escape opcode map's array - print "/* Escape opcode map array */" - print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ - "[INAT_LSTPFX_MAX + 1] = {" - for (i = 0; i < geid; i++) - for (j = 0; j < max_lprefix; j++) - if (etable[i,j]) - print " ["i"]["j"] = "etable[i,j]"," - print "};\n" - # print group opcode map's array - print "/* Group opcode map array */" - print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ - "[INAT_LSTPFX_MAX + 1] = {" - for (i = 0; i < ggid; i++) - for (j = 0; j < max_lprefix; j++) - if (gtable[i,j]) - print " ["i"]["j"] = "gtable[i,j]"," - print "};\n" - # print AVX opcode map's array - print "/* AVX opcode map array */" - print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ - "[INAT_LSTPFX_MAX + 1] = {" - for (i = 0; i < gaid; i++) - for (j = 0; j < max_lprefix; j++) - if (atable[i,j]) - print " ["i"]["j"] = "atable[i,j]"," - print "};" -} diff --git a/tools/perf/util/intel-pt-decoder/inat.c b/tools/perf/util/intel-pt-decoder/inat.c deleted file mode 100644 index 446c0413a27c..000000000000 --- a/tools/perf/util/intel-pt-decoder/inat.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * x86 instruction attribute tables - * - * Written by Masami Hiramatsu <mhiramat@redhat.com> - */ -#include "insn.h" - -/* Attribute tables are generated from opcode map */ -#include "inat-tables.c" - -/* Attribute search APIs */ -insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) -{ - return inat_primary_table[opcode]; -} - -int inat_get_last_prefix_id(insn_byte_t last_pfx) -{ - insn_attr_t lpfx_attr; - - lpfx_attr = inat_get_opcode_attribute(last_pfx); - return inat_last_prefix_id(lpfx_attr); -} - -insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, - insn_attr_t esc_attr) -{ - const insn_attr_t *table; - int n; - - n = inat_escape_id(esc_attr); - - table = inat_escape_tables[n][0]; - if (!table) - return 0; - if (inat_has_variant(table[opcode]) && lpfx_id) { - table = inat_escape_tables[n][lpfx_id]; - if (!table) - return 0; - } - return table[opcode]; -} - -insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, - insn_attr_t grp_attr) -{ - const insn_attr_t *table; - int n; - - n = inat_group_id(grp_attr); - - table = inat_group_tables[n][0]; - if (!table) - return inat_group_common_attribute(grp_attr); - if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { - table = inat_group_tables[n][lpfx_id]; - if (!table) - return inat_group_common_attribute(grp_attr); - } - return table[X86_MODRM_REG(modrm)] | - inat_group_common_attribute(grp_attr); -} - -insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, - insn_byte_t vex_p) -{ - const insn_attr_t *table; - if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) - return 0; - /* At first, this checks the master table */ - table = inat_avx_tables[vex_m][0]; - if (!table) - return 0; - if (!inat_is_group(table[opcode]) && vex_p) { - /* If this is not a group, get attribute directly */ - table = inat_avx_tables[vex_m][vex_p]; - if (!table) - return 0; - } - return table[opcode]; -} diff --git a/tools/perf/util/intel-pt-decoder/inat_types.h b/tools/perf/util/intel-pt-decoder/inat_types.h deleted file mode 100644 index b047efa9ddc2..000000000000 --- a/tools/perf/util/intel-pt-decoder/inat_types.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_X86_INAT_TYPES_H -#define _ASM_X86_INAT_TYPES_H -/* - * x86 instruction attributes - * - * Written by Masami Hiramatsu <mhiramat@redhat.com> - */ - -/* Instruction attributes */ -typedef unsigned int insn_attr_t; -typedef unsigned char insn_byte_t; -typedef signed int insn_value_t; - -#endif diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 3bfdf2b7a96a..f8ccfd6be0ee 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -14,9 +14,9 @@ #include <stdint.h> #include <inttypes.h> #include <linux/compiler.h> +#include <linux/string.h> #include <linux/zalloc.h> -#include "../cache.h" #include "../auxtrace.h" #include "intel-pt-insn-decoder.h" diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c index 598f56be9f17..fb8a3558d3d5 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c @@ -4,17 +4,17 @@ * Copyright (c) 2013-2014, Intel Corporation. */ +#include <linux/kernel.h> #include <stdio.h> #include <string.h> #include <endian.h> #include <byteswap.h> +#include "../../../arch/x86/include/asm/insn.h" -#include "event.h" - -#include "insn.h" +#include "../../../arch/x86/lib/inat.c" +#include "../../../arch/x86/lib/insn.c" -#include "inat.c" -#include "insn.c" +#include "event.h" #include "intel-pt-insn-decoder.h" #include "dump-insn.h" diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt deleted file mode 100644 index e0b85930dd77..000000000000 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ /dev/null @@ -1,1072 +0,0 @@ -# x86 Opcode Maps -# -# This is (mostly) based on following documentations. -# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C -# (#326018-047US, June 2013) -# -#<Opcode maps> -# Table: table-name -# Referrer: escaped-name -# AVXcode: avx-code -# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] -# (or) -# opcode: escape # escaped-name -# EndTable -# -# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix -# mnemonics that begin with lowercase 'k' accept a VEX prefix -# -#<group maps> -# GrpTable: GrpXXX -# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] -# EndTable -# -# AVX Superscripts -# (ev): this opcode requires EVEX prefix. -# (evo): this opcode is changed by EVEX prefix (EVEX opcode) -# (v): this opcode requires VEX prefix. -# (v1): this opcode only supports 128bit VEX. -# -# Last Prefix Superscripts -# - (66): the last prefix is 0x66 -# - (F3): the last prefix is 0xF3 -# - (F2): the last prefix is 0xF2 -# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) -# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. - -Table: one byte opcode -Referrer: -AVXcode: -# 0x00 - 0x0f -00: ADD Eb,Gb -01: ADD Ev,Gv -02: ADD Gb,Eb -03: ADD Gv,Ev -04: ADD AL,Ib -05: ADD rAX,Iz -06: PUSH ES (i64) -07: POP ES (i64) -08: OR Eb,Gb -09: OR Ev,Gv -0a: OR Gb,Eb -0b: OR Gv,Ev -0c: OR AL,Ib -0d: OR rAX,Iz -0e: PUSH CS (i64) -0f: escape # 2-byte escape -# 0x10 - 0x1f -10: ADC Eb,Gb -11: ADC Ev,Gv -12: ADC Gb,Eb -13: ADC Gv,Ev -14: ADC AL,Ib -15: ADC rAX,Iz -16: PUSH SS (i64) -17: POP SS (i64) -18: SBB Eb,Gb -19: SBB Ev,Gv -1a: SBB Gb,Eb -1b: SBB Gv,Ev -1c: SBB AL,Ib -1d: SBB rAX,Iz -1e: PUSH DS (i64) -1f: POP DS (i64) -# 0x20 - 0x2f -20: AND Eb,Gb -21: AND Ev,Gv -22: AND Gb,Eb -23: AND Gv,Ev -24: AND AL,Ib -25: AND rAx,Iz -26: SEG=ES (Prefix) -27: DAA (i64) -28: SUB Eb,Gb -29: SUB Ev,Gv -2a: SUB Gb,Eb -2b: SUB Gv,Ev -2c: SUB AL,Ib -2d: SUB rAX,Iz -2e: SEG=CS (Prefix) -2f: DAS (i64) -# 0x30 - 0x3f -30: XOR Eb,Gb -31: XOR Ev,Gv -32: XOR Gb,Eb -33: XOR Gv,Ev -34: XOR AL,Ib -35: XOR rAX,Iz -36: SEG=SS (Prefix) -37: AAA (i64) -38: CMP Eb,Gb -39: CMP Ev,Gv -3a: CMP Gb,Eb -3b: CMP Gv,Ev -3c: CMP AL,Ib -3d: CMP rAX,Iz -3e: SEG=DS (Prefix) -3f: AAS (i64) -# 0x40 - 0x4f -40: INC eAX (i64) | REX (o64) -41: INC eCX (i64) | REX.B (o64) -42: INC eDX (i64) | REX.X (o64) -43: INC eBX (i64) | REX.XB (o64) -44: INC eSP (i64) | REX.R (o64) -45: INC eBP (i64) | REX.RB (o64) -46: INC eSI (i64) | REX.RX (o64) -47: INC eDI (i64) | REX.RXB (o64) -48: DEC eAX (i64) | REX.W (o64) -49: DEC eCX (i64) | REX.WB (o64) -4a: DEC eDX (i64) | REX.WX (o64) -4b: DEC eBX (i64) | REX.WXB (o64) -4c: DEC eSP (i64) | REX.WR (o64) -4d: DEC eBP (i64) | REX.WRB (o64) -4e: DEC eSI (i64) | REX.WRX (o64) -4f: DEC eDI (i64) | REX.WRXB (o64) -# 0x50 - 0x5f -50: PUSH rAX/r8 (d64) -51: PUSH rCX/r9 (d64) -52: PUSH rDX/r10 (d64) -53: PUSH rBX/r11 (d64) -54: PUSH rSP/r12 (d64) -55: PUSH rBP/r13 (d64) -56: PUSH rSI/r14 (d64) -57: PUSH rDI/r15 (d64) -58: POP rAX/r8 (d64) -59: POP rCX/r9 (d64) -5a: POP rDX/r10 (d64) -5b: POP rBX/r11 (d64) -5c: POP rSP/r12 (d64) -5d: POP rBP/r13 (d64) -5e: POP rSI/r14 (d64) -5f: POP rDI/r15 (d64) -# 0x60 - 0x6f -60: PUSHA/PUSHAD (i64) -61: POPA/POPAD (i64) -62: BOUND Gv,Ma (i64) | EVEX (Prefix) -63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) -64: SEG=FS (Prefix) -65: SEG=GS (Prefix) -66: Operand-Size (Prefix) -67: Address-Size (Prefix) -68: PUSH Iz (d64) -69: IMUL Gv,Ev,Iz -6a: PUSH Ib (d64) -6b: IMUL Gv,Ev,Ib -6c: INS/INSB Yb,DX -6d: INS/INSW/INSD Yz,DX -6e: OUTS/OUTSB DX,Xb -6f: OUTS/OUTSW/OUTSD DX,Xz -# 0x70 - 0x7f -70: JO Jb -71: JNO Jb -72: JB/JNAE/JC Jb -73: JNB/JAE/JNC Jb -74: JZ/JE Jb -75: JNZ/JNE Jb -76: JBE/JNA Jb -77: JNBE/JA Jb -78: JS Jb -79: JNS Jb -7a: JP/JPE Jb -7b: JNP/JPO Jb -7c: JL/JNGE Jb -7d: JNL/JGE Jb -7e: JLE/JNG Jb -7f: JNLE/JG Jb -# 0x80 - 0x8f -80: Grp1 Eb,Ib (1A) -81: Grp1 Ev,Iz (1A) -82: Grp1 Eb,Ib (1A),(i64) -83: Grp1 Ev,Ib (1A) -84: TEST Eb,Gb -85: TEST Ev,Gv -86: XCHG Eb,Gb -87: XCHG Ev,Gv -88: MOV Eb,Gb -89: MOV Ev,Gv -8a: MOV Gb,Eb -8b: MOV Gv,Ev -8c: MOV Ev,Sw -8d: LEA Gv,M -8e: MOV Sw,Ew -8f: Grp1A (1A) | POP Ev (d64) -# 0x90 - 0x9f -90: NOP | PAUSE (F3) | XCHG r8,rAX -91: XCHG rCX/r9,rAX -92: XCHG rDX/r10,rAX -93: XCHG rBX/r11,rAX -94: XCHG rSP/r12,rAX -95: XCHG rBP/r13,rAX -96: XCHG rSI/r14,rAX -97: XCHG rDI/r15,rAX -98: CBW/CWDE/CDQE -99: CWD/CDQ/CQO -9a: CALLF Ap (i64) -9b: FWAIT/WAIT -9c: PUSHF/D/Q Fv (d64) -9d: POPF/D/Q Fv (d64) -9e: SAHF -9f: LAHF -# 0xa0 - 0xaf -a0: MOV AL,Ob -a1: MOV rAX,Ov -a2: MOV Ob,AL -a3: MOV Ov,rAX -a4: MOVS/B Yb,Xb -a5: MOVS/W/D/Q Yv,Xv -a6: CMPS/B Xb,Yb -a7: CMPS/W/D Xv,Yv -a8: TEST AL,Ib -a9: TEST rAX,Iz -aa: STOS/B Yb,AL -ab: STOS/W/D/Q Yv,rAX -ac: LODS/B AL,Xb -ad: LODS/W/D/Q rAX,Xv -ae: SCAS/B AL,Yb -# Note: The May 2011 Intel manual shows Xv for the second parameter of the -# next instruction but Yv is correct -af: SCAS/W/D/Q rAX,Yv -# 0xb0 - 0xbf -b0: MOV AL/R8L,Ib -b1: MOV CL/R9L,Ib -b2: MOV DL/R10L,Ib -b3: MOV BL/R11L,Ib -b4: MOV AH/R12L,Ib -b5: MOV CH/R13L,Ib -b6: MOV DH/R14L,Ib -b7: MOV BH/R15L,Ib -b8: MOV rAX/r8,Iv -b9: MOV rCX/r9,Iv -ba: MOV rDX/r10,Iv -bb: MOV rBX/r11,Iv -bc: MOV rSP/r12,Iv -bd: MOV rBP/r13,Iv -be: MOV rSI/r14,Iv -bf: MOV rDI/r15,Iv -# 0xc0 - 0xcf -c0: Grp2 Eb,Ib (1A) -c1: Grp2 Ev,Ib (1A) -c2: RETN Iw (f64) -c3: RETN -c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) -c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) -c6: Grp11A Eb,Ib (1A) -c7: Grp11B Ev,Iz (1A) -c8: ENTER Iw,Ib -c9: LEAVE (d64) -ca: RETF Iw -cb: RETF -cc: INT3 -cd: INT Ib -ce: INTO (i64) -cf: IRET/D/Q -# 0xd0 - 0xdf -d0: Grp2 Eb,1 (1A) -d1: Grp2 Ev,1 (1A) -d2: Grp2 Eb,CL (1A) -d3: Grp2 Ev,CL (1A) -d4: AAM Ib (i64) -d5: AAD Ib (i64) -d6: -d7: XLAT/XLATB -d8: ESC -d9: ESC -da: ESC -db: ESC -dc: ESC -dd: ESC -de: ESC -df: ESC -# 0xe0 - 0xef -# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix -# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation -# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. -e0: LOOPNE/LOOPNZ Jb (f64) -e1: LOOPE/LOOPZ Jb (f64) -e2: LOOP Jb (f64) -e3: JrCXZ Jb (f64) -e4: IN AL,Ib -e5: IN eAX,Ib -e6: OUT Ib,AL -e7: OUT Ib,eAX -# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset -# in "near" jumps and calls is 16-bit. For CALL, -# push of return address is 16-bit wide, RSP is decremented by 2 -# but is not truncated to 16 bits, unlike RIP. -e8: CALL Jz (f64) -e9: JMP-near Jz (f64) -ea: JMP-far Ap (i64) -eb: JMP-short Jb (f64) -ec: IN AL,DX -ed: IN eAX,DX -ee: OUT DX,AL -ef: OUT DX,eAX -# 0xf0 - 0xff -f0: LOCK (Prefix) -f1: -f2: REPNE (Prefix) | XACQUIRE (Prefix) -f3: REP/REPE (Prefix) | XRELEASE (Prefix) -f4: HLT -f5: CMC -f6: Grp3_1 Eb (1A) -f7: Grp3_2 Ev (1A) -f8: CLC -f9: STC -fa: CLI -fb: STI -fc: CLD -fd: STD -fe: Grp4 (1A) -ff: Grp5 (1A) -EndTable - -Table: 2-byte opcode (0x0f) -Referrer: 2-byte escape -AVXcode: 1 -# 0x0f 0x00-0x0f -00: Grp6 (1A) -01: Grp7 (1A) -02: LAR Gv,Ew -03: LSL Gv,Ew -04: -05: SYSCALL (o64) -06: CLTS -07: SYSRET (o64) -08: INVD -09: WBINVD -0a: -0b: UD2 (1B) -0c: -# AMD's prefetch group. Intel supports prefetchw(/1) only. -0d: GrpP -0e: FEMMS -# 3DNow! uses the last imm byte as opcode extension. -0f: 3DNow! Pq,Qq,Ib -# 0x0f 0x10-0x1f -# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands -# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. -# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. -# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming -# Reference A.1 -10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) -11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) -12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) -13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) -14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) -15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) -16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) -17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) -18: Grp16 (1A) -19: -# Intel SDM opcode map does not list MPX instructions. For now using Gv for -# bnd registers and Ev for everything else is OK because the instruction -# decoder does not use the information except as an indication that there is -# a ModR/M byte. -1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev -1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv -1c: -1d: -1e: -1f: NOP Ev -# 0x0f 0x20-0x2f -20: MOV Rd,Cd -21: MOV Rd,Dd -22: MOV Cd,Rd -23: MOV Dd,Rd -24: -25: -26: -27: -28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) -29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) -2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) -2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) -2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) -2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) -2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) -2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) -# 0x0f 0x30-0x3f -30: WRMSR -31: RDTSC -32: RDMSR -33: RDPMC -34: SYSENTER -35: SYSEXIT -36: -37: GETSEC -38: escape # 3-byte escape 1 -39: -3a: escape # 3-byte escape 2 -3b: -3c: -3d: -3e: -3f: -# 0x0f 0x40-0x4f -40: CMOVO Gv,Ev -41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) -42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) -43: CMOVAE/NB/NC Gv,Ev -44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) -45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) -46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) -47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) -48: CMOVS Gv,Ev -49: CMOVNS Gv,Ev -4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) -4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk -4c: CMOVL/NGE Gv,Ev -4d: CMOVNL/GE Gv,Ev -4e: CMOVLE/NG Gv,Ev -4f: CMOVNLE/G Gv,Ev -# 0x0f 0x50-0x5f -50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) -51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) -52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) -53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) -54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) -55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) -56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) -57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) -58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) -59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) -5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) -5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) -5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) -5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) -5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) -5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) -# 0x0f 0x60-0x6f -60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) -61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) -62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) -63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) -64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) -65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) -66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) -67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) -68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) -69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) -6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) -6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) -6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) -6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) -6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) -6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) -# 0x0f 0x70-0x7f -70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) -71: Grp12 (1A) -72: Grp13 (1A) -73: Grp14 (1A) -74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) -75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) -76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) -# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. -77: emms | vzeroupper | vzeroall -78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) -79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) -7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) -7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) -7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) -7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) -7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) -7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) -# 0x0f 0x80-0x8f -# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). -80: JO Jz (f64) -81: JNO Jz (f64) -82: JB/JC/JNAE Jz (f64) -83: JAE/JNB/JNC Jz (f64) -84: JE/JZ Jz (f64) -85: JNE/JNZ Jz (f64) -86: JBE/JNA Jz (f64) -87: JA/JNBE Jz (f64) -88: JS Jz (f64) -89: JNS Jz (f64) -8a: JP/JPE Jz (f64) -8b: JNP/JPO Jz (f64) -8c: JL/JNGE Jz (f64) -8d: JNL/JGE Jz (f64) -8e: JLE/JNG Jz (f64) -8f: JNLE/JG Jz (f64) -# 0x0f 0x90-0x9f -90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) -91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) -92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) -93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) -94: SETE/Z Eb -95: SETNE/NZ Eb -96: SETBE/NA Eb -97: SETA/NBE Eb -98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) -99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) -9a: SETP/PE Eb -9b: SETNP/PO Eb -9c: SETL/NGE Eb -9d: SETNL/GE Eb -9e: SETLE/NG Eb -9f: SETNLE/G Eb -# 0x0f 0xa0-0xaf -a0: PUSH FS (d64) -a1: POP FS (d64) -a2: CPUID -a3: BT Ev,Gv -a4: SHLD Ev,Gv,Ib -a5: SHLD Ev,Gv,CL -a6: GrpPDLK -a7: GrpRNG -a8: PUSH GS (d64) -a9: POP GS (d64) -aa: RSM -ab: BTS Ev,Gv -ac: SHRD Ev,Gv,Ib -ad: SHRD Ev,Gv,CL -ae: Grp15 (1A),(1C) -af: IMUL Gv,Ev -# 0x0f 0xb0-0xbf -b0: CMPXCHG Eb,Gb -b1: CMPXCHG Ev,Gv -b2: LSS Gv,Mp -b3: BTR Ev,Gv -b4: LFS Gv,Mp -b5: LGS Gv,Mp -b6: MOVZX Gv,Eb -b7: MOVZX Gv,Ew -b8: JMPE (!F3) | POPCNT Gv,Ev (F3) -b9: Grp10 (1A) -ba: Grp8 Ev,Ib (1A) -bb: BTC Ev,Gv -bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) -bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) -be: MOVSX Gv,Eb -bf: MOVSX Gv,Ew -# 0x0f 0xc0-0xcf -c0: XADD Eb,Gb -c1: XADD Ev,Gv -c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) -c3: movnti My,Gy -c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) -c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) -c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) -c7: Grp9 (1A) -c8: BSWAP RAX/EAX/R8/R8D -c9: BSWAP RCX/ECX/R9/R9D -ca: BSWAP RDX/EDX/R10/R10D -cb: BSWAP RBX/EBX/R11/R11D -cc: BSWAP RSP/ESP/R12/R12D -cd: BSWAP RBP/EBP/R13/R13D -ce: BSWAP RSI/ESI/R14/R14D -cf: BSWAP RDI/EDI/R15/R15D -# 0x0f 0xd0-0xdf -d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) -d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) -d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) -d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) -d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) -d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) -d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) -d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) -d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) -d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) -da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) -db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) -dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) -dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) -de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) -df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) -# 0x0f 0xe0-0xef -e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) -e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) -e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) -e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) -e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) -e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) -e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) -e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) -e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) -e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) -ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) -eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) -ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) -ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) -ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) -ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) -# 0x0f 0xf0-0xff -f0: vlddqu Vx,Mx (F2) -f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) -f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) -f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) -f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) -f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) -f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) -f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) -f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) -f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) -fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) -fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) -fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) -fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) -fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) -ff: UD0 -EndTable - -Table: 3-byte opcode 1 (0x0f 0x38) -Referrer: 3-byte escape 1 -AVXcode: 2 -# 0x0f 0x38 0x00-0x0f -00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) -01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) -02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) -03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) -04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) -05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) -06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) -07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) -08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) -09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) -0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) -0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) -0c: vpermilps Vx,Hx,Wx (66),(v) -0d: vpermilpd Vx,Hx,Wx (66),(v) -0e: vtestps Vx,Wx (66),(v) -0f: vtestpd Vx,Wx (66),(v) -# 0x0f 0x38 0x10-0x1f -10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) -11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) -12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) -13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) -14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) -15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) -16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) -17: vptest Vx,Wx (66) -18: vbroadcastss Vx,Wd (66),(v) -19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) -1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) -1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) -1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) -1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) -1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) -1f: vpabsq Vx,Wx (66),(ev) -# 0x0f 0x38 0x20-0x2f -20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) -21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) -22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) -23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) -24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) -25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) -26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) -27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) -28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) -29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) -2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) -2b: vpackusdw Vx,Hx,Wx (66),(v1) -2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) -2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) -2e: vmaskmovps Mx,Hx,Vx (66),(v) -2f: vmaskmovpd Mx,Hx,Vx (66),(v) -# 0x0f 0x38 0x30-0x3f -30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) -31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) -32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) -33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) -34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) -35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) -36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) -37: vpcmpgtq Vx,Hx,Wx (66),(v1) -38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) -39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) -3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) -3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) -3c: vpmaxsb Vx,Hx,Wx (66),(v1) -3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) -3e: vpmaxuw Vx,Hx,Wx (66),(v1) -3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) -# 0x0f 0x38 0x40-0x8f -40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) -41: vphminposuw Vdq,Wdq (66),(v1) -42: vgetexpps/d Vx,Wx (66),(ev) -43: vgetexpss/d Vx,Hx,Wx (66),(ev) -44: vplzcntd/q Vx,Wx (66),(ev) -45: vpsrlvd/q Vx,Hx,Wx (66),(v) -46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) -47: vpsllvd/q Vx,Hx,Wx (66),(v) -# Skip 0x48-0x4b -4c: vrcp14ps/d Vpd,Wpd (66),(ev) -4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) -4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) -4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) -# Skip 0x50-0x57 -58: vpbroadcastd Vx,Wx (66),(v) -59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) -5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) -5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) -# Skip 0x5c-0x63 -64: vpblendmd/q Vx,Hx,Wx (66),(ev) -65: vblendmps/d Vx,Hx,Wx (66),(ev) -66: vpblendmb/w Vx,Hx,Wx (66),(ev) -# Skip 0x67-0x74 -75: vpermi2b/w Vx,Hx,Wx (66),(ev) -76: vpermi2d/q Vx,Hx,Wx (66),(ev) -77: vpermi2ps/d Vx,Hx,Wx (66),(ev) -78: vpbroadcastb Vx,Wx (66),(v) -79: vpbroadcastw Vx,Wx (66),(v) -7a: vpbroadcastb Vx,Rv (66),(ev) -7b: vpbroadcastw Vx,Rv (66),(ev) -7c: vpbroadcastd/q Vx,Rv (66),(ev) -7d: vpermt2b/w Vx,Hx,Wx (66),(ev) -7e: vpermt2d/q Vx,Hx,Wx (66),(ev) -7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) -80: INVEPT Gy,Mdq (66) -81: INVVPID Gy,Mdq (66) -82: INVPCID Gy,Mdq (66) -83: vpmultishiftqb Vx,Hx,Wx (66),(ev) -88: vexpandps/d Vpd,Wpd (66),(ev) -89: vpexpandd/q Vx,Wx (66),(ev) -8a: vcompressps/d Wx,Vx (66),(ev) -8b: vpcompressd/q Wx,Vx (66),(ev) -8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) -8d: vpermb/w Vx,Hx,Wx (66),(ev) -8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) -# 0x0f 0x38 0x90-0xbf (FMA) -90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) -91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) -92: vgatherdps/d Vx,Hx,Wx (66),(v) -93: vgatherqps/d Vx,Hx,Wx (66),(v) -94: -95: -96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) -97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) -98: vfmadd132ps/d Vx,Hx,Wx (66),(v) -99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) -9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) -9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) -9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -a0: vpscatterdd/q Wx,Vx (66),(ev) -a1: vpscatterqd/q Wx,Vx (66),(ev) -a2: vscatterdps/d Wx,Vx (66),(ev) -a3: vscatterqps/d Wx,Vx (66),(ev) -a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) -a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) -a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) -a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) -ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) -ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) -af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -b4: vpmadd52luq Vx,Hx,Wx (66),(ev) -b5: vpmadd52huq Vx,Hx,Wx (66),(ev) -b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) -b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) -b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) -b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) -bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) -bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) -bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -# 0x0f 0x38 0xc0-0xff -c4: vpconflictd/q Vx,Wx (66),(ev) -c6: Grp18 (1A) -c7: Grp19 (1A) -c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) -c9: sha1msg1 Vdq,Wdq -ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) -cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) -cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) -cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) -db: VAESIMC Vdq,Wdq (66),(v1) -dc: VAESENC Vdq,Hdq,Wdq (66),(v1) -dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) -de: VAESDEC Vdq,Hdq,Wdq (66),(v1) -df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) -f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) -f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) -f2: ANDN Gy,By,Ey (v) -f3: Grp17 (1A) -f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) -f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) -f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) -EndTable - -Table: 3-byte opcode 2 (0x0f 0x3a) -Referrer: 3-byte escape 2 -AVXcode: 3 -# 0x0f 0x3a 0x00-0xff -00: vpermq Vqq,Wqq,Ib (66),(v) -01: vpermpd Vqq,Wqq,Ib (66),(v) -02: vpblendd Vx,Hx,Wx,Ib (66),(v) -03: valignd/q Vx,Hx,Wx,Ib (66),(ev) -04: vpermilps Vx,Wx,Ib (66),(v) -05: vpermilpd Vx,Wx,Ib (66),(v) -06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) -07: -08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) -09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) -0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) -0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) -0c: vblendps Vx,Hx,Wx,Ib (66) -0d: vblendpd Vx,Hx,Wx,Ib (66) -0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) -0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) -14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) -15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) -16: vpextrd/q Ey,Vdq,Ib (66),(v1) -17: vextractps Ed,Vdq,Ib (66),(v1) -18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) -19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) -1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) -1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) -1d: vcvtps2ph Wx,Vx,Ib (66),(v) -1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) -1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) -20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) -21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) -22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) -23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) -25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) -26: vgetmantps/d Vx,Wx,Ib (66),(ev) -27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) -30: kshiftrb/w Vk,Uk,Ib (66),(v) -31: kshiftrd/q Vk,Uk,Ib (66),(v) -32: kshiftlb/w Vk,Uk,Ib (66),(v) -33: kshiftld/q Vk,Uk,Ib (66),(v) -38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) -39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) -3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) -3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) -3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) -3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) -40: vdpps Vx,Hx,Wx,Ib (66) -41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) -42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) -43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) -44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) -46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) -4a: vblendvps Vx,Hx,Wx,Lx (66),(v) -4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) -4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) -50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) -51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) -54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) -55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) -56: vreduceps/d Vx,Wx,Ib (66),(ev) -57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) -60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) -61: vpcmpestri Vdq,Wdq,Ib (66),(v1) -62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) -63: vpcmpistri Vdq,Wdq,Ib (66),(v1) -66: vfpclassps/d Vk,Wx,Ib (66),(ev) -67: vfpclassss/d Vk,Wx,Ib (66),(ev) -cc: sha1rnds4 Vdq,Wdq,Ib -df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) -f0: RORX Gy,Ey,Ib (F2),(v) -EndTable - -GrpTable: Grp1 -0: ADD -1: OR -2: ADC -3: SBB -4: AND -5: SUB -6: XOR -7: CMP -EndTable - -GrpTable: Grp1A -0: POP -EndTable - -GrpTable: Grp2 -0: ROL -1: ROR -2: RCL -3: RCR -4: SHL/SAL -5: SHR -6: -7: SAR -EndTable - -GrpTable: Grp3_1 -0: TEST Eb,Ib -1: TEST Eb,Ib -2: NOT Eb -3: NEG Eb -4: MUL AL,Eb -5: IMUL AL,Eb -6: DIV AL,Eb -7: IDIV AL,Eb -EndTable - -GrpTable: Grp3_2 -0: TEST Ev,Iz -1: -2: NOT Ev -3: NEG Ev -4: MUL rAX,Ev -5: IMUL rAX,Ev -6: DIV rAX,Ev -7: IDIV rAX,Ev -EndTable - -GrpTable: Grp4 -0: INC Eb -1: DEC Eb -EndTable - -GrpTable: Grp5 -0: INC Ev -1: DEC Ev -# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). -2: CALLN Ev (f64) -3: CALLF Ep -4: JMPN Ev (f64) -5: JMPF Mp -6: PUSH Ev (d64) -7: -EndTable - -GrpTable: Grp6 -0: SLDT Rv/Mw -1: STR Rv/Mw -2: LLDT Ew -3: LTR Ew -4: VERR Ew -5: VERW Ew -EndTable - -GrpTable: Grp7 -0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) -1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) -2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) -3: LIDT Ms -4: SMSW Mw/Rv -5: rdpkru (110),(11B) | wrpkru (111),(11B) -6: LMSW Ew -7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) -EndTable - -GrpTable: Grp8 -4: BT -5: BTS -6: BTR -7: BTC -EndTable - -GrpTable: Grp9 -1: CMPXCHG8B/16B Mq/Mdq -3: xrstors -4: xsavec -5: xsaves -6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) -7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) -EndTable - -GrpTable: Grp10 -# all are UD1 -0: UD1 -1: UD1 -2: UD1 -3: UD1 -4: UD1 -5: UD1 -6: UD1 -7: UD1 -EndTable - -# Grp11A and Grp11B are expressed as Grp11 in Intel SDM -GrpTable: Grp11A -0: MOV Eb,Ib -7: XABORT Ib (000),(11B) -EndTable - -GrpTable: Grp11B -0: MOV Eb,Iz -7: XBEGIN Jz (000),(11B) -EndTable - -GrpTable: Grp12 -2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) -4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) -6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) -EndTable - -GrpTable: Grp13 -0: vprord/q Hx,Wx,Ib (66),(ev) -1: vprold/q Hx,Wx,Ib (66),(ev) -2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) -4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) -6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) -EndTable - -GrpTable: Grp14 -2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) -3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) -6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) -7: vpslldq Hx,Ux,Ib (66),(11B),(v1) -EndTable - -GrpTable: Grp15 -0: fxsave | RDFSBASE Ry (F3),(11B) -1: fxstor | RDGSBASE Ry (F3),(11B) -2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) -3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) -4: XSAVE | ptwrite Ey (F3),(11B) -5: XRSTOR | lfence (11B) -6: XSAVEOPT | clwb (66) | mfence (11B) -7: clflush | clflushopt (66) | sfence (11B) -EndTable - -GrpTable: Grp16 -0: prefetch NTA -1: prefetch T0 -2: prefetch T1 -3: prefetch T2 -EndTable - -GrpTable: Grp17 -1: BLSR By,Ey (v) -2: BLSMSK By,Ey (v) -3: BLSI By,Ey (v) -EndTable - -GrpTable: Grp18 -1: vgatherpf0dps/d Wx (66),(ev) -2: vgatherpf1dps/d Wx (66),(ev) -5: vscatterpf0dps/d Wx (66),(ev) -6: vscatterpf1dps/d Wx (66),(ev) -EndTable - -GrpTable: Grp19 -1: vgatherpf0qps/d Wx (66),(ev) -2: vgatherpf1qps/d Wx (66),(ev) -5: vscatterpf0qps/d Wx (66),(ev) -6: vscatterpf1qps/d Wx (66),(ev) -EndTable - -# AMD's Prefetch Group -GrpTable: GrpP -0: PREFETCH -1: PREFETCHW -EndTable - -GrpTable: GrpPDLK -0: MONTMUL -1: XSHA1 -2: XSHA2 -EndTable - -GrpTable: GrpRNG -0: xstore-rng -1: xcrypt-ecb -2: xcrypt-cbc -4: xcrypt-cfb -5: xcrypt-ofb -EndTable diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index df061599fef4..9b56fb74bedf 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -9,10 +9,10 @@ #include <stdbool.h> #include <errno.h> #include <linux/kernel.h> +#include <linux/string.h> #include <linux/types.h> #include <linux/zalloc.h> -#include "../perf.h" #include "session.h" #include "machine.h" #include "memswap.h" @@ -56,7 +56,7 @@ struct intel_pt { u32 auxtrace_type; struct perf_session *session; struct machine *machine; - struct perf_evsel *switch_evsel; + struct evsel *switch_evsel; struct thread *unknown_thread; bool timeless_decoding; bool sampling_mode; @@ -104,7 +104,7 @@ struct intel_pt { u64 cbr_id; bool sample_pebs; - struct perf_evsel *pebs_evsel; + struct evsel *pebs_evsel; u64 tsc_bit; u64 mtc_bit; @@ -723,11 +723,11 @@ static bool intel_pt_get_config(struct intel_pt *pt, static bool intel_pt_exclude_kernel(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, NULL) && - !evsel->attr.exclude_kernel) + if (intel_pt_get_config(pt, &evsel->core.attr, NULL) && + !evsel->core.attr.exclude_kernel) return false; } return true; @@ -735,14 +735,14 @@ static bool intel_pt_exclude_kernel(struct intel_pt *pt) static bool intel_pt_return_compression(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 config; if (!pt->noretcomp_bit) return true; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config) && + if (intel_pt_get_config(pt, &evsel->core.attr, &config) && (config & pt->noretcomp_bit)) return false; } @@ -751,11 +751,11 @@ static bool intel_pt_return_compression(struct intel_pt *pt) static bool intel_pt_branch_enable(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 config; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config) && + if (intel_pt_get_config(pt, &evsel->core.attr, &config) && (config & 1) && !(config & 0x2000)) return false; } @@ -764,7 +764,7 @@ static bool intel_pt_branch_enable(struct intel_pt *pt) static unsigned int intel_pt_mtc_period(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; unsigned int shift; u64 config; @@ -775,7 +775,7 @@ static unsigned int intel_pt_mtc_period(struct intel_pt *pt) config >>= 1; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config)) + if (intel_pt_get_config(pt, &evsel->core.attr, &config)) return (config & pt->mtc_freq_bits) >> shift; } return 0; @@ -783,7 +783,7 @@ static unsigned int intel_pt_mtc_period(struct intel_pt *pt) static bool intel_pt_timeless_decoding(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; bool timeless_decoding = true; u64 config; @@ -791,9 +791,9 @@ static bool intel_pt_timeless_decoding(struct intel_pt *pt) return true; evlist__for_each_entry(pt->session->evlist, evsel) { - if (!(evsel->attr.sample_type & PERF_SAMPLE_TIME)) + if (!(evsel->core.attr.sample_type & PERF_SAMPLE_TIME)) return true; - if (intel_pt_get_config(pt, &evsel->attr, &config)) { + if (intel_pt_get_config(pt, &evsel->core.attr, &config)) { if (config & pt->tsc_bit) timeless_decoding = false; else @@ -805,11 +805,11 @@ static bool intel_pt_timeless_decoding(struct intel_pt *pt) static bool intel_pt_tracing_kernel(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, NULL) && - !evsel->attr.exclude_kernel) + if (intel_pt_get_config(pt, &evsel->core.attr, NULL) && + !evsel->core.attr.exclude_kernel) return true; } return false; @@ -817,7 +817,7 @@ static bool intel_pt_tracing_kernel(struct intel_pt *pt) static bool intel_pt_have_tsc(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; bool have_tsc = false; u64 config; @@ -825,7 +825,7 @@ static bool intel_pt_have_tsc(struct intel_pt *pt) return false; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config)) { + if (intel_pt_get_config(pt, &evsel->core.attr, &config)) { if (config & pt->tsc_bit) have_tsc = true; else @@ -1702,8 +1702,8 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) struct perf_sample sample = { .ip = 0, }; union perf_event *event = ptq->event_buf; struct intel_pt *pt = ptq->pt; - struct perf_evsel *evsel = pt->pebs_evsel; - u64 sample_type = evsel->attr.sample_type; + struct evsel *evsel = pt->pebs_evsel; + u64 sample_type = evsel->core.attr.sample_type; u64 id = evsel->id[0]; u8 cpumode; @@ -1715,8 +1715,8 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) sample.id = id; sample.stream_id = id; - if (!evsel->attr.freq) - sample.period = evsel->attr.sample_period; + if (!evsel->core.attr.freq) + sample.period = evsel->core.attr.sample_period; /* No support for non-zero CS base */ if (items->has_ip) @@ -1757,7 +1757,7 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) if (sample_type & PERF_SAMPLE_REGS_INTR && items->mask[INTEL_PT_GP_REGS_POS]) { u64 regs[sizeof(sample.intr_regs.mask)]; - u64 regs_mask = evsel->attr.sample_regs_intr; + u64 regs_mask = evsel->core.attr.sample_regs_intr; u64 *pos; sample.intr_regs.abi = items->is_32_bit ? @@ -2401,7 +2401,7 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid, static int intel_pt_process_switch(struct intel_pt *pt, struct perf_sample *sample) { - struct perf_evsel *evsel; + struct evsel *evsel; pid_t tid; int cpu, ret; @@ -2713,10 +2713,10 @@ static int intel_pt_synth_event(struct perf_session *session, const char *name, return err; } -static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, +static void intel_pt_set_event_name(struct evlist *evlist, u64 id, const char *name) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->id && evsel->id[0] == id) { @@ -2728,13 +2728,13 @@ static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, } } -static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, - struct perf_evlist *evlist) +static struct evsel *intel_pt_evsel(struct intel_pt *pt, + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == pt->pmu_type && evsel->ids) + if (evsel->core.attr.type == pt->pmu_type && evsel->ids) return evsel; } @@ -2744,8 +2744,8 @@ static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, static int intel_pt_synth_events(struct intel_pt *pt, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel = intel_pt_evsel(pt, evlist); + struct evlist *evlist = session->evlist; + struct evsel *evsel = intel_pt_evsel(pt, evlist); struct perf_event_attr attr; u64 id; int err; @@ -2758,7 +2758,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, memset(&attr, 0, sizeof(struct perf_event_attr)); attr.size = sizeof(struct perf_event_attr); attr.type = PERF_TYPE_HARDWARE; - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; if (pt->timeless_decoding) @@ -2767,13 +2767,13 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_type |= PERF_SAMPLE_TIME; if (!pt->per_cpu_mmaps) attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; - attr.exclude_user = evsel->attr.exclude_user; - attr.exclude_kernel = evsel->attr.exclude_kernel; - attr.exclude_hv = evsel->attr.exclude_hv; - attr.exclude_host = evsel->attr.exclude_host; - attr.exclude_guest = evsel->attr.exclude_guest; - attr.sample_id_all = evsel->attr.sample_id_all; - attr.read_format = evsel->attr.read_format; + attr.exclude_user = evsel->core.attr.exclude_user; + attr.exclude_kernel = evsel->core.attr.exclude_kernel; + attr.exclude_hv = evsel->core.attr.exclude_hv; + attr.exclude_host = evsel->core.attr.exclude_host; + attr.exclude_guest = evsel->core.attr.exclude_guest; + attr.sample_id_all = evsel->core.attr.sample_id_all; + attr.read_format = evsel->core.attr.read_format; id = evsel->id[0] + 1000000000; if (!id) @@ -2857,7 +2857,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, id += 1; } - if (pt->synth_opts.pwr_events && (evsel->attr.config & 0x10)) { + if (pt->synth_opts.pwr_events && (evsel->core.attr.config & 0x10)) { attr.config = PERF_SYNTH_INTEL_MWAIT; err = intel_pt_synth_event(session, "mwait", &attr, id); if (err) @@ -2894,9 +2894,25 @@ static int intel_pt_synth_events(struct intel_pt *pt, return 0; } -static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) +static void intel_pt_setup_pebs_events(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; + + if (!pt->synth_opts.other_events) + return; + + evlist__for_each_entry(pt->session->evlist, evsel) { + if (evsel->core.attr.aux_output && evsel->id) { + pt->sample_pebs = true; + pt->pebs_evsel = evsel; + return; + } + } +} + +static struct evsel *intel_pt_find_sched_switch(struct evlist *evlist) +{ + struct evsel *evsel; evlist__for_each_entry_reverse(evlist, evsel) { const char *name = perf_evsel__name(evsel); @@ -2908,12 +2924,12 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) return NULL; } -static bool intel_pt_find_switch(struct perf_evlist *evlist) +static bool intel_pt_find_switch(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.context_switch) + if (evsel->core.attr.context_switch) return true; } @@ -3028,7 +3044,7 @@ static const char * const intel_pt_info_fmts[] = { [INTEL_PT_FILTER_STR_LEN] = " Filter string len. %"PRIu64"\n", }; -static void intel_pt_print_info(u64 *arr, int start, int finish) +static void intel_pt_print_info(__u64 *arr, int start, int finish) { int i; @@ -3047,23 +3063,23 @@ static void intel_pt_print_info_str(const char *name, const char *str) fprintf(stdout, " %-20s%s\n", name, str ? str : ""); } -static bool intel_pt_has(struct auxtrace_info_event *auxtrace_info, int pos) +static bool intel_pt_has(struct perf_record_auxtrace_info *auxtrace_info, int pos) { return auxtrace_info->header.size >= - sizeof(struct auxtrace_info_event) + (sizeof(u64) * (pos + 1)); + sizeof(struct perf_record_auxtrace_info) + (sizeof(u64) * (pos + 1)); } int intel_pt_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * INTEL_PT_PER_CPU_MMAPS; struct intel_pt *pt; void *info_end; - u64 *info; + __u64 *info; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; @@ -3263,6 +3279,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, if (err) goto err_delete_thread; + intel_pt_setup_pebs_events(pt); + err = auxtrace_queues__process_index(&pt->queues, session); if (err) goto err_delete_thread; diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index 18c34f0c1966..b80f29bfc7bb 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -14,6 +14,7 @@ #include <sys/mman.h> #include <linux/stringify.h> +#include "build-id.h" #include "util.h" #include "event.h" #include "debug.h" @@ -118,13 +119,13 @@ jit_close(struct jit_buf_desc *jd) static int jit_validate_events(struct perf_session *session) { - struct perf_evsel *evsel; + struct evsel *evsel; /* * check that all events use CLOCK_MONOTONIC */ evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC) + if (evsel->core.attr.use_clockid == 0 || evsel->core.attr.clockid != CLOCK_MONOTONIC) return -1; } return 0; @@ -758,7 +759,7 @@ jit_process(struct perf_session *session, pid_t pid, u64 *nbytes) { - struct perf_evsel *first; + struct evsel *first; struct jit_buf_desc jd; int ret; @@ -779,7 +780,7 @@ jit_process(struct perf_session *session, * perf sets the same sample type to all events as of now */ first = perf_evlist__first(session->evlist); - jd.sample_type = first->attr.sample_type; + jd.sample_type = first->core.attr.sample_type; *nbytes = 0; diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 1403dec189b4..46913637085b 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -2,12 +2,12 @@ #ifndef __PERF_KVM_STAT_H #define __PERF_KVM_STAT_H -#include "../perf.h" #include "tool.h" #include "stat.h" +#include "record.h" -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct perf_session; struct event_key { @@ -45,17 +45,17 @@ struct kvm_event_key { struct perf_kvm_stat; struct child_event_ops { - void (*get_key)(struct perf_evsel *evsel, + void (*get_key)(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); const char *name; }; struct kvm_events_ops { - bool (*is_begin_event)(struct perf_evsel *evsel, + bool (*is_begin_event)(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); - bool (*is_end_event)(struct perf_evsel *evsel, + bool (*is_end_event)(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); struct child_event_ops *child_ops; void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, @@ -74,7 +74,7 @@ struct exit_reasons_table { struct perf_kvm_stat { struct perf_tool tool; struct record_opts opts; - struct perf_evlist *evlist; + struct evlist *evlist; struct perf_session *session; const char *file_name; @@ -109,21 +109,21 @@ struct kvm_reg_events_ops { struct kvm_events_ops *ops; }; -void exit_event_get_key(struct perf_evsel *evsel, +void exit_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); -bool exit_event_begin(struct perf_evsel *evsel, +bool exit_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); -bool exit_event_end(struct perf_evsel *evsel, +bool exit_event_end(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); void exit_event_decode_key(struct perf_kvm_stat *kvm, struct event_key *key, char *decode); -bool kvm_exit_event(struct perf_evsel *evsel); -bool kvm_entry_event(struct perf_evsel *evsel); +bool kvm_exit_event(struct evsel *evsel); +bool kvm_entry_event(struct evsel *evsel); int setup_kvm_events_tp(struct perf_kvm_stat *kvm); #define define_exit_reasons_table(name, symbols) \ diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 9f0470ecbca9..55fb4b3b1157 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -9,6 +9,7 @@ #include <stdio.h> #include <stdlib.h> #include <linux/err.h> +#include <linux/string.h> #include <linux/zalloc.h> #include "debug.h" #include "llvm-utils.h" diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h index bf3f3f4c4fe2..7878a0e3fa98 100644 --- a/tools/perf/util/llvm-utils.h +++ b/tools/perf/util/llvm-utils.h @@ -6,7 +6,7 @@ #ifndef __LLVM_UTILS_H #define __LLVM_UTILS_H -#include "debug.h" +#include <stdbool.h> struct llvm_param { /* Path of clang executable */ diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index b1dd29a9d915..397447066033 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -9,6 +9,7 @@ #include "compress.h" #include "util.h" #include "debug.h" +#include <string.h> #include <unistd.h> #define BUFSIZE 8192 diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 83b2fbbeeb90..b4749d3eed08 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -3,17 +3,26 @@ #include <errno.h> #include <inttypes.h> #include <regex.h> +#include <stdlib.h> #include "callchain.h" #include "debug.h" +#include "dso.h" +#include "env.h" #include "event.h" #include "evsel.h" #include "hist.h" #include "machine.h" #include "map.h" +#include "map_symbol.h" +#include "branch.h" +#include "mem-events.h" +#include "srcline.h" #include "symbol.h" #include "sort.h" #include "strlist.h" +#include "target.h" #include "thread.h" +#include "util.h" #include "vdso.h" #include <stdbool.h> #include <sys/types.h> @@ -27,6 +36,7 @@ #include <linux/ctype.h> #include <symbol/kallsyms.h> #include <linux/mman.h> +#include <linux/string.h> #include <linux/zalloc.h> static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); @@ -642,7 +652,7 @@ int machine__process_namespaces_event(struct machine *machine __maybe_unused, int machine__process_lost_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused) { - dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", + dump_printf(": id:%" PRI_lu64 ": lost:%" PRI_lu64 "\n", event->lost.id, event->lost.lost); return 0; } @@ -650,7 +660,7 @@ int machine__process_lost_event(struct machine *machine __maybe_unused, int machine__process_lost_samples_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample) { - dump_printf(": id:%" PRIu64 ": lost samples :%" PRIu64 "\n", + dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "\n", sample->id, event->lost_samples.lost); return 0; } @@ -710,20 +720,20 @@ static int machine__process_ksymbol_register(struct machine *machine, struct symbol *sym; struct map *map; - map = map_groups__find(&machine->kmaps, event->ksymbol_event.addr); + map = map_groups__find(&machine->kmaps, event->ksymbol.addr); if (!map) { - map = dso__new_map(event->ksymbol_event.name); + map = dso__new_map(event->ksymbol.name); if (!map) return -ENOMEM; - map->start = event->ksymbol_event.addr; - map->end = map->start + event->ksymbol_event.len; + map->start = event->ksymbol.addr; + map->end = map->start + event->ksymbol.len; map_groups__insert(&machine->kmaps, map); } sym = symbol__new(map->map_ip(map, map->start), - event->ksymbol_event.len, - 0, 0, event->ksymbol_event.name); + event->ksymbol.len, + 0, 0, event->ksymbol.name); if (!sym) return -ENOMEM; dso__insert_symbol(map->dso, sym); @@ -736,7 +746,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine, { struct map *map; - map = map_groups__find(&machine->kmaps, event->ksymbol_event.addr); + map = map_groups__find(&machine->kmaps, event->ksymbol.addr); if (map) map_groups__remove(&machine->kmaps, map); @@ -750,7 +760,7 @@ int machine__process_ksymbol(struct machine *machine __maybe_unused, if (dump_trace) perf_event__fprintf_ksymbol(event, stdout); - if (event->ksymbol_event.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) + if (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) return machine__process_ksymbol_unregister(machine, event, sample); return machine__process_ksymbol_register(machine, event, sample); @@ -1919,7 +1929,7 @@ int machine__process_event(struct machine *machine, union perf_event *event, case PERF_RECORD_KSYMBOL: ret = machine__process_ksymbol(machine, event, sample); break; case PERF_RECORD_BPF_EVENT: - ret = machine__process_bpf_event(machine, event, sample); break; + ret = machine__process_bpf(machine, event, sample); break; default: ret = -1; break; @@ -2288,7 +2298,7 @@ static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, static int thread__resolve_callchain_sample(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, @@ -2494,13 +2504,13 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) static int thread__resolve_callchain_unwind(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, int max_stack) { /* Can we do dwarf post unwind? */ - if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && - (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) + if (!((evsel->core.attr.sample_type & PERF_SAMPLE_REGS_USER) && + (evsel->core.attr.sample_type & PERF_SAMPLE_STACK_USER))) return 0; /* Bail out if nothing was captured. */ @@ -2514,7 +2524,7 @@ static int thread__resolve_callchain_unwind(struct thread *thread, int thread__resolve_callchain(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, @@ -2600,7 +2610,7 @@ int machines__for_each_thread(struct machines *machines, } int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, - struct target *target, struct thread_map *threads, + struct target *target, struct perf_thread_map *threads, perf_event__handler_t process, bool data_mmap, unsigned int nr_threads_synthesize) { @@ -2616,7 +2626,9 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too pid_t machine__get_current_tid(struct machine *machine, int cpu) { - if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid) + int nr_cpus = min(machine->env->nr_cpus_online, MAX_NR_CPUS); + + if (cpu < 0 || cpu >= nr_cpus || !machine->current_tid) return -1; return machine->current_tid[cpu]; @@ -2626,6 +2638,7 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, pid_t tid) { struct thread *thread; + int nr_cpus = min(machine->env->nr_cpus_online, MAX_NR_CPUS); if (cpu < 0) return -EINVAL; @@ -2633,14 +2646,14 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, if (!machine->current_tid) { int i; - machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t)); + machine->current_tid = calloc(nr_cpus, sizeof(pid_t)); if (!machine->current_tid) return -ENOMEM; - for (i = 0; i < MAX_NR_CPUS; i++) + for (i = 0; i < nr_cpus; i++) machine->current_tid[i] = -1; } - if (cpu >= MAX_NR_CPUS) { + if (cpu >= nr_cpus) { pr_err("Requested CPU %d too large. ", cpu); pr_err("Consider raising MAX_NR_CPUS\n"); return -EINVAL; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 7aa38da26427..ffd391a925a6 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -5,15 +5,17 @@ #include <sys/types.h> #include <linux/rbtree.h> #include "map_groups.h" -#include "dso.h" +#include "dsos.h" #include "event.h" #include "rwsem.h" struct addr_location; struct branch_stack; -struct perf_evsel; +struct dso; +struct evsel; struct perf_sample; struct symbol; +struct target; struct thread; union perf_event; @@ -175,7 +177,7 @@ struct callchain_cursor; int thread__resolve_callchain(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, @@ -251,12 +253,12 @@ int machines__for_each_thread(struct machines *machines, void *priv); int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, - struct target *target, struct thread_map *threads, + struct target *target, struct perf_thread_map *threads, perf_event__handler_t process, bool data_mmap, unsigned int nr_threads_synthesize); static inline int machine__synthesize_threads(struct machine *machine, struct target *target, - struct thread_map *threads, bool data_mmap, + struct perf_thread_map *threads, bool data_mmap, unsigned int nr_threads_synthesize) { return __machine__synthesize_threads(machine, NULL, target, threads, diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 668410b1d426..5b83ed1ebbd6 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -8,7 +8,9 @@ #include <stdio.h> #include <unistd.h> #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ +#include "dso.h" #include "map.h" +#include "map_symbol.h" #include "thread.h" #include "vdso.h" #include "build-id.h" @@ -20,6 +22,7 @@ #include "namespaces.h" #include "unwind.h" #include "srccode.h" +#include "ui/ui.h" static void __maps__insert(struct maps *maps, struct map *map); static void __maps__insert_name(struct maps *maps, struct map *map); @@ -636,7 +639,7 @@ bool map_groups__empty(struct map_groups *mg) struct map_groups *map_groups__new(struct machine *machine) { - struct map_groups *mg = malloc(sizeof(*mg)); + struct map_groups *mg = zalloc(sizeof(*mg)); if (mg != NULL) map_groups__init(mg, machine); @@ -647,6 +650,7 @@ struct map_groups *map_groups__new(struct machine *machine) void map_groups__delete(struct map_groups *mg) { map_groups__exit(mg); + unwind__finish_access(mg); free(mg); } @@ -887,7 +891,7 @@ int map_groups__clone(struct thread *thread, struct map_groups *parent) if (new == NULL) goto out_unlock; - err = unwind__prepare_access(thread, new, NULL); + err = unwind__prepare_access(mg, new, NULL); if (err) goto out_unlock; diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index dc93787c74f0..c3614195ddc7 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -16,7 +16,7 @@ struct ip_callchain; struct ref_reloc_sym; struct map_groups; struct machine; -struct perf_evsel; +struct evsel; struct map { union { diff --git a/tools/perf/util/map_groups.h b/tools/perf/util/map_groups.h index 5f25efa6d6bc..77252e14008f 100644 --- a/tools/perf/util/map_groups.h +++ b/tools/perf/util/map_groups.h @@ -31,6 +31,10 @@ struct map_groups { struct maps maps; struct machine *machine; refcount_t refcnt; +#ifdef HAVE_LIBUNWIND_SUPPORT + void *addr_space; + struct unwind_libunwind_ops *unwind_libunwind_ops; +#endif }; #define KMAP_NAME_LEN 256 diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 42c3e5a229d2..3d391583f2ae 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -8,10 +8,10 @@ #include <unistd.h> #include <api/fs/fs.h> #include <linux/kernel.h> +#include "map_symbol.h" #include "mem-events.h" #include "debug.h" #include "symbol.h" -#include "sort.h" unsigned int perf_mem_events__loads_ldlat = 30; diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h index a889ec2fa9f5..f1389bdae7bf 100644 --- a/tools/perf/util/mem-events.h +++ b/tools/perf/util/mem-events.h @@ -6,6 +6,8 @@ #include <stdint.h> #include <stdio.h> #include <linux/types.h> +#include <linux/refcount.h> +#include <linux/perf_event.h> #include "stat.h" struct perf_mem_event { @@ -16,6 +18,13 @@ struct perf_mem_event { const char *sysfs_name; }; +struct mem_info { + struct addr_map_symbol iaddr; + struct addr_map_symbol daddr; + union perf_mem_data_src data_src; + refcount_t refcnt; +}; + enum { PERF_MEM_EVENTS__LOAD, PERF_MEM_EVENTS__STORE, diff --git a/tools/perf/util/mem2node.c b/tools/perf/util/mem2node.c index cacc2fc4dcbd..797d86a1ab09 100644 --- a/tools/perf/util/mem2node.c +++ b/tools/perf/util/mem2node.c @@ -1,7 +1,10 @@ #include <errno.h> #include <inttypes.h> #include <linux/bitmap.h> +#include <linux/kernel.h> #include <linux/zalloc.h> +#include "debug.h" +#include "env.h" #include "mem2node.h" struct phys_entry { diff --git a/tools/perf/util/mem2node.h b/tools/perf/util/mem2node.h index 59c4752a2181..8dfa2b58d0cd 100644 --- a/tools/perf/util/mem2node.h +++ b/tools/perf/util/mem2node.h @@ -2,8 +2,9 @@ #define __MEM2NODE_H #include <linux/rbtree.h> -#include "env.h" +#include <linux/types.h> +struct perf_env; struct phys_entry; struct mem2node { diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 416a9015405e..a7c0424dbda3 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -6,22 +6,25 @@ /* Manage metrics and groups of metrics from JSON files */ #include "metricgroup.h" +#include "debug.h" #include "evlist.h" +#include "evsel.h" #include "strbuf.h" #include "pmu.h" #include "expr.h" #include "rblist.h" #include <string.h> -#include <stdbool.h> #include <errno.h> #include "pmu-events/pmu-events.h" #include "strlist.h" #include <assert.h> #include <linux/ctype.h> +#include <linux/string.h> #include <linux/zalloc.h> +#include <subcmd/parse-options.h> struct metric_event *metricgroup__lookup(struct rblist *metric_events, - struct perf_evsel *evsel, + struct evsel *evsel, bool create) { struct rb_node *nd; @@ -84,63 +87,68 @@ struct egroup { const char **ids; const char *metric_name; const char *metric_expr; + const char *metric_unit; }; -static bool record_evsel(int *ind, struct perf_evsel **start, - int idnum, - struct perf_evsel **metric_events, - struct perf_evsel *ev) +static struct evsel *find_evsel_group(struct evlist *perf_evlist, + const char **ids, + int idnum, + struct evsel **metric_events) { - metric_events[*ind] = ev; - if (*ind == 0) - *start = ev; - if (++*ind == idnum) { - metric_events[*ind] = NULL; - return true; - } - return false; -} - -static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist, - const char **ids, - int idnum, - struct perf_evsel **metric_events) -{ - struct perf_evsel *ev, *start = NULL; - int ind = 0; + struct evsel *ev; + int i = 0; + bool leader_found; evlist__for_each_entry (perf_evlist, ev) { - if (ev->collect_stat) - continue; - if (!strcmp(ev->name, ids[ind])) { - if (record_evsel(&ind, &start, idnum, - metric_events, ev)) - return start; + if (!strcmp(ev->name, ids[i])) { + if (!metric_events[i]) + metric_events[i] = ev; } else { - /* - * We saw some other event that is not - * in our list of events. Discard - * the whole match and start again. - */ - ind = 0; - start = NULL; - if (!strcmp(ev->name, ids[ind])) { - if (record_evsel(&ind, &start, idnum, - metric_events, ev)) - return start; + if (++i == idnum) { + /* Discard the whole match and start again */ + i = 0; + memset(metric_events, 0, + sizeof(struct evsel *) * idnum); + continue; + } + + if (!strcmp(ev->name, ids[i])) + metric_events[i] = ev; + else { + /* Discard the whole match and start again */ + i = 0; + memset(metric_events, 0, + sizeof(struct evsel *) * idnum); + continue; } } } - /* - * This can happen when an alias expands to multiple - * events, like for uncore events. - * We don't support this case for now. - */ - return NULL; + + if (i != idnum - 1) { + /* Not whole match */ + return NULL; + } + + metric_events[idnum] = NULL; + + for (i = 0; i < idnum; i++) { + leader_found = false; + evlist__for_each_entry(perf_evlist, ev) { + if (!leader_found && (ev == metric_events[i])) + leader_found = true; + + if (leader_found && + !strcmp(ev->name, metric_events[i]->name)) { + ev->metric_leader = metric_events[i]; + } + } + } + + return metric_events[0]; } static int metricgroup__setup_events(struct list_head *groups, - struct perf_evlist *perf_evlist, + struct evlist *perf_evlist, struct rblist *metric_events_list) { struct metric_event *me; @@ -148,10 +156,10 @@ static int metricgroup__setup_events(struct list_head *groups, int i = 0; int ret = 0; struct egroup *eg; - struct perf_evsel *evsel; + struct evsel *evsel; list_for_each_entry (eg, groups, nd) { - struct perf_evsel **metric_events; + struct evsel **metric_events; metric_events = calloc(sizeof(void *), eg->idnum + 1); if (!metric_events) { @@ -179,6 +187,7 @@ static int metricgroup__setup_events(struct list_head *groups, } expr->metric_expr = eg->metric_expr; expr->metric_name = eg->metric_name; + expr->metric_unit = eg->metric_unit; expr->metric_events = metric_events; list_add(&expr->nd, &me->head); } @@ -450,6 +459,7 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events, eg->idnum = idnum; eg->metric_name = pe->metric_name; eg->metric_expr = pe->metric_expr; + eg->metric_unit = pe->unit; list_add_tail(&eg->nd, group_list); ret = 0; } @@ -502,7 +512,7 @@ int metricgroup__parse_groups(const struct option *opt, struct rblist *metric_events) { struct parse_events_error parse_error; - struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value; + struct evlist *perf_evlist = *(struct evlist **)opt->value; struct strbuf extra_events; LIST_HEAD(group_list); int ret; diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 5c52097a5c63..475c7f912864 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -1,15 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only #ifndef METRICGROUP_H #define METRICGROUP_H 1 -#include "linux/list.h" -#include "rblist.h" -#include <subcmd/parse-options.h> -#include "evlist.h" -#include "strbuf.h" +#include <linux/list.h> +#include <linux/rbtree.h> +#include <stdbool.h> + +struct evsel; +struct option; +struct rblist; struct metric_event { struct rb_node nd; - struct perf_evsel *evsel; + struct evsel *evsel; struct list_head head; /* list of metric_expr */ }; @@ -17,11 +20,12 @@ struct metric_expr { struct list_head nd; const char *metric_expr; const char *metric_name; - struct perf_evsel **metric_events; + const char *metric_unit; + struct evsel **metric_events; }; struct metric_event *metricgroup__lookup(struct rblist *metric_events, - struct perf_evsel *evsel, + struct evsel *evsel, bool create); int metricgroup__parse_groups(const struct option *opt, const char *str, diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 9f0b6391af33..33c5b5495482 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -10,12 +10,16 @@ #include <inttypes.h> #include <asm/bug.h> #include <linux/zalloc.h> +#include <stdlib.h> +#include <string.h> #ifdef HAVE_LIBNUMA_SUPPORT #include <numaif.h> #endif +#include "cpumap.h" #include "debug.h" #include "event.h" #include "mmap.h" +#include "../perf.h" #include "util.h" /* page_size */ size_t perf_mmap__mmap_len(struct perf_mmap *map) @@ -150,7 +154,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u } void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int idx __maybe_unused, bool per_cpu __maybe_unused) { @@ -325,13 +329,13 @@ void perf_mmap__munmap(struct perf_mmap *map) static void build_node_mask(int node, cpu_set_t *mask) { int c, cpu, nr_cpus; - const struct cpu_map *cpu_map = NULL; + const struct perf_cpu_map *cpu_map = NULL; cpu_map = cpu_map__online(); if (!cpu_map) return; - nr_cpus = cpu_map__nr(cpu_map); + nr_cpus = perf_cpu_map__nr(cpu_map); for (c = 0; c < nr_cpus; c++) { cpu = cpu_map->map[c]; /* map c index to online cpu index */ if (cpu__get_node(cpu) == node) diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index 274ce389cd84..3857a49e8f96 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -6,6 +6,7 @@ #include <linux/types.h> #include <linux/ring_buffer.h> #include <stdbool.h> +#include <pthread.h> // for cpu_set_t #ifdef HAVE_AIO_SUPPORT #include <aio.h> #endif diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index 46d3a7754897..99be15dd2b6b 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c @@ -19,7 +19,7 @@ #include <asm/bug.h> #include <linux/zalloc.h> -struct namespaces *namespaces__new(struct namespaces_event *event) +struct namespaces *namespaces__new(struct perf_record_namespaces *event) { struct namespaces *namespaces; u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) * diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h index 004430c0de93..40edef56cb52 100644 --- a/tools/perf/util/namespaces.h +++ b/tools/perf/util/namespaces.h @@ -17,7 +17,7 @@ int setns(int fd, int nstype); #endif -struct namespaces_event; +struct perf_record_namespaces; struct namespaces { struct list_head list; @@ -25,7 +25,7 @@ struct namespaces { struct perf_ns_link_info link_info[]; }; -struct namespaces *namespaces__new(struct namespaces_event *event); +struct namespaces *namespaces__new(struct perf_record_namespaces *event); void namespaces__free(struct namespaces *namespaces); struct nsinfo { diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index bb5f34b7ab44..359db2b1fcef 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -8,6 +8,7 @@ #include "session.h" #include "asm/bug.h" #include "debug.h" +#include "ui/progress.h" #define pr_N(n, fmt, ...) \ eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__) diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c index 726e8d9e8c54..bb4aa88c50a8 100644 --- a/tools/perf/util/parse-branch-options.c +++ b/tools/perf/util/parse-branch-options.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" #include "util/debug.h" +#include "util/event.h" #include <subcmd/parse-options.h> #include "util/parse-branch-options.h" #include <stdlib.h> +#include <string.h> #define BRANCH_OPT(n, m) \ { .name = n, .mode = (m) } @@ -30,6 +31,7 @@ static const struct branch_mode branch_modes[] = { BRANCH_OPT("ind_jmp", PERF_SAMPLE_BRANCH_IND_JUMP), BRANCH_OPT("call", PERF_SAMPLE_BRANCH_CALL), BRANCH_OPT("save_type", PERF_SAMPLE_BRANCH_TYPE_SAVE), + BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK), BRANCH_END }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 371ff3aee769..5ec21d21113c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -10,20 +10,21 @@ #include <fcntl.h> #include <sys/param.h> #include "term.h" -#include "../perf.h" +#include "build-id.h" #include "evlist.h" #include "evsel.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "parse-events.h" #include <subcmd/exec-cmd.h> #include "string2.h" #include "strlist.h" #include "symbol.h" -#include "cache.h" #include "header.h" #include "bpf-loader.h" #include "debug.h" #include <api/fs/tracing_path.h> +#include <perf/cpumap.h> #include "parse-events-bison.h" #define YY_EXTRA_TYPE int #include "parse-events-flex.h" @@ -314,16 +315,16 @@ static char *get_config_name(struct list_head *head_terms) return NULL; } -static struct perf_evsel * +static struct evsel * __add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, char *name, struct perf_pmu *pmu, struct list_head *config_terms, bool auto_merge_stats, const char *cpu_list) { - struct perf_evsel *evsel; - struct cpu_map *cpus = pmu ? pmu->cpus : - cpu_list ? cpu_map__new(cpu_list) : NULL; + struct evsel *evsel; + struct perf_cpu_map *cpus = pmu ? pmu->cpus : + cpu_list ? perf_cpu_map__new(cpu_list) : NULL; event_attr_init(attr); @@ -332,8 +333,8 @@ __add_event(struct list_head *list, int *idx, return NULL; (*idx)++; - evsel->cpus = cpu_map__get(cpus); - evsel->own_cpus = cpu_map__get(cpus); + evsel->core.cpus = perf_cpu_map__get(cpus); + evsel->core.own_cpus = perf_cpu_map__get(cpus); evsel->system_wide = pmu ? pmu->is_uncore : false; evsel->auto_merge_stats = auto_merge_stats; @@ -343,7 +344,7 @@ __add_event(struct list_head *list, int *idx, if (config_terms) list_splice(config_terms, &evsel->config_terms); - list_add_tail(&evsel->node, list); + list_add_tail(&evsel->core.node, list); return evsel; } @@ -357,7 +358,7 @@ static int add_event(struct list_head *list, int *idx, static int add_event_tool(struct list_head *list, int *idx, enum perf_tool_event tool_event) { - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_DUMMY, @@ -510,7 +511,7 @@ static int add_tracepoint(struct list_head *list, int *idx, struct parse_events_error *err, struct list_head *head_config) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); if (IS_ERR(evsel)) { @@ -526,7 +527,7 @@ static int add_tracepoint(struct list_head *list, int *idx, list_splice(&config_terms, &evsel->config_terms); } - list_add_tail(&evsel->node, list); + list_add_tail(&evsel->core.node, list); return 0; } @@ -630,15 +631,24 @@ struct __add_bpf_event_param { struct list_head *head_config; }; -static int add_bpf_event(const char *group, const char *event, int fd, +static int add_bpf_event(const char *group, const char *event, int fd, struct bpf_object *obj, void *_param) { LIST_HEAD(new_evsels); struct __add_bpf_event_param *param = _param; struct parse_events_state *parse_state = param->parse_state; struct list_head *list = param->list; - struct perf_evsel *pos; + struct evsel *pos; int err; + /* + * Check if we should add the event, i.e. if it is a TP but starts with a '!', + * then don't add the tracepoint, this will be used for something else, like + * adding to a BPF_MAP_TYPE_PROG_ARRAY. + * + * See tools/perf/examples/bpf/augmented_raw_syscalls.c + */ + if (group[0] == '!') + return 0; pr_debug("add bpf event %s:%s and attach bpf program %d\n", group, event, fd); @@ -647,22 +657,23 @@ static int add_bpf_event(const char *group, const char *event, int fd, event, parse_state->error, param->head_config); if (err) { - struct perf_evsel *evsel, *tmp; + struct evsel *evsel, *tmp; pr_debug("Failed to add BPF event %s:%s\n", group, event); - list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { - list_del_init(&evsel->node); - perf_evsel__delete(evsel); + list_for_each_entry_safe(evsel, tmp, &new_evsels, core.node) { + list_del_init(&evsel->core.node); + evsel__delete(evsel); } return err; } pr_debug("adding %s:%s\n", group, event); - list_for_each_entry(pos, &new_evsels, node) { + list_for_each_entry(pos, &new_evsels, core.node) { pr_debug("adding %s:%s to %p\n", group, event, pos); pos->bpf_fd = fd; + pos->bpf_obj = obj; } list_splice(&new_evsels, list); return 0; @@ -952,6 +963,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", [PARSE_EVENTS__TERM_TYPE_PERCORE] = "percore", + [PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT] = "aux-output", }; static bool config_term_shrinked; @@ -1072,6 +1084,9 @@ do { \ return -EINVAL; } break; + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: + CHECK_TYPE_VAL(NUM); + break; default: err->str = strdup("unknown term"); err->idx = term->err_term; @@ -1122,6 +1137,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr, case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: case PARSE_EVENTS__TERM_TYPE_OVERWRITE: case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: return config_term_common(attr, term, err); default: if (err) { @@ -1214,6 +1230,9 @@ do { \ ADD_CONFIG_TERM(PERCORE, percore, term->val.num ? true : false); break; + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: + ADD_CONFIG_TERM(AUX_OUTPUT, aux_output, term->val.num ? 1 : 0); + break; default: break; } @@ -1296,7 +1315,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, struct perf_event_attr attr; struct perf_pmu_info info; struct perf_pmu *pmu; - struct perf_evsel *evsel; + struct evsel *evsel; struct parse_events_error *err = parse_state->error; bool use_uncore_alias; LIST_HEAD(config_terms); @@ -1443,13 +1462,13 @@ static int parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, struct parse_events_state *parse_state) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; uintptr_t *leaders; bool is_leader = true; int i, nr_pmu = 0, total_members, ret = 0; - leader = list_first_entry(list, struct perf_evsel, node); - evsel = list_last_entry(list, struct perf_evsel, node); + leader = list_first_entry(list, struct evsel, core.node); + evsel = list_last_entry(list, struct evsel, core.node); total_members = evsel->idx - leader->idx + 1; leaders = calloc(total_members, sizeof(uintptr_t)); @@ -1511,13 +1530,13 @@ parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, __evlist__for_each_entry(list, evsel) { if (i >= nr_pmu) i = 0; - evsel->leader = (struct perf_evsel *) leaders[i++]; + evsel->leader = (struct evsel *) leaders[i++]; } /* The number of members and group name are same for each group */ for (i = 0; i < nr_pmu; i++) { - evsel = (struct perf_evsel *) leaders[i]; - evsel->nr_members = total_members / nr_pmu; + evsel = (struct evsel *) leaders[i]; + evsel->core.nr_members = total_members / nr_pmu; evsel->group_name = name ? strdup(name) : NULL; } @@ -1534,7 +1553,7 @@ out: void parse_events__set_leader(char *name, struct list_head *list, struct parse_events_state *parse_state) { - struct perf_evsel *leader; + struct evsel *leader; if (list_empty(list)) { WARN_ONCE(true, "WARNING: failed to set leader: empty list"); @@ -1545,7 +1564,7 @@ void parse_events__set_leader(char *name, struct list_head *list, return; __perf_evlist__set_leader(list); - leader = list_entry(list->next, struct perf_evsel, node); + leader = list_entry(list->next, struct evsel, core.node); leader->group_name = name ? strdup(name) : NULL; } @@ -1578,18 +1597,18 @@ struct event_modifier { }; static int get_event_modifier(struct event_modifier *mod, char *str, - struct perf_evsel *evsel) -{ - int eu = evsel ? evsel->attr.exclude_user : 0; - int ek = evsel ? evsel->attr.exclude_kernel : 0; - int eh = evsel ? evsel->attr.exclude_hv : 0; - int eH = evsel ? evsel->attr.exclude_host : 0; - int eG = evsel ? evsel->attr.exclude_guest : 0; - int eI = evsel ? evsel->attr.exclude_idle : 0; - int precise = evsel ? evsel->attr.precise_ip : 0; + struct evsel *evsel) +{ + int eu = evsel ? evsel->core.attr.exclude_user : 0; + int ek = evsel ? evsel->core.attr.exclude_kernel : 0; + int eh = evsel ? evsel->core.attr.exclude_hv : 0; + int eH = evsel ? evsel->core.attr.exclude_host : 0; + int eG = evsel ? evsel->core.attr.exclude_guest : 0; + int eI = evsel ? evsel->core.attr.exclude_idle : 0; + int precise = evsel ? evsel->core.attr.precise_ip : 0; int precise_max = 0; int sample_read = 0; - int pinned = evsel ? evsel->attr.pinned : 0; + int pinned = evsel ? evsel->core.attr.pinned : 0; int exclude = eu | ek | eh; int exclude_GH = evsel ? evsel->exclude_GH : 0; @@ -1691,7 +1710,7 @@ static int check_modifier(char *str) int parse_events__modifier_event(struct list_head *list, char *str, bool add) { - struct perf_evsel *evsel; + struct evsel *evsel; struct event_modifier mod; if (str == NULL) @@ -1707,20 +1726,20 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) if (add && get_event_modifier(&mod, str, evsel)) return -EINVAL; - evsel->attr.exclude_user = mod.eu; - evsel->attr.exclude_kernel = mod.ek; - evsel->attr.exclude_hv = mod.eh; - evsel->attr.precise_ip = mod.precise; - evsel->attr.exclude_host = mod.eH; - evsel->attr.exclude_guest = mod.eG; - evsel->attr.exclude_idle = mod.eI; + evsel->core.attr.exclude_user = mod.eu; + evsel->core.attr.exclude_kernel = mod.ek; + evsel->core.attr.exclude_hv = mod.eh; + evsel->core.attr.precise_ip = mod.precise; + evsel->core.attr.exclude_host = mod.eH; + evsel->core.attr.exclude_guest = mod.eG; + evsel->core.attr.exclude_idle = mod.eI; evsel->exclude_GH = mod.exclude_GH; evsel->sample_read = mod.sample_read; evsel->precise_max = mod.precise_max; evsel->weak_group = mod.weak; if (perf_evsel__is_group_leader(evsel)) - evsel->attr.pinned = mod.pinned; + evsel->core.attr.pinned = mod.pinned; } return 0; @@ -1728,7 +1747,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) int parse_events_name(struct list_head *list, char *name) { - struct perf_evsel *evsel; + struct evsel *evsel; __evlist__for_each_entry(list, evsel) { if (!evsel->name) @@ -1894,12 +1913,12 @@ int parse_events_terms(struct list_head *terms, const char *str) return ret; } -int parse_events(struct perf_evlist *evlist, const char *str, +int parse_events(struct evlist *evlist, const char *str, struct parse_events_error *err) { struct parse_events_state parse_state = { .list = LIST_HEAD_INIT(parse_state.list), - .idx = evlist->nr_entries, + .idx = evlist->core.nr_entries, .error = err, .evlist = evlist, }; @@ -1908,7 +1927,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS); perf_pmu__parse_cleanup(); if (!ret) { - struct perf_evsel *last; + struct evsel *last; if (list_empty(&parse_state.list)) { WARN_ONCE(true, "WARNING: event parser found nothing\n"); @@ -1925,7 +1944,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, /* * There are 2 users - builtin-record and builtin-test objects. - * Both call perf_evlist__delete in case of error, so we dont + * Both call evlist__delete in case of error, so we dont * need to bother. */ return ret; @@ -2003,7 +2022,7 @@ void parse_events_print_error(struct parse_events_error *err, int parse_events_option(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; + struct evlist *evlist = *(struct evlist **)opt->value; struct parse_events_error err = { .idx = 0, }; int ret = parse_events(evlist, str, &err); @@ -2016,12 +2035,12 @@ int parse_events_option(const struct option *opt, const char *str, } static int -foreach_evsel_in_last_glob(struct perf_evlist *evlist, - int (*func)(struct perf_evsel *evsel, +foreach_evsel_in_last_glob(struct evlist *evlist, + int (*func)(struct evsel *evsel, const void *arg), const void *arg) { - struct perf_evsel *last = NULL; + struct evsel *last = NULL; int err; /* @@ -2030,7 +2049,7 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist, * * So no need to WARN here, let *func do this. */ - if (evlist->nr_entries > 0) + if (evlist->core.nr_entries > 0) last = perf_evlist__last(evlist); do { @@ -2040,15 +2059,15 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist, if (!last) return 0; - if (last->node.prev == &evlist->entries) + if (last->core.node.prev == &evlist->core.entries) return 0; - last = list_entry(last->node.prev, struct perf_evsel, node); + last = list_entry(last->core.node.prev, struct evsel, core.node); } while (!last->cmdline_group_boundary); return 0; } -static int set_filter(struct perf_evsel *evsel, const void *arg) +static int set_filter(struct evsel *evsel, const void *arg) { const char *str = arg; bool found = false; @@ -2061,7 +2080,7 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) return -1; } - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { if (perf_evsel__append_tp_filter(evsel, str) < 0) { fprintf(stderr, "not enough memory to hold filter string\n"); @@ -2072,7 +2091,7 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) } while ((pmu = perf_pmu__scan(pmu)) != NULL) - if (pmu->type == evsel->attr.type) { + if (pmu->type == evsel->core.attr.type) { found = true; break; } @@ -2099,18 +2118,18 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) int parse_filter(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; + struct evlist *evlist = *(struct evlist **)opt->value; return foreach_evsel_in_last_glob(evlist, set_filter, (const void *)str); } -static int add_exclude_perf_filter(struct perf_evsel *evsel, +static int add_exclude_perf_filter(struct evsel *evsel, const void *arg __maybe_unused) { char new_filter[64]; - if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel == NULL || evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { fprintf(stderr, "--exclude-perf option should follow a -e tracepoint option\n"); return -1; @@ -2131,7 +2150,7 @@ int exclude_perf(const struct option *opt, const char *arg __maybe_unused, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; + struct evlist *evlist = *(struct evlist **)opt->value; return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, NULL); @@ -2297,20 +2316,20 @@ static bool is_event_supported(u8 type, unsigned config) { bool ret = true; int open_return; - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_event_attr attr = { .type = type, .config = config, .disabled = 1, }; - struct thread_map *tmap = thread_map__new_by_tid(0); + struct perf_thread_map *tmap = thread_map__new_by_tid(0); if (tmap == NULL) return false; - evsel = perf_evsel__new(&attr); + evsel = evsel__new(&attr); if (evsel) { - open_return = perf_evsel__open(evsel, NULL, tmap); + open_return = evsel__open(evsel, NULL, tmap); ret = open_return >= 0; if (open_return == -EACCES) { @@ -2321,13 +2340,13 @@ static bool is_event_supported(u8 type, unsigned config) * by default as some ARM machines do not support it. * */ - evsel->attr.exclude_kernel = 1; - ret = perf_evsel__open(evsel, NULL, tmap) >= 0; + evsel->core.attr.exclude_kernel = 1; + ret = evsel__open(evsel, NULL, tmap) >= 0; } - perf_evsel__delete(evsel); + evsel__delete(evsel); } - thread_map__put(tmap); + perf_thread_map__put(tmap); return ret; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index f7139e1a2fd3..616ca1eda0eb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -12,8 +12,8 @@ #include <string.h> struct list_head; -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct parse_events_error; struct option; @@ -31,7 +31,7 @@ bool have_tracepoints(struct list_head *evlist); const char *event_type(int type); int parse_events_option(const struct option *opt, const char *str, int unset); -int parse_events(struct perf_evlist *evlist, const char *str, +int parse_events(struct evlist *evlist, const char *str, struct parse_events_error *error); int parse_events_terms(struct list_head *terms, const char *str); int parse_filter(const struct option *opt, const char *str, int unset); @@ -76,6 +76,7 @@ enum { PARSE_EVENTS__TERM_TYPE_OVERWRITE, PARSE_EVENTS__TERM_TYPE_DRV_CFG, PARSE_EVENTS__TERM_TYPE_PERCORE, + PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT, __PARSE_EVENTS__TERM_TYPE_NR, }; @@ -119,7 +120,7 @@ struct parse_events_state { int idx; int nr_groups; struct parse_events_error *error; - struct perf_evlist *evlist; + struct evlist *evlist; struct list_head *terms; }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index ca6098874fe2..7469497cd28e 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -284,6 +284,7 @@ no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } +aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index ca56ba2dd3da..caed0336429f 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -11,11 +11,12 @@ * * which is what it's designed for. */ -#include "cache.h" #include "path.h" +#include "cache.h" #include <linux/kernel.h> #include <limits.h> #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> diff --git a/tools/perf/util/path.h b/tools/perf/util/path.h index f014f905df50..083429b7efa3 100644 --- a/tools/perf/util/path.h +++ b/tools/perf/util/path.h @@ -2,6 +2,9 @@ #ifndef _PERF_PATH_H #define _PERF_PATH_H +#include <stddef.h> +#include <stdbool.h> + struct dirent; int path__join(char *bf, size_t size, const char *path1, const char *path2); diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c index 4f3aa8d99ef4..e635c594f773 100644 --- a/tools/perf/util/perf-hooks.c +++ b/tools/perf/util/perf-hooks.c @@ -8,6 +8,7 @@ #include <errno.h> #include <stdlib.h> +#include <string.h> #include <setjmp.h> #include <linux/err.h> #include <linux/kernel.h> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index f32b710347db..fb597fa94234 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -3,6 +3,7 @@ #include <linux/compiler.h> #include <linux/string.h> #include <linux/zalloc.h> +#include <subcmd/pager.h> #include <sys/types.h> #include <errno.h> #include <fcntl.h> @@ -15,13 +16,15 @@ #include <api/fs/fs.h> #include <locale.h> #include <regex.h> +#include <perf/cpumap.h> +#include "debug.h" #include "pmu.h" #include "parse-events.h" #include "cpumap.h" #include "header.h" #include "pmu-events/pmu-events.h" -#include "cache.h" #include "string2.h" +#include "strbuf.h" struct perf_pmu_format { char *name; @@ -99,7 +102,7 @@ static int pmu_format(const char *name, struct list_head *format) return 0; } -static int convert_scale(const char *scale, char **end, double *sval) +int perf_pmu__convert_scale(const char *scale, char **end, double *sval) { char *lc; int ret = 0; @@ -162,7 +165,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * else scale[sret] = '\0'; - ret = convert_scale(scale, NULL, &alias->scale); + ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); error: close(fd); return ret; @@ -370,7 +373,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, desc ? strdup(desc) : NULL; alias->topic = topic ? strdup(topic) : NULL; if (unit) { - if (convert_scale(unit, &unit, &alias->scale) < 0) + if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) return -1; snprintf(alias->unit, sizeof(alias->unit), "%s", unit); } @@ -572,16 +575,16 @@ static void pmu_read_sysfs(void) closedir(dir); } -static struct cpu_map *__pmu_cpumask(const char *path) +static struct perf_cpu_map *__pmu_cpumask(const char *path) { FILE *file; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; file = fopen(path, "r"); if (!file) return NULL; - cpus = cpu_map__read(file); + cpus = perf_cpu_map__read(file); fclose(file); return cpus; } @@ -593,10 +596,10 @@ static struct cpu_map *__pmu_cpumask(const char *path) #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" -static struct cpu_map *pmu_cpumask(const char *name) +static struct perf_cpu_map *pmu_cpumask(const char *name) { char path[PATH_MAX]; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; const char *sysfs = sysfs__mountpoint(); const char *templates[] = { CPUS_TEMPLATE_UNCORE, @@ -621,12 +624,12 @@ static struct cpu_map *pmu_cpumask(const char *name) static bool pmu_is_uncore(const char *name) { char path[PATH_MAX]; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; const char *sysfs = sysfs__mountpoint(); snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); cpus = __pmu_cpumask(path); - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return !!cpus; } diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index bd9ec2704a57..f36ade6df76d 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -28,7 +28,7 @@ struct perf_pmu { bool is_uncore; int max_precise; struct perf_event_attr *default_config; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; struct list_head format; /* HEAD struct perf_pmu_format -> list */ struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ struct list_head list; /* ELEM */ @@ -96,4 +96,6 @@ struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu); struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu); +int perf_pmu__convert_scale(const char *scale, char **end, double *sval); + #endif /* __PMU_H */ diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8394d48f8b32..b8e0967c5c21 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -19,17 +19,17 @@ #include <limits.h> #include <elf.h> +#include "build-id.h" #include "event.h" #include "namespaces.h" #include "strlist.h" #include "strfilter.h" #include "debug.h" -#include "cache.h" +#include "dso.h" #include "color.h" #include "map.h" #include "map_groups.h" #include "symbol.h" -#include "thread.h" #include <api/fs/fs.h> #include "trace-event.h" /* For __maybe_unused */ #include "probe-event.h" @@ -37,7 +37,9 @@ #include "probe-file.h" #include "session.h" #include "string2.h" +#include "strbuf.h" +#include <subcmd/pager.h> #include <linux/ctype.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 5b4d49382932..d13db55a2feb 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -16,10 +16,10 @@ #include "strlist.h" #include "strfilter.h" #include "debug.h" -#include "cache.h" +#include "dso.h" #include "color.h" #include "symbol.h" -#include "thread.h" +#include "strbuf.h" #include <api/fs/tracing_path.h> #include "probe-event.h" #include "probe-file.h" diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 025fc4491993..505905fc21c5 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -24,6 +24,7 @@ #include "dso.h" #include "debug.h" #include "intlist.h" +#include "strbuf.h" #include "strlist.h" #include "symbol.h" #include "probe-finder.h" diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c index 28de8a4c2ce8..80ff41fc45be 100644 --- a/tools/perf/util/pstack.c +++ b/tools/perf/util/pstack.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <stdlib.h> +#include <string.h> struct pstack { unsigned short top; diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index ceb8afdf9a89..c6dd478956f1 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -7,6 +7,7 @@ util/python.c ../lib/ctype.c +util/cap.c util/evlist.c util/evsel.c util/cpumap.c @@ -18,10 +19,8 @@ util/namespaces.c ../lib/hweight.c ../lib/string.c ../lib/vsprintf.c -../lib/zalloc.c util/thread_map.c util/util.c -util/xyarray.c util/cgroup.c util/parse-branch-options.c util/rblist.c diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 1e5b6718dcea..07ca4535e6f7 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -4,6 +4,9 @@ #include <inttypes.h> #include <poll.h> #include <linux/err.h> +#include <perf/cpumap.h> +#include <traceevent/event-parse.h> +#include "debug.h" #include "evlist.h" #include "callchain.h" #include "evsel.h" @@ -11,8 +14,10 @@ #include "cpumap.h" #include "print_binary.h" #include "thread_map.h" +#include "trace-event.h" #include "mmap.h" #include "util.h" +#include "../perf-sys.h" #if PY_MAJOR_VERSION < 3 #define _PyUnicode_FromString(arg) \ @@ -93,7 +98,7 @@ PyMODINIT_FUNC PyInit_perf(void); struct pyrf_event { PyObject_HEAD - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_sample sample; union perf_event event; }; @@ -115,12 +120,12 @@ static PyMemberDef pyrf_mmap_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), member_def(perf_event_header, misc, T_UINT, "event misc"), - member_def(mmap_event, pid, T_UINT, "event pid"), - member_def(mmap_event, tid, T_UINT, "event tid"), - member_def(mmap_event, start, T_ULONGLONG, "start of the map"), - member_def(mmap_event, len, T_ULONGLONG, "map length"), - member_def(mmap_event, pgoff, T_ULONGLONG, "page offset"), - member_def(mmap_event, filename, T_STRING_INPLACE, "backing store"), + member_def(perf_record_mmap, pid, T_UINT, "event pid"), + member_def(perf_record_mmap, tid, T_UINT, "event tid"), + member_def(perf_record_mmap, start, T_ULONGLONG, "start of the map"), + member_def(perf_record_mmap, len, T_ULONGLONG, "map length"), + member_def(perf_record_mmap, pgoff, T_ULONGLONG, "page offset"), + member_def(perf_record_mmap, filename, T_STRING_INPLACE, "backing store"), { .name = NULL, }, }; @@ -129,8 +134,8 @@ static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent) PyObject *ret; char *s; - if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRIx64 ", " - "length: %#" PRIx64 ", offset: %#" PRIx64 ", " + if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRI_lx64 ", " + "length: %#" PRI_lx64 ", offset: %#" PRI_lx64 ", " "filename: %s }", pevent->event.mmap.pid, pevent->event.mmap.tid, pevent->event.mmap.start, pevent->event.mmap.len, @@ -158,18 +163,18 @@ static char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event obje static PyMemberDef pyrf_task_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(fork_event, pid, T_UINT, "event pid"), - member_def(fork_event, ppid, T_UINT, "event ppid"), - member_def(fork_event, tid, T_UINT, "event tid"), - member_def(fork_event, ptid, T_UINT, "event ptid"), - member_def(fork_event, time, T_ULONGLONG, "timestamp"), + member_def(perf_record_fork, pid, T_UINT, "event pid"), + member_def(perf_record_fork, ppid, T_UINT, "event ppid"), + member_def(perf_record_fork, tid, T_UINT, "event tid"), + member_def(perf_record_fork, ptid, T_UINT, "event ptid"), + member_def(perf_record_fork, time, T_ULONGLONG, "timestamp"), { .name = NULL, }, }; static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent) { return _PyUnicode_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, " - "ptid: %u, time: %" PRIu64 "}", + "ptid: %u, time: %" PRI_lu64 "}", pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit", pevent->event.fork.pid, pevent->event.fork.ppid, @@ -193,9 +198,9 @@ static char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object."); static PyMemberDef pyrf_comm_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(comm_event, pid, T_UINT, "event pid"), - member_def(comm_event, tid, T_UINT, "event tid"), - member_def(comm_event, comm, T_STRING_INPLACE, "process name"), + member_def(perf_record_comm, pid, T_UINT, "event pid"), + member_def(perf_record_comm, tid, T_UINT, "event tid"), + member_def(perf_record_comm, comm, T_STRING_INPLACE, "process name"), { .name = NULL, }, }; @@ -222,18 +227,18 @@ static char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object." static PyMemberDef pyrf_throttle_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(throttle_event, time, T_ULONGLONG, "timestamp"), - member_def(throttle_event, id, T_ULONGLONG, "event id"), - member_def(throttle_event, stream_id, T_ULONGLONG, "event stream id"), + member_def(perf_record_throttle, time, T_ULONGLONG, "timestamp"), + member_def(perf_record_throttle, id, T_ULONGLONG, "event id"), + member_def(perf_record_throttle, stream_id, T_ULONGLONG, "event stream id"), { .name = NULL, }, }; static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent) { - struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1); + struct perf_record_throttle *te = (struct perf_record_throttle *)(&pevent->event.header + 1); - return _PyUnicode_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64 - ", stream_id: %" PRIu64 " }", + return _PyUnicode_FromFormat("{ type: %sthrottle, time: %" PRI_lu64 ", id: %" PRI_lu64 + ", stream_id: %" PRI_lu64 " }", pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un", te->time, te->id, te->stream_id); } @@ -252,8 +257,8 @@ static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object."); static PyMemberDef pyrf_lost_event__members[] = { sample_members - member_def(lost_event, id, T_ULONGLONG, "event id"), - member_def(lost_event, lost, T_ULONGLONG, "number of lost events"), + member_def(perf_record_lost, id, T_ULONGLONG, "event id"), + member_def(perf_record_lost, lost, T_ULONGLONG, "number of lost events"), { .name = NULL, }, }; @@ -262,8 +267,8 @@ static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent) PyObject *ret; char *s; - if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", " - "lost: %#" PRIx64 " }", + if (asprintf(&s, "{ type: lost, id: %#" PRI_lx64 ", " + "lost: %#" PRI_lx64 " }", pevent->event.lost.id, pevent->event.lost.lost) < 0) { ret = PyErr_NoMemory(); } else { @@ -287,8 +292,8 @@ static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); static PyMemberDef pyrf_read_event__members[] = { sample_members - member_def(read_event, pid, T_UINT, "event pid"), - member_def(read_event, tid, T_UINT, "event tid"), + member_def(perf_record_read, pid, T_UINT, "event pid"), + member_def(perf_record_read, tid, T_UINT, "event tid"), { .name = NULL, }, }; @@ -337,7 +342,7 @@ static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) static bool is_tracepoint(struct pyrf_event *pevent) { - return pevent->evsel->attr.type == PERF_TYPE_TRACEPOINT; + return pevent->evsel->core.attr.type == PERF_TYPE_TRACEPOINT; } static PyObject* @@ -383,13 +388,13 @@ static PyObject* get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) { const char *str = _PyUnicode_AsString(PyObject_Str(attr_name)); - struct perf_evsel *evsel = pevent->evsel; + struct evsel *evsel = pevent->evsel; struct tep_format_field *field; if (!evsel->tp_format) { struct tep_event *tp_format; - tp_format = trace_event__tp_format_id(evsel->attr.config); + tp_format = trace_event__tp_format_id(evsel->core.attr.config); if (!tp_format) return NULL; @@ -430,8 +435,8 @@ static char pyrf_context_switch_event__doc[] = PyDoc_STR("perf context_switch ev static PyMemberDef pyrf_context_switch_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(context_switch_event, next_prev_pid, T_UINT, "next/prev pid"), - member_def(context_switch_event, next_prev_tid, T_UINT, "next/prev tid"), + member_def(perf_record_switch, next_prev_pid, T_UINT, "next/prev pid"), + member_def(perf_record_switch, next_prev_tid, T_UINT, "next/prev tid"), { .name = NULL, }, }; @@ -536,7 +541,7 @@ static PyObject *pyrf_event__new(union perf_event *event) struct pyrf_cpu_map { PyObject_HEAD - struct cpu_map *cpus; + struct perf_cpu_map *cpus; }; static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, @@ -549,7 +554,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, kwlist, &cpustr)) return -1; - pcpus->cpus = cpu_map__new(cpustr); + pcpus->cpus = perf_cpu_map__new(cpustr); if (pcpus->cpus == NULL) return -1; return 0; @@ -557,7 +562,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) { - cpu_map__put(pcpus->cpus); + perf_cpu_map__put(pcpus->cpus); Py_TYPE(pcpus)->tp_free((PyObject*)pcpus); } @@ -605,7 +610,7 @@ static int pyrf_cpu_map__setup_types(void) struct pyrf_thread_map { PyObject_HEAD - struct thread_map *threads; + struct perf_thread_map *threads; }; static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, @@ -626,7 +631,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) { - thread_map__put(pthreads->threads); + perf_thread_map__put(pthreads->threads); Py_TYPE(pthreads)->tp_free((PyObject*)pthreads); } @@ -674,7 +679,7 @@ static int pyrf_thread_map__setup_types(void) struct pyrf_evsel { PyObject_HEAD - struct perf_evsel evsel; + struct evsel evsel; }; static int pyrf_evsel__init(struct pyrf_evsel *pevsel, @@ -782,7 +787,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, attr.sample_id_all = sample_id_all; attr.size = sizeof(attr); - perf_evsel__init(&pevsel->evsel, &attr, idx); + evsel__init(&pevsel->evsel, &attr, idx); return 0; } @@ -795,9 +800,9 @@ static void pyrf_evsel__delete(struct pyrf_evsel *pevsel) static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, PyObject *args, PyObject *kwargs) { - struct perf_evsel *evsel = &pevsel->evsel; - struct cpu_map *cpus = NULL; - struct thread_map *threads = NULL; + struct evsel *evsel = &pevsel->evsel; + struct perf_cpu_map *cpus = NULL; + struct perf_thread_map *threads = NULL; PyObject *pcpus = NULL, *pthreads = NULL; int group = 0, inherit = 0; static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL }; @@ -812,12 +817,12 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, if (pcpus != NULL) cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - evsel->attr.inherit = inherit; + evsel->core.attr.inherit = inherit; /* * This will group just the fds for this single evsel, to group * multiple events, use evlist.open(). */ - if (perf_evsel__open(evsel, cpus, threads) < 0) { + if (evsel__open(evsel, cpus, threads) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -858,22 +863,22 @@ static int pyrf_evsel__setup_types(void) struct pyrf_evlist { PyObject_HEAD - struct perf_evlist evlist; + struct evlist evlist; }; static int pyrf_evlist__init(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs __maybe_unused) { PyObject *pcpus = NULL, *pthreads = NULL; - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads)) return -1; threads = ((struct pyrf_thread_map *)pthreads)->threads; cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - perf_evlist__init(&pevlist->evlist, cpus, threads); + evlist__init(&pevlist->evlist, cpus, threads); return 0; } @@ -886,7 +891,7 @@ static void pyrf_evlist__delete(struct pyrf_evlist *pevlist) static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; static char *kwlist[] = { "pages", "overwrite", NULL }; int pages = 128, overwrite = false; @@ -906,7 +911,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; static char *kwlist[] = { "timeout", NULL }; int timeout = -1, n; @@ -926,7 +931,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, PyObject *args __maybe_unused, PyObject *kwargs __maybe_unused) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; PyObject *list = PyList_New(0); int i; @@ -964,22 +969,22 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs __maybe_unused) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; PyObject *pevsel; - struct perf_evsel *evsel; + struct evsel *evsel; if (!PyArg_ParseTuple(args, "O", &pevsel)) return NULL; Py_INCREF(pevsel); evsel = &((struct pyrf_evsel *)pevsel)->evsel; - evsel->idx = evlist->nr_entries; - perf_evlist__add(evlist, evsel); + evsel->idx = evlist->core.nr_entries; + evlist__add(evlist, evsel); - return Py_BuildValue("i", evlist->nr_entries); + return Py_BuildValue("i", evlist->core.nr_entries); } -static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu) +static struct perf_mmap *get_md(struct evlist *evlist, int cpu) { int i; @@ -996,7 +1001,7 @@ static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu) static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; union perf_event *event; int sample_id_all = 1, cpu; static char *kwlist[] = { "cpu", "sample_id_all", NULL }; @@ -1018,7 +1023,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, if (event != NULL) { PyObject *pyevent = pyrf_event__new(event); struct pyrf_event *pevent = (struct pyrf_event *)pyevent; - struct perf_evsel *evsel; + struct evsel *evsel; if (pyevent == NULL) return PyErr_NoMemory(); @@ -1049,7 +1054,7 @@ end: static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; int group = 0; static char *kwlist[] = { "group", NULL }; @@ -1059,7 +1064,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, if (group) perf_evlist__set_leader(evlist); - if (perf_evlist__open(evlist) < 0) { + if (evlist__open(evlist) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -1112,15 +1117,15 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj) { struct pyrf_evlist *pevlist = (void *)obj; - return pevlist->evlist.nr_entries; + return pevlist->evlist.core.nr_entries; } static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) { struct pyrf_evlist *pevlist = (void *)obj; - struct perf_evsel *pos; + struct evsel *pos; - if (i >= pevlist->evlist.nr_entries) + if (i >= pevlist->evlist.core.nr_entries) return NULL; evlist__for_each_entry(&pevlist->evlist, pos) { diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 9cfc7bf16531..286fe816c0f3 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -1,25 +1,31 @@ // SPDX-License-Identifier: GPL-2.0 +#include "debug.h" #include "evlist.h" #include "evsel.h" #include "cpumap.h" #include "parse-events.h" #include <errno.h> +#include <limits.h> +#include <stdlib.h> #include <api/fs/fs.h> #include <subcmd/parse-options.h> +#include <perf/cpumap.h> #include "util.h" #include "cloexec.h" +#include "record.h" +#include "../perf-sys.h" -typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); +typedef void (*setup_probe_fn_t)(struct evsel *evsel); static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) { - struct perf_evlist *evlist; - struct perf_evsel *evsel; + struct evlist *evlist; + struct evsel *evsel; unsigned long flags = perf_event_open_cloexec_flag(); int err = -EAGAIN, fd; static pid_t pid = -1; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) return -ENOMEM; @@ -29,7 +35,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) evsel = perf_evlist__first(evlist); while (1) { - fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); if (fd < 0) { if (pid == -1 && errno == EACCES) { pid = 0; @@ -43,7 +49,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) fn(evsel); - fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); if (fd < 0) { if (errno == EINVAL) err = -EINVAL; @@ -53,21 +59,21 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) err = 0; out_delete: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } static bool perf_probe_api(setup_probe_fn_t fn) { const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; int cpu, ret, i = 0; - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) return false; cpu = cpus->map[0]; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); do { ret = perf_do_probe_api(fn, cpu, try[i++]); @@ -78,19 +84,19 @@ static bool perf_probe_api(setup_probe_fn_t fn) return false; } -static void perf_probe_sample_identifier(struct perf_evsel *evsel) +static void perf_probe_sample_identifier(struct evsel *evsel) { - evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; + evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER; } -static void perf_probe_comm_exec(struct perf_evsel *evsel) +static void perf_probe_comm_exec(struct evsel *evsel) { - evsel->attr.comm_exec = 1; + evsel->core.attr.comm_exec = 1; } -static void perf_probe_context_switch(struct perf_evsel *evsel) +static void perf_probe_context_switch(struct evsel *evsel) { - evsel->attr.context_switch = 1; + evsel->core.attr.context_switch = 1; } bool perf_can_sample_identifier(void) @@ -115,14 +121,14 @@ bool perf_can_record_cpu_wide(void) .config = PERF_COUNT_SW_CPU_CLOCK, .exclude_kernel = 1, }; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; int cpu, fd; - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) return false; cpu = cpus->map[0]; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); fd = sys_perf_event_open(&attr, -1, cpu, -1, 0); if (fd < 0) @@ -132,10 +138,10 @@ bool perf_can_record_cpu_wide(void) return true; } -void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, +void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain) { - struct perf_evsel *evsel; + struct evsel *evsel; bool use_sample_identifier = false; bool use_comm_exec; bool sample_id = opts->sample_id; @@ -147,7 +153,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, if (opts->group) perf_evlist__set_leader(evlist); - if (evlist->cpus->map[0] < 0) + if (evlist->core.cpus->map[0] < 0) opts->no_inherit = true; use_comm_exec = perf_can_comm_exec(); @@ -155,7 +161,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, evlist__for_each_entry(evlist, evsel) { perf_evsel__config(evsel, opts, callchain); if (evsel->tracking && use_comm_exec) - evsel->attr.comm_exec = 1; + evsel->core.attr.comm_exec = 1; } if (opts->full_auxtrace) { @@ -166,11 +172,11 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, */ use_sample_identifier = perf_can_sample_identifier(); sample_id = true; - } else if (evlist->nr_entries > 1) { - struct perf_evsel *first = perf_evlist__first(evlist); + } else if (evlist->core.nr_entries > 1) { + struct evsel *first = perf_evlist__first(evlist); evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.sample_type == first->attr.sample_type) + if (evsel->core.attr.sample_type == first->core.attr.sample_type) continue; use_sample_identifier = perf_can_sample_identifier(); break; @@ -256,15 +262,15 @@ int record_opts__config(struct record_opts *opts) return record_opts__config_freq(opts); } -bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) +bool perf_evlist__can_select_event(struct evlist *evlist, const char *str) { - struct perf_evlist *temp_evlist; - struct perf_evsel *evsel; + struct evlist *temp_evlist; + struct evsel *evsel; int err, fd, cpu; bool ret = false; pid_t pid = -1; - temp_evlist = perf_evlist__new(); + temp_evlist = evlist__new(); if (!temp_evlist) return false; @@ -274,17 +280,17 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) evsel = perf_evlist__last(temp_evlist); - if (!evlist || cpu_map__empty(evlist->cpus)) { - struct cpu_map *cpus = cpu_map__new(NULL); + if (!evlist || perf_cpu_map__empty(evlist->core.cpus)) { + struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); cpu = cpus ? cpus->map[0] : 0; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); } else { - cpu = evlist->cpus->map[0]; + cpu = evlist->core.cpus->map[0]; } while (1) { - fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, perf_event_open_cloexec_flag()); if (fd < 0) { if (pid == -1 && errno == EACCES) { @@ -299,7 +305,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) ret = true; out_delete: - perf_evlist__delete(temp_evlist); + evlist__delete(temp_evlist); return ret; } diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h new file mode 100644 index 000000000000..00275afc524d --- /dev/null +++ b/tools/perf/util/record.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PERF_RECORD_H +#define _PERF_RECORD_H + +#include <time.h> +#include <stdbool.h> +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/perf_event.h> +#include "util/target.h" + +struct option; + +struct record_opts { + struct target target; + bool group; + bool inherit_stat; + bool no_buffering; + bool no_inherit; + bool no_inherit_set; + bool no_samples; + bool raw_samples; + bool sample_address; + bool sample_phys_addr; + bool sample_weight; + bool sample_time; + bool sample_time_set; + bool sample_cpu; + bool period; + bool period_set; + bool running_time; + bool full_auxtrace; + bool auxtrace_snapshot_mode; + bool auxtrace_snapshot_on_exit; + bool record_namespaces; + bool record_switch_events; + bool all_kernel; + bool all_user; + bool kernel_callchains; + bool user_callchains; + bool tail_synthesize; + bool overwrite; + bool ignore_missing_thread; + bool strict_freq; + bool sample_id; + bool no_bpf_event; + unsigned int freq; + unsigned int mmap_pages; + unsigned int auxtrace_mmap_pages; + unsigned int user_freq; + u64 branch_stack; + u64 sample_intr_regs; + u64 sample_user_regs; + u64 default_interval; + u64 user_interval; + size_t auxtrace_snapshot_size; + const char *auxtrace_snapshot_opts; + bool sample_transaction; + unsigned initial_delay; + bool use_clockid; + clockid_t clockid; + u64 clockid_res_ns; + int nr_cblocks; + int affinity; + int mmap_flush; + unsigned int comp_level; +}; + +extern const char * const *record_usage; +extern struct option *record_options; + +int record__parse_freq(const struct option *opt, const char *str, int unset); + +#endif // _PERF_RECORD_H diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c index 83d2e149ef19..24a99909d8b3 100644 --- a/tools/perf/util/s390-cpumsf.c +++ b/tools/perf/util/s390-cpumsf.c @@ -157,7 +157,7 @@ #include "evlist.h" #include "machine.h" #include "session.h" -#include "thread.h" +#include "tool.h" #include "debug.h" #include "auxtrace.h" #include "s390-cpumsf.h" @@ -918,7 +918,7 @@ s390_cpumsf_process_event(struct perf_session *session, struct s390_cpumsf, auxtrace); u64 timestamp = sample->time; - struct perf_evsel *ev_bc000; + struct evsel *ev_bc000; int err = 0; @@ -935,7 +935,7 @@ s390_cpumsf_process_event(struct perf_session *session, /* Handle event with raw data */ ev_bc000 = perf_evlist__event2evsel(session->evlist, event); if (ev_bc000 && - ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG) + ev_bc000->core.attr.config == PERF_EVENT_CPUM_CF_DIAG) err = s390_cpumcf_dumpctr(sf, sample); return err; } @@ -1109,11 +1109,11 @@ static int s390_cpumsf__config(const char *var, const char *value, void *cb) int s390_cpumsf_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; struct s390_cpumsf *sf; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event)) + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info)) return -EINVAL; sf = zalloc(sizeof(struct s390_cpumsf)); diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index 6650f599ed9c..4d9593e331ea 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -23,10 +23,8 @@ #include "debug.h" #include "util.h" -#include "auxtrace.h" #include "session.h" #include "evlist.h" -#include "config.h" #include "color.h" #include "sample-raw.h" #include "s390-cpumcf-kernel.h" @@ -200,17 +198,17 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample) * its raw data. * The function is only invoked when the dump flag -D is set. */ -void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event, +void perf_evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { - struct perf_evsel *ev_bc000; + struct evsel *ev_bc000; if (event->header.type != PERF_RECORD_SAMPLE) return; ev_bc000 = perf_evlist__event2evsel(evlist, event); if (ev_bc000 == NULL || - ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG) + ev_bc000->core.attr.config != PERF_EVENT_CPUM_CF_DIAG) return; /* Display raw data on screen */ diff --git a/tools/perf/util/sample-raw.c b/tools/perf/util/sample-raw.c index c21e1311fb0f..e84bbe0e441a 100644 --- a/tools/perf/util/sample-raw.c +++ b/tools/perf/util/sample-raw.c @@ -9,7 +9,7 @@ * Check platform the perf data file was created on and perform platform * specific interpretation. */ -void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist) +void perf_evlist__init_trace_event_sample_raw(struct evlist *evlist) { const char *arch_pf = perf_env__arch(evlist->env); diff --git a/tools/perf/util/sample-raw.h b/tools/perf/util/sample-raw.h index 95d445c87e93..afe1491a117e 100644 --- a/tools/perf/util/sample-raw.h +++ b/tools/perf/util/sample-raw.h @@ -2,13 +2,13 @@ #ifndef __SAMPLE_RAW_H #define __SAMPLE_RAW_H 1 -struct perf_evlist; +struct evlist; union perf_event; struct perf_sample; -void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, +void perf_evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample); -void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist); +void perf_evlist__init_trace_event_sample_raw(struct evlist *evlist); #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 61aa7f3df915..15961854ba67 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -34,8 +34,8 @@ #include <EXTERN.h> #include <perl.h> -#include "../../perf.h" #include "../callchain.h" +#include "../dso.h" #include "../machine.h" #include "../map.h" #include "../symbol.h" @@ -258,7 +258,7 @@ static void define_event_symbols(struct tep_event *event, } static SV *perl_process_callchain(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { AV *list; @@ -336,7 +336,7 @@ exit: } static void perl_process_tracepoint(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { struct thread *thread = al->thread; @@ -353,11 +353,11 @@ static void perl_process_tracepoint(struct perf_sample *sample, dSP; - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) return; if (!event) { - pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); + pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config); return; } @@ -431,7 +431,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, static void perl_process_event_generic(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { dSP; @@ -442,7 +442,7 @@ static void perl_process_event_generic(union perf_event *event, SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size))); - XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr)))); + XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->core.attr, sizeof(evsel->core.attr)))); XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample)))); XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size))); PUTBACK; @@ -455,7 +455,7 @@ static void perl_process_event_generic(union perf_event *event, static void perl_process_event(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { perl_process_tracepoint(sample, evsel, al); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 25dc1d765553..666a56e88d8e 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -31,8 +31,10 @@ #include <linux/compiler.h> #include <linux/time64.h> -#include "../../perf.h" +#include "../build-id.h" +#include "../counts.h" #include "../debug.h" +#include "../dso.h" #include "../callchain.h" #include "../evsel.h" #include "../util.h" @@ -392,7 +394,7 @@ static const char *get_dsoname(struct map *map) } static PyObject *python_process_callchain(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { PyObject *pylist; @@ -634,9 +636,9 @@ static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) static void set_sample_read_in_dict(PyObject *dict_sample, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { - u64 read_format = evsel->attr.read_format; + u64 read_format = evsel->core.attr.read_format; PyObject *values; unsigned int i; @@ -705,9 +707,9 @@ static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) static void set_regs_in_dict(PyObject *dict, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; char bf[512]; regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf)); @@ -722,7 +724,7 @@ static void set_regs_in_dict(PyObject *dict, } static PyObject *get_perf_sample_dict(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al, PyObject *callchain) { @@ -737,7 +739,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, Py_FatalError("couldn't create Python dictionary"); pydict_set_item_string_decref(dict, "ev_name", _PyUnicode_FromString(perf_evsel__name(evsel))); - pydict_set_item_string_decref(dict, "attr", _PyBytes_FromStringAndSize((const char *)&evsel->attr, sizeof(evsel->attr))); + pydict_set_item_string_decref(dict, "attr", _PyBytes_FromStringAndSize((const char *)&evsel->core.attr, sizeof(evsel->core.attr))); pydict_set_item_string_decref(dict_sample, "pid", _PyLong_FromLong(sample->pid)); @@ -790,7 +792,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, } static void python_process_tracepoint(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { struct tep_event *event = evsel->tp_format; @@ -809,7 +811,7 @@ static void python_process_tracepoint(struct perf_sample *sample, if (!event) { snprintf(handler_name, sizeof(handler_name), - "ug! no event found for type %" PRIu64, (u64)evsel->attr.config); + "ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config); Py_FatalError(handler_name); } @@ -955,7 +957,7 @@ static int tuple_set_bytes(PyObject *t, unsigned int pos, void *bytes, return PyTuple_SetItem(t, pos, _PyBytes_FromStringAndSize(bytes, sz)); } -static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel) +static int python_export_evsel(struct db_export *dbe, struct evsel *evsel) { struct tables *tables = container_of(dbe, struct tables, dbe); PyObject *t; @@ -1163,7 +1165,7 @@ static void python_export_synth(struct db_export *dbe, struct export_sample *es) t = tuple_new(3); tuple_set_u64(t, 0, es->db_id); - tuple_set_u64(t, 1, es->evsel->attr.config); + tuple_set_u64(t, 1, es->evsel->core.attr.config); tuple_set_bytes(t, 2, es->sample->raw_data, es->sample->raw_size); call_object(tables->synth_handler, t, "synth_data"); @@ -1178,7 +1180,7 @@ static int python_export_sample(struct db_export *dbe, python_export_sample_table(dbe, es); - if (es->evsel->attr.type == PERF_TYPE_SYNTH && tables->synth_handler) + if (es->evsel->core.attr.type == PERF_TYPE_SYNTH && tables->synth_handler) python_export_synth(dbe, es); return 0; @@ -1275,7 +1277,7 @@ static int python_process_call_return(struct call_return *cr, u64 *parent_db_id, } static void python_process_general_event(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { PyObject *handler, *t, *dict, *callchain; @@ -1311,12 +1313,12 @@ static void python_process_general_event(struct perf_sample *sample, static void python_process_event(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { struct tables *tables = &tables_global; - switch (evsel->attr.type) { + switch (evsel->core.attr.type) { case PERF_TYPE_TRACEPOINT: python_process_tracepoint(sample, evsel, al); break; @@ -1340,7 +1342,7 @@ static void python_process_switch(union perf_event *event, } static void get_handler_name(char *str, size_t size, - struct perf_evsel *evsel) + struct evsel *evsel) { char *p = str; @@ -1353,7 +1355,7 @@ static void get_handler_name(char *str, size_t size, } static void -process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp, +process_stat(struct evsel *counter, int cpu, int thread, u64 tstamp, struct perf_counts_values *count) { PyObject *handler, *t; @@ -1390,10 +1392,10 @@ process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp, } static void python_process_stat(struct perf_stat_config *config, - struct perf_evsel *counter, u64 tstamp) + struct evsel *counter, u64 tstamp) { - struct thread_map *threads = counter->threads; - struct cpu_map *cpus = counter->cpus; + struct perf_thread_map *threads = counter->core.threads; + struct perf_cpu_map *cpus = counter->core.cpus; int cpu, thread; if (config->aggr_mode == AGGR_GLOBAL) { @@ -1405,7 +1407,7 @@ static void python_process_stat(struct perf_stat_config *config, for (thread = 0; thread < threads->nr; thread++) { for (cpu = 0; cpu < cpus->nr; cpu++) { process_stat(counter, cpus->map[cpu], - thread_map__pid(threads, thread), tstamp, + perf_thread_map__pid(threads, thread), tstamp, perf_counts(counter->counts, cpu, thread)); } } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 37efa1f43d8b..e9e4a04f15db 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,16 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <inttypes.h> +#include <linux/err.h> #include <linux/kernel.h> #include <linux/zalloc.h> -#include <traceevent/event-parse.h> #include <api/fs/fs.h> #include <byteswap.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> +#include <perf/cpumap.h> +#include "map_symbol.h" +#include "branch.h" +#include "debug.h" #include "evlist.h" #include "evsel.h" #include "memswap.h" @@ -18,7 +22,6 @@ #include "symbol.h" #include "session.h" #include "tool.h" -#include "sort.h" #include "cpumap.h" #include "perf_regs.h" #include "asm/bug.h" @@ -27,6 +30,9 @@ #include "thread-stack.h" #include "sample-raw.h" #include "stat.h" +#include "util.h" +#include "ui/progress.h" +#include "../perf.h" #include "arch/common.h" #ifdef HAVE_ZSTD_SUPPORT @@ -61,8 +67,8 @@ static int perf_session__process_compressed_event(struct perf_session *session, decomp->size = decomp_last_rem; } - src = (void *)event + sizeof(struct compressed_event); - src_size = event->pack.header.size - sizeof(struct compressed_event); + src = (void *)event + sizeof(struct perf_record_compressed); + src_size = event->pack.header.size - sizeof(struct perf_record_compressed); decomp_size = zstd_decompress_stream(&(session->zstd_data), src, src_size, &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem); @@ -151,10 +157,10 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session) static bool perf_session__has_comm_exec(struct perf_session *session) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.comm_exec) + if (evsel->core.attr.comm_exec) return true; } @@ -300,7 +306,7 @@ static int process_event_synth_tracing_data_stub(struct perf_session *session static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, - struct perf_evlist **pevlist + struct evlist **pevlist __maybe_unused) { dump_printf(": unhandled!\n"); @@ -309,7 +315,7 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, - struct perf_evlist **pevlist + struct evlist **pevlist __maybe_unused) { if (dump_trace) @@ -322,7 +328,7 @@ static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_ 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 evsel *evsel __maybe_unused, struct machine *machine __maybe_unused) { dump_printf(": unhandled!\n"); @@ -471,8 +477,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->context_switch = perf_event__process_switch; if (tool->ksymbol == NULL) tool->ksymbol = perf_event__process_ksymbol; - if (tool->bpf_event == NULL) - tool->bpf_event = perf_event__process_bpf_event; + if (tool->bpf == NULL) + tool->bpf = perf_event__process_bpf; if (tool->read == NULL) tool->read = process_event_sample_stub; if (tool->throttle == NULL) @@ -833,9 +839,9 @@ static void perf_event__thread_map_swap(union perf_event *event, static void perf_event__cpu_map_swap(union perf_event *event, bool sample_id_all __maybe_unused) { - struct cpu_map_data *data = &event->cpu_map.data; + struct perf_record_cpu_map_data *data = &event->cpu_map.data; struct cpu_map_entries *cpus; - struct cpu_map_mask *mask; + struct perf_record_record_cpu_map *mask; unsigned i; data->type = bswap_64(data->type); @@ -850,7 +856,7 @@ static void perf_event__cpu_map_swap(union perf_event *event, cpus->cpu[i] = bswap_16(cpus->cpu[i]); break; case PERF_CPU_MAP__MASK: - mask = (struct cpu_map_mask *) data->data; + mask = (struct perf_record_record_cpu_map *)data->data; mask->nr = bswap_16(mask->nr); mask->long_size = bswap_16(mask->long_size); @@ -1033,7 +1039,7 @@ static void callchain__lbr_callstack_printf(struct perf_sample *sample) } } -static void callchain__printf(struct perf_evsel *evsel, +static void callchain__printf(struct evsel *evsel, struct perf_sample *sample) { unsigned int i; @@ -1049,23 +1055,30 @@ static void callchain__printf(struct perf_evsel *evsel, i, callchain->ips[i]); } -static void branch_stack__printf(struct perf_sample *sample) +static void branch_stack__printf(struct perf_sample *sample, bool callstack) { uint64_t i; - printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr); + printf("%s: nr:%" PRIu64 "\n", + !callstack ? "... branch stack" : "... branch callstack", + sample->branch_stack->nr); for (i = 0; i < sample->branch_stack->nr; i++) { struct branch_entry *e = &sample->branch_stack->entries[i]; - printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n", - i, e->from, e->to, - (unsigned short)e->flags.cycles, - e->flags.mispred ? "M" : " ", - e->flags.predicted ? "P" : " ", - e->flags.abort ? "A" : " ", - e->flags.in_tx ? "T" : " ", - (unsigned)e->flags.reserved); + if (!callstack) { + printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n", + i, e->from, e->to, + (unsigned short)e->flags.cycles, + e->flags.mispred ? "M" : " ", + e->flags.predicted ? "P" : " ", + e->flags.abort ? "A" : " ", + e->flags.in_tx ? "T" : " ", + (unsigned)e->flags.reserved); + } else { + printf("..... %2"PRIu64": %016" PRIx64 "\n", + i, i > 0 ? e->from : e->to); + } } } @@ -1129,7 +1142,7 @@ static void stack_user__printf(struct stack_dump *dump) dump->size, dump->offset); } -static void perf_evlist__print_tstamp(struct perf_evlist *evlist, +static void perf_evlist__print_tstamp(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { @@ -1178,7 +1191,7 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format) sample->read.one.id, sample->read.one.value); } -static void dump_event(struct perf_evlist *evlist, union perf_event *event, +static void dump_event(struct evlist *evlist, union perf_event *event, u64 file_offset, struct perf_sample *sample) { if (!dump_trace) @@ -1198,7 +1211,7 @@ static void dump_event(struct perf_evlist *evlist, union perf_event *event, event->header.size, perf_event__name(event->header.type)); } -static void dump_sample(struct perf_evsel *evsel, union perf_event *event, +static void dump_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *sample) { u64 sample_type; @@ -1210,13 +1223,13 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, event->header.misc, sample->pid, sample->tid, sample->ip, sample->period, sample->addr); - sample_type = evsel->attr.sample_type; + sample_type = evsel->core.attr.sample_type; if (evsel__has_callchain(evsel)) callchain__printf(evsel, sample); - if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) - branch_stack__printf(sample); + if (sample_type & PERF_SAMPLE_BRANCH_STACK) + branch_stack__printf(sample, perf_evsel__has_branch_callstack(evsel)); if (sample_type & PERF_SAMPLE_REGS_USER) regs_user__printf(sample); @@ -1240,34 +1253,34 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, printf("... transaction: %" PRIx64 "\n", sample->transaction); if (sample_type & PERF_SAMPLE_READ) - sample_read__printf(sample, evsel->attr.read_format); + sample_read__printf(sample, evsel->core.attr.read_format); } -static void dump_read(struct perf_evsel *evsel, union perf_event *event) +static void dump_read(struct evsel *evsel, union perf_event *event) { - struct read_event *read_event = &event->read; + struct perf_record_read *read_event = &event->read; u64 read_format; if (!dump_trace) return; - printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, + printf(": %d %d %s %" PRI_lu64 "\n", event->read.pid, event->read.tid, perf_evsel__name(evsel), event->read.value); if (!evsel) return; - read_format = evsel->attr.read_format; + read_format = evsel->core.attr.read_format; if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - printf("... time enabled : %" PRIu64 "\n", read_event->time_enabled); + printf("... time enabled : %" PRI_lu64 "\n", read_event->time_enabled); if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - printf("... time running : %" PRIu64 "\n", read_event->time_running); + printf("... time running : %" PRI_lu64 "\n", read_event->time_running); if (read_format & PERF_FORMAT_ID) - printf("... id : %" PRIu64 "\n", read_event->id); + printf("... id : %" PRI_lu64 "\n", read_event->id); } static struct machine *machines__find_for_cpumode(struct machines *machines, @@ -1296,7 +1309,7 @@ static struct machine *machines__find_for_cpumode(struct machines *machines, return &machines->host; } -static int deliver_sample_value(struct perf_evlist *evlist, +static int deliver_sample_value(struct evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -1326,7 +1339,7 @@ static int deliver_sample_value(struct perf_evlist *evlist, return tool->sample(tool, event, sample, sid->evsel, machine); } -static int deliver_sample_group(struct perf_evlist *evlist, +static int deliver_sample_group(struct evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -1347,16 +1360,16 @@ static int deliver_sample_group(struct perf_evlist *evlist, } static int - perf_evlist__deliver_sample(struct perf_evlist *evlist, + perf_evlist__deliver_sample(struct evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { /* We know evsel != NULL. */ - u64 sample_type = evsel->attr.sample_type; - u64 read_format = evsel->attr.read_format; + u64 sample_type = evsel->core.attr.sample_type; + u64 read_format = evsel->core.attr.read_format; /* Standard sample delivery. */ if (!(sample_type & PERF_SAMPLE_READ)) @@ -1372,12 +1385,12 @@ static int } static int machines__deliver_event(struct machines *machines, - struct perf_evlist *evlist, + struct evlist *evlist, union perf_event *event, struct perf_sample *sample, struct perf_tool *tool, u64 file_offset) { - struct perf_evsel *evsel; + struct evsel *evsel; struct machine *machine; dump_event(evlist, event, file_offset, sample); @@ -1443,7 +1456,7 @@ static int machines__deliver_event(struct machines *machines, case PERF_RECORD_KSYMBOL: return tool->ksymbol(tool, event, sample, machine); case PERF_RECORD_BPF_EVENT: - return tool->bpf_event(tool, event, sample, machine); + return tool->bpf(tool, event, sample, machine); default: ++evlist->stats.nr_unknown_events; return -1; @@ -1553,7 +1566,7 @@ int perf_session__deliver_synth_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample) { - struct perf_evlist *evlist = session->evlist; + struct evlist *evlist = session->evlist; struct perf_tool *tool = session->tool; events_stats__inc(&evlist->stats, event->header.type); @@ -1631,7 +1644,7 @@ out_parse_sample: static s64 perf_session__process_event(struct perf_session *session, union perf_event *event, u64 file_offset) { - struct perf_evlist *evlist = session->evlist; + struct evlist *evlist = session->evlist; struct perf_tool *tool = session->tool; int ret; @@ -1705,11 +1718,11 @@ static void perf_session__warn_order(const struct perf_session *session) { const struct ordered_events *oe = &session->ordered_events; - struct perf_evsel *evsel; + struct evsel *evsel; bool should_warn = true; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.write_backward) + if (evsel->core.attr.write_backward) should_warn = false; } @@ -1954,7 +1967,9 @@ fetch_mmaped_event(struct perf_session *session, /* We're not fetching the event so swap back again */ if (session->header.needs_swap) perf_event_header__bswap(&event->header); - return NULL; + pr_debug("%s: head=%#" PRIx64 " event->header_size=%#x, mmap_size=%#zx: fuzzed perf.data?\n", + __func__, head, event->header.size, mmap_size); + return ERR_PTR(-EINVAL); } return event; @@ -1972,6 +1987,9 @@ static int __perf_session__process_decomp_events(struct perf_session *session) while (decomp->head < decomp->size && !session_done()) { union perf_event *event = fetch_mmaped_event(session, decomp->head, decomp->size, decomp->data); + if (IS_ERR(event)) + return PTR_ERR(event); + if (!event) break; @@ -2071,6 +2089,9 @@ remap: more: event = fetch_mmaped_event(session, head, mmap_size, buf); + if (IS_ERR(event)) + return PTR_ERR(event); + if (!event) { if (mmaps[map_idx]) { munmap(mmaps[map_idx], mmap_size); @@ -2183,10 +2204,10 @@ int perf_session__process_events(struct perf_session *session) bool perf_session__has_traces(struct perf_session *session, const char *msg) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) return true; } @@ -2257,13 +2278,13 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) return machine__fprintf(&session->machines.host, fp); } -struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, +struct evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(session->evlist, pos) { - if (pos->attr.type == type) + if (pos->core.attr.type == type) return pos; } return NULL; @@ -2273,23 +2294,24 @@ int perf_session__cpu_bitmap(struct perf_session *session, const char *cpu_list, unsigned long *cpu_bitmap) { int i, err = -1; - struct cpu_map *map; + struct perf_cpu_map *map; + int nr_cpus = min(session->header.env.nr_cpus_online, MAX_NR_CPUS); for (i = 0; i < PERF_TYPE_MAX; ++i) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = perf_session__find_first_evtype(session, i); if (!evsel) continue; - if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { + if (!(evsel->core.attr.sample_type & PERF_SAMPLE_CPU)) { pr_err("File does not contain CPU events. " "Remove -C option to proceed.\n"); return -1; } } - map = cpu_map__new(cpu_list); + map = perf_cpu_map__new(cpu_list); if (map == NULL) { pr_err("Invalid cpu_list\n"); return -1; @@ -2298,7 +2320,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, for (i = 0; i < map->nr; i++) { int cpu = map->map[i]; - if (cpu >= MAX_NR_CPUS) { + if (cpu >= nr_cpus) { pr_err("Requested CPU %d too large. " "Consider raising MAX_NR_CPUS\n", cpu); goto out_delete_map; @@ -2310,7 +2332,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, err = 0; out_delete_map: - cpu_map__put(map); + perf_cpu_map__put(map); return err; } @@ -2327,10 +2349,10 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp, int __perf_session__set_tracepoints_handlers(struct perf_session *session, - const struct perf_evsel_str_handler *assocs, + const struct evsel_str_handler *assocs, size_t nr_assocs) { - struct perf_evsel *evsel; + struct evsel *evsel; size_t i; int err; @@ -2357,11 +2379,11 @@ out: int perf_event__process_id_index(struct perf_session *session, union perf_event *event) { - struct perf_evlist *evlist = session->evlist; - struct id_index_event *ie = &event->id_index; + struct evlist *evlist = session->evlist; + struct perf_record_id_index *ie = &event->id_index; size_t i, nr, max_nr; - max_nr = (ie->header.size - sizeof(struct id_index_event)) / + max_nr = (ie->header.size - sizeof(struct perf_record_id_index)) / sizeof(struct id_index_entry); nr = ie->nr; if (nr > max_nr) @@ -2375,10 +2397,10 @@ int perf_event__process_id_index(struct perf_session *session, struct perf_sample_id *sid; if (dump_trace) { - fprintf(stdout, " ... id: %"PRIu64, e->id); - fprintf(stdout, " idx: %"PRIu64, e->idx); - fprintf(stdout, " cpu: %"PRId64, e->cpu); - fprintf(stdout, " tid: %"PRId64"\n", e->tid); + fprintf(stdout, " ... id: %"PRI_lu64, e->id); + fprintf(stdout, " idx: %"PRI_lu64, e->idx); + fprintf(stdout, " cpu: %"PRI_ld64, e->cpu); + fprintf(stdout, " tid: %"PRI_ld64"\n", e->tid); } sid = perf_evlist__id2sid(evlist, e->id); @@ -2393,24 +2415,24 @@ int perf_event__process_id_index(struct perf_session *session, int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, - struct perf_evlist *evlist, + struct evlist *evlist, struct machine *machine) { union perf_event *ev; - struct perf_evsel *evsel; + struct evsel *evsel; size_t nr = 0, i = 0, sz, max_nr, n; int err; pr_debug2("Synthesizing id index\n"); - max_nr = (UINT16_MAX - sizeof(struct id_index_event)) / + max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / sizeof(struct id_index_entry); evlist__for_each_entry(evlist, evsel) nr += evsel->ids; n = nr > max_nr ? max_nr : nr; - sz = sizeof(struct id_index_event) + n * sizeof(struct id_index_entry); + sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); ev = zalloc(sz); if (!ev) return -ENOMEM; @@ -2450,7 +2472,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, } } - sz = sizeof(struct id_index_event) + nr * sizeof(struct id_index_entry); + sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); ev->id_index.header.size = sz; ev->id_index.nr = nr; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 863dbad87849..b7aa076ab6fd 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -23,12 +23,12 @@ struct itrace_synth_opts; struct perf_session { struct perf_header header; struct machines machines; - struct perf_evlist *evlist; + struct evlist *evlist; struct auxtrace *auxtrace; struct itrace_synth_opts *itrace_synth_opts; struct list_head auxtrace_index; struct trace_event tevent; - struct time_conv_event time_conv; + struct perf_record_time_conv time_conv; bool repipe; bool one_mmap; void *one_mmap_addr; @@ -73,7 +73,7 @@ int perf_session__queue_event(struct perf_session *s, union perf_event *event, void perf_tool__fill_defaults(struct perf_tool *tool); int perf_session__resolve_callchain(struct perf_session *session, - struct perf_evsel *evsel, + struct evsel *evsel, struct thread *thread, struct ip_callchain *chain, struct symbol **parent); @@ -110,7 +110,7 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); -struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, +struct evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); int perf_session__cpu_bitmap(struct perf_session *session, @@ -118,10 +118,10 @@ int perf_session__cpu_bitmap(struct perf_session *session, void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); -struct perf_evsel_str_handler; +struct evsel_str_handler; int __perf_session__set_tracepoints_handlers(struct perf_session *session, - const struct perf_evsel_str_handler *assocs, + const struct evsel_str_handler *assocs, size_t nr_assocs); #define perf_session__set_tracepoints_handlers(session, array) \ @@ -140,7 +140,7 @@ int perf_event__process_id_index(struct perf_session *session, int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, - struct perf_evlist *evlist, + struct evlist *evlist, struct machine *machine); #endif /* __PERF_SESSION_H */ diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index a1a68a2fa917..aa344a163eaf 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -48,6 +48,7 @@ build_lib = getenv('PYTHON_EXTBUILD_LIB') build_tmp = getenv('PYTHON_EXTBUILD_TMP') libtraceevent = getenv('LIBTRACEEVENT') libapikfs = getenv('LIBAPI') +libperf = getenv('LIBPERF') ext_sources = [f.strip() for f in open('util/python-ext-sources') if len(f.strip()) > 0 and f[0] != '#'] @@ -58,13 +59,15 @@ ext_sources = list(map(lambda x: '%s/%s' % (src_perf, x) , ext_sources)) extra_libraries = [] if '-DHAVE_LIBNUMA_SUPPORT' in cflags: extra_libraries = [ 'numa' ] +if '-DHAVE_LIBCAP_SUPPORT' in cflags: + extra_libraries += [ 'cap' ] perf = Extension('perf', sources = ext_sources, include_dirs = ['util/include'], libraries = extra_libraries, extra_compile_args = cflags, - extra_objects = [libtraceevent, libapikfs], + extra_objects = [libtraceevent, libapikfs, libperf], ) setup(name='perf', diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5d2518e89fc4..a2308eb77681 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2,16 +2,23 @@ #include <errno.h> #include <inttypes.h> #include <regex.h> +#include <stdlib.h> #include <linux/mman.h> #include <linux/time64.h> +#include "debug.h" +#include "dso.h" #include "sort.h" #include "hist.h" +#include "cacheline.h" #include "comm.h" #include "map.h" #include "symbol.h" +#include "map_symbol.h" +#include "branch.h" #include "thread.h" #include "evsel.h" #include "evlist.h" +#include "srcline.h" #include "strlist.h" #include "strbuf.h" #include <traceevent/event-parse.h> @@ -19,6 +26,7 @@ #include "annotate.h" #include "time-utils.h" #include <linux/kernel.h> +#include <linux/string.h> regex_t parent_regex; const char default_parent_pattern[] = "^sys_|^do_page_fault"; @@ -668,17 +676,11 @@ sort__time_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__time_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - unsigned long secs; - unsigned long long nsecs; char he_time[32]; - nsecs = he->time; - secs = nsecs / NSEC_PER_SEC; - nsecs -= secs * NSEC_PER_SEC; - if (symbol_conf.nanosecs) - snprintf(he_time, sizeof he_time, "%5lu.%09llu: ", - secs, nsecs); + timestamp__scnprintf_nsec(he->time, he_time, + sizeof(he_time)); else timestamp__scnprintf_usec(he->time, he_time, sizeof(he_time)); @@ -698,7 +700,7 @@ struct sort_entry sort_time = { static char *get_trace_output(struct hist_entry *he) { struct trace_seq seq; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_record rec = { .data = he->raw_data, .size = he->raw_size, @@ -711,7 +713,8 @@ static char *get_trace_output(struct hist_entry *he) tep_print_fields(&seq, he->raw_data, he->raw_size, evsel->tp_format); } else { - tep_event_info(&seq, evsel->tp_format, &rec); + tep_print_event(evsel->tp_format->tep, + &seq, &rec, "%s", TEP_PRINT_INFO); } /* * Trim the buffer, it starts at 4KB and we're not going to @@ -723,10 +726,10 @@ static char *get_trace_output(struct hist_entry *he) static int64_t sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = hists_to_evsel(left->hists); - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) return 0; if (left->trace_output == NULL) @@ -740,10 +743,10 @@ sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = hists_to_evsel(he->hists); - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) return scnprintf(bf, size, "%-.*s", width, "N/A"); if (he->trace_output == NULL) @@ -1984,7 +1987,7 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd, struct hpp_dynamic_entry { struct perf_hpp_fmt hpp; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_format_field *field; unsigned dynamic_len; bool raw_trace; @@ -2218,7 +2221,7 @@ static void hde_free(struct perf_hpp_fmt *fmt) } static struct hpp_dynamic_entry * -__alloc_dynamic_entry(struct perf_evsel *evsel, struct tep_format_field *field, +__alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field, int level) { struct hpp_dynamic_entry *hde; @@ -2313,17 +2316,17 @@ static int parse_field_name(char *str, char **event, char **field, char **opt) * 2. full event name (e.g. sched:sched_switch) * 3. partial event name (should not contain ':') */ -static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name) +static struct evsel *find_evsel(struct evlist *evlist, char *event_name) { - struct perf_evsel *evsel = NULL; - struct perf_evsel *pos; + struct evsel *evsel = NULL; + struct evsel *pos; bool full_name; /* case 1 */ if (event_name[0] == '%') { int nr = strtol(event_name+1, NULL, 0); - if (nr > evlist->nr_entries) + if (nr > evlist->core.nr_entries) return NULL; evsel = perf_evlist__first(evlist); @@ -2352,7 +2355,7 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam return evsel; } -static int __dynamic_dimension__add(struct perf_evsel *evsel, +static int __dynamic_dimension__add(struct evsel *evsel, struct tep_format_field *field, bool raw_trace, int level) { @@ -2368,7 +2371,7 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel, return 0; } -static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level) +static int add_evsel_fields(struct evsel *evsel, bool raw_trace, int level) { int ret; struct tep_format_field *field; @@ -2384,14 +2387,14 @@ static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level) return 0; } -static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace, +static int add_all_dynamic_fields(struct evlist *evlist, bool raw_trace, int level) { int ret; - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; ret = add_evsel_fields(evsel, raw_trace, level); @@ -2401,15 +2404,15 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace, return 0; } -static int add_all_matching_fields(struct perf_evlist *evlist, +static int add_all_matching_fields(struct evlist *evlist, char *field_name, bool raw_trace, int level) { int ret = -ESRCH; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_format_field *field; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; field = tep_find_any_field(evsel->tp_format, field_name); @@ -2423,11 +2426,11 @@ static int add_all_matching_fields(struct perf_evlist *evlist, return ret; } -static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok, +static int add_dynamic_entry(struct evlist *evlist, const char *tok, int level) { char *str, *event_name, *field_name, *opt_name; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_format_field *field; bool raw_trace = symbol_conf.raw_trace; int ret = 0; @@ -2470,7 +2473,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok, goto out; } - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { pr_debug("%s is not a tracepoint event\n", event_name); ret = -EINVAL; goto out; @@ -2567,7 +2570,7 @@ int hpp_dimension__add_output(unsigned col) } int sort_dimension__add(struct perf_hpp_list *list, const char *tok, - struct perf_evlist *evlist, + struct evlist *evlist, int level) { unsigned int i; @@ -2663,7 +2666,7 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, } static int setup_sort_list(struct perf_hpp_list *list, char *str, - struct perf_evlist *evlist) + struct evlist *evlist) { char *tmp, *tok; int ret = 0; @@ -2709,7 +2712,7 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, return ret; } -static const char *get_default_sort_order(struct perf_evlist *evlist) +static const char *get_default_sort_order(struct evlist *evlist) { const char *default_sort_orders[] = { default_sort_order, @@ -2720,7 +2723,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) default_tracepoint_sort_order, }; bool use_trace = true; - struct perf_evsel *evsel; + struct evsel *evsel; BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); @@ -2728,7 +2731,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) goto out_no_evlist; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { use_trace = false; break; } @@ -2743,7 +2746,7 @@ out_no_evlist: return default_sort_orders[sort__mode]; } -static int setup_sort_order(struct perf_evlist *evlist) +static int setup_sort_order(struct evlist *evlist) { char *new_sort_order; @@ -2804,7 +2807,7 @@ static char *setup_overhead(char *keys) return keys; } -static int __setup_sorting(struct perf_evlist *evlist) +static int __setup_sorting(struct evlist *evlist) { char *str; const char *sort_keys; @@ -3057,7 +3060,7 @@ out: return ret; } -int setup_sorting(struct perf_evlist *evlist) +int setup_sorting(struct evlist *evlist) { int err; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index a0f232151d6f..7b93f34ac1f4 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -1,29 +1,17 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __PERF_SORT_H #define __PERF_SORT_H -#include "../builtin.h" - #include <regex.h> - -#include "color.h" +#include <stdbool.h> #include <linux/list.h> -#include "cache.h" #include <linux/rbtree.h> #include "map_symbol.h" #include "symbol_conf.h" -#include "string.h" #include "callchain.h" #include "values.h" - -#include "../perf.h" -#include "debug.h" -#include "header.h" - -#include <subcmd/parse-options.h> -#include "parse-events.h" #include "hist.h" -#include "srcline.h" +struct option; struct thread; extern regex_t parent_regex; @@ -204,18 +192,6 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he) return period * 100.0 / total_period; } -static inline u64 cl_address(u64 address) -{ - /* return the cacheline of the address */ - return (address & ~(cacheline_size() - 1)); -} - -static inline u64 cl_offset(u64 address) -{ - /* return the cacheline of the address */ - return (address & (cacheline_size() - 1)); -} - enum sort_mode { SORT_MODE__NORMAL, SORT_MODE__BRANCH, @@ -301,9 +277,9 @@ struct block_hist { extern struct sort_entry sort_thread; extern struct list_head hist_entry__sort_list; -struct perf_evlist; +struct evlist; struct tep_handle; -int setup_sorting(struct perf_evlist *evlist); +int setup_sorting(struct evlist *evlist); int setup_output_field(void); void reset_output_field(void); void sort__setup_elide(FILE *fp); @@ -318,7 +294,7 @@ bool is_strict_order(const char *order); int hpp_dimension__add_output(unsigned col); void reset_dimensions(void); int sort_dimension__add(struct perf_hpp_list *list, const char *tok, - struct perf_evlist *evlist, + struct evlist *evlist, int level); int output_field_add(struct perf_hpp_list *list, char *tok); int64_t diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 58df6a0dbb9f..ed3b0ac2f785 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -1,9 +1,11 @@ +#include <stdlib.h> #include <stdio.h> #include <inttypes.h> #include <linux/string.h> #include <linux/time64.h> #include <math.h> #include "color.h" +#include "counts.h" #include "evlist.h" #include "evsel.h" #include "stat.h" @@ -13,7 +15,6 @@ #include "string2.h" #include <linux/ctype.h> #include "cgroup.h" -#include <math.h> #include <api/fs/fs.h> #define CNTR_NOT_SUPPORTED "<not supported>" @@ -45,7 +46,7 @@ static void print_noise_pct(struct perf_stat_config *config, } static void print_noise(struct perf_stat_config *config, - struct perf_evsel *evsel, double avg) + struct evsel *evsel, double avg) { struct perf_stat_evsel *ps; @@ -56,7 +57,7 @@ static void print_noise(struct perf_stat_config *config, print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg); } -static void print_cgroup(struct perf_stat_config *config, struct perf_evsel *evsel) +static void print_cgroup(struct perf_stat_config *config, struct evsel *evsel) { if (nr_cgroups) { const char *cgrp_name = evsel->cgrp ? evsel->cgrp->name : ""; @@ -66,7 +67,7 @@ static void print_cgroup(struct perf_stat_config *config, struct perf_evsel *evs static void aggr_printout(struct perf_stat_config *config, - struct perf_evsel *evsel, int id, int nr) + struct evsel *evsel, int id, int nr) { switch (config->aggr_mode) { case AGGR_CORE: @@ -109,16 +110,16 @@ static void aggr_printout(struct perf_stat_config *config, } else { fprintf(config->output, "CPU%*d%s ", config->csv_output ? 0 : -5, - perf_evsel__cpus(evsel)->map[id], + evsel__cpus(evsel)->map[id], config->csv_sep); } break; case AGGR_THREAD: fprintf(config->output, "%*s-%*d%s", config->csv_output ? 0 : 16, - thread_map__comm(evsel->threads, id), + perf_thread_map__comm(evsel->core.threads, id), config->csv_output ? 0 : -8, - thread_map__pid(evsel->threads, id), + perf_thread_map__pid(evsel->core.threads, id), config->csv_sep); break; case AGGR_GLOBAL: @@ -134,7 +135,7 @@ struct outstate { const char *prefix; int nfields; int id, nr; - struct perf_evsel *evsel; + struct evsel *evsel; }; #define METRIC_LEN 35 @@ -233,7 +234,7 @@ static bool valid_only_metric(const char *unit) return true; } -static const char *fixunit(char *buf, struct perf_evsel *evsel, +static const char *fixunit(char *buf, struct evsel *evsel, const char *unit) { if (!strncmp(unit, "of all", 6)) { @@ -310,9 +311,9 @@ static void print_metric_header(struct perf_stat_config *config, } static int first_shadow_cpu(struct perf_stat_config *config, - struct perf_evsel *evsel, int id) + struct evsel *evsel, int id) { - struct perf_evlist *evlist = evsel->evlist; + struct evlist *evlist = evsel->evlist; int i; if (!config->aggr_get_id) @@ -325,16 +326,16 @@ static int first_shadow_cpu(struct perf_stat_config *config, return 0; for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) { - int cpu2 = perf_evsel__cpus(evsel)->map[i]; + int cpu2 = evsel__cpus(evsel)->map[i]; - if (config->aggr_get_id(config, evlist->cpus, cpu2) == id) + if (config->aggr_get_id(config, evlist->core.cpus, cpu2) == id) return cpu2; } return 0; } static void abs_printout(struct perf_stat_config *config, - int id, int nr, struct perf_evsel *evsel, double avg) + int id, int nr, struct evsel *evsel, double avg) { FILE *output = config->output; double sc = evsel->scale; @@ -363,24 +364,24 @@ static void abs_printout(struct perf_stat_config *config, print_cgroup(config, evsel); } -static bool is_mixed_hw_group(struct perf_evsel *counter) +static bool is_mixed_hw_group(struct evsel *counter) { - struct perf_evlist *evlist = counter->evlist; - u32 pmu_type = counter->attr.type; - struct perf_evsel *pos; + struct evlist *evlist = counter->evlist; + u32 pmu_type = counter->core.attr.type; + struct evsel *pos; - if (counter->nr_members < 2) + if (counter->core.nr_members < 2) return false; evlist__for_each_entry(evlist, pos) { /* software events can be part of any hardware group */ - if (pos->attr.type == PERF_TYPE_SOFTWARE) + if (pos->core.attr.type == PERF_TYPE_SOFTWARE) continue; if (pmu_type == PERF_TYPE_SOFTWARE) { - pmu_type = pos->attr.type; + pmu_type = pos->core.attr.type; continue; } - if (pmu_type != pos->attr.type) + if (pmu_type != pos->core.attr.type) return true; } @@ -388,7 +389,7 @@ static bool is_mixed_hw_group(struct perf_evsel *counter) } static void printout(struct perf_stat_config *config, int id, int nr, - struct perf_evsel *counter, double uval, + struct evsel *counter, double uval, char *prefix, u64 run, u64 ena, double noise, struct runtime_stat *st) { @@ -489,18 +490,18 @@ static void printout(struct perf_stat_config *config, int id, int nr, } static void aggr_update_shadow(struct perf_stat_config *config, - struct perf_evlist *evlist) + struct evlist *evlist) { int cpu, s2, id, s; u64 val; - struct perf_evsel *counter; + struct evsel *counter; for (s = 0; s < config->aggr_map->nr; s++) { id = config->aggr_map->map[s]; evlist__for_each_entry(evlist, counter) { val = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { - s2 = config->aggr_get_id(config, evlist->cpus, cpu); + s2 = config->aggr_get_id(config, evlist->core.cpus, cpu); if (s2 != id) continue; val += perf_counts(counter->counts, cpu, 0)->val; @@ -512,7 +513,7 @@ static void aggr_update_shadow(struct perf_stat_config *config, } } -static void uniquify_event_name(struct perf_evsel *counter) +static void uniquify_event_name(struct evsel *counter) { char *new_name; char *config; @@ -540,16 +541,16 @@ static void uniquify_event_name(struct perf_evsel *counter) counter->uniquified_name = true; } -static void collect_all_aliases(struct perf_stat_config *config, struct perf_evsel *counter, - void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data, +static void collect_all_aliases(struct perf_stat_config *config, struct evsel *counter, + void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data, bool first), void *data) { - struct perf_evlist *evlist = counter->evlist; - struct perf_evsel *alias; + struct evlist *evlist = counter->evlist; + struct evsel *alias; - alias = list_prepare_entry(counter, &(evlist->entries), node); - list_for_each_entry_continue (alias, &evlist->entries, node) { + alias = list_prepare_entry(counter, &(evlist->core.entries), core.node); + list_for_each_entry_continue (alias, &evlist->core.entries, core.node) { if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) || alias->scale != counter->scale || alias->cgrp != counter->cgrp || @@ -562,8 +563,8 @@ static void collect_all_aliases(struct perf_stat_config *config, struct perf_evs } } -static bool collect_data(struct perf_stat_config *config, struct perf_evsel *counter, - void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data, +static bool collect_data(struct perf_stat_config *config, struct evsel *counter, + void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data, bool first), void *data) { @@ -585,7 +586,7 @@ struct aggr_data { }; static void aggr_cb(struct perf_stat_config *config, - struct perf_evsel *counter, void *data, bool first) + struct evsel *counter, void *data, bool first) { struct aggr_data *ad = data; int cpu, s2; @@ -593,7 +594,7 @@ static void aggr_cb(struct perf_stat_config *config, for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { struct perf_counts_values *counts; - s2 = config->aggr_get_id(config, perf_evsel__cpus(counter), cpu); + s2 = config->aggr_get_id(config, evsel__cpus(counter), cpu); if (s2 != ad->id) continue; if (first) @@ -616,7 +617,7 @@ static void aggr_cb(struct perf_stat_config *config, } static void print_counter_aggrdata(struct perf_stat_config *config, - struct perf_evsel *counter, int s, + struct evsel *counter, int s, char *prefix, bool metric_only, bool *first) { @@ -651,12 +652,12 @@ static void print_counter_aggrdata(struct perf_stat_config *config, } static void print_aggr(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, char *prefix) { bool metric_only = config->metric_only; FILE *output = config->output; - struct perf_evsel *counter; + struct evsel *counter; int s; bool first; @@ -691,7 +692,7 @@ static int cmp_val(const void *a, const void *b) } static struct perf_aggr_thread_value *sort_aggr_thread( - struct perf_evsel *counter, + struct evsel *counter, int nthreads, int ncpus, int *ret, struct target *_target) @@ -741,11 +742,11 @@ static struct perf_aggr_thread_value *sort_aggr_thread( static void print_aggr_thread(struct perf_stat_config *config, struct target *_target, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { FILE *output = config->output; - int nthreads = thread_map__nr(counter->threads); - int ncpus = cpu_map__nr(counter->cpus); + int nthreads = perf_thread_map__nr(counter->core.threads); + int ncpus = perf_cpu_map__nr(counter->core.cpus); int thread, sorted_threads, id; struct perf_aggr_thread_value *buf; @@ -779,7 +780,7 @@ struct caggr_data { }; static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused, - struct perf_evsel *counter, void *data, + struct evsel *counter, void *data, bool first __maybe_unused) { struct caggr_data *cd = data; @@ -795,7 +796,7 @@ static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused, * aggregated counts in system-wide mode */ static void print_counter_aggr(struct perf_stat_config *config, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { bool metric_only = config->metric_only; FILE *output = config->output; @@ -816,7 +817,7 @@ static void print_counter_aggr(struct perf_stat_config *config, } static void counter_cb(struct perf_stat_config *config __maybe_unused, - struct perf_evsel *counter, void *data, + struct evsel *counter, void *data, bool first __maybe_unused) { struct aggr_data *ad = data; @@ -831,7 +832,7 @@ static void counter_cb(struct perf_stat_config *config __maybe_unused, * does not use aggregated count in system-wide */ static void print_counter(struct perf_stat_config *config, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { FILE *output = config->output; u64 ena, run, val; @@ -859,16 +860,16 @@ static void print_counter(struct perf_stat_config *config, } static void print_no_aggr_metric(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, char *prefix) { int cpu; int nrcpus = 0; - struct perf_evsel *counter; + struct evsel *counter; u64 ena, run, val; double uval; - nrcpus = evlist->cpus->nr; + nrcpus = evlist->core.cpus->nr; for (cpu = 0; cpu < nrcpus; cpu++) { bool first = true; @@ -910,11 +911,11 @@ static const char *aggr_header_csv[] = { }; static void print_metric_headers(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, const char *prefix, bool no_indent) { struct perf_stat_output_ctx out; - struct perf_evsel *counter; + struct evsel *counter; struct outstate os = { .fh = config->output }; @@ -949,7 +950,7 @@ static void print_metric_headers(struct perf_stat_config *config, } static void print_interval(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, char *prefix, struct timespec *ts) { bool metric_only = config->metric_only; @@ -1132,7 +1133,7 @@ static void print_footer(struct perf_stat_config *config) } static void print_percore(struct perf_stat_config *config, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { bool metric_only = config->metric_only; FILE *output = config->output; @@ -1156,7 +1157,7 @@ static void print_percore(struct perf_stat_config *config, } void -perf_evlist__print_counters(struct perf_evlist *evlist, +perf_evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, struct target *_target, struct timespec *ts, @@ -1164,7 +1165,7 @@ perf_evlist__print_counters(struct perf_evlist *evlist, { bool metric_only = config->metric_only; int interval = config->interval; - struct perf_evsel *counter; + struct evsel *counter; char buf[64], *prefix = NULL; if (interval) diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index accb1bf1cfd8..70c87fdb2a43 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -25,12 +25,14 @@ struct stats walltime_nsecs_stats; struct saved_value { struct rb_node rb_node; - struct perf_evsel *evsel; + struct evsel *evsel; enum stat_type type; int ctx; int cpu; struct runtime_stat *stat; struct stats stats; + u64 metric_total; + int metric_other; }; static int saved_value_cmp(struct rb_node *rb_node, const void *entry) @@ -94,7 +96,7 @@ static void saved_value_delete(struct rblist *rblist __maybe_unused, free(v); } -static struct saved_value *saved_value_lookup(struct perf_evsel *evsel, +static struct saved_value *saved_value_lookup(struct evsel *evsel, int cpu, bool create, enum stat_type type, @@ -146,19 +148,19 @@ void perf_stat__init_shadow_stats(void) runtime_stat__init(&rt_stat); } -static int evsel_context(struct perf_evsel *evsel) +static int evsel_context(struct evsel *evsel) { int ctx = 0; - if (evsel->attr.exclude_kernel) + if (evsel->core.attr.exclude_kernel) ctx |= CTX_BIT_KERNEL; - if (evsel->attr.exclude_user) + if (evsel->core.attr.exclude_user) ctx |= CTX_BIT_USER; - if (evsel->attr.exclude_hv) + if (evsel->core.attr.exclude_hv) ctx |= CTX_BIT_HV; - if (evsel->attr.exclude_host) + if (evsel->core.attr.exclude_host) ctx |= CTX_BIT_HOST; - if (evsel->attr.exclude_idle) + if (evsel->core.attr.exclude_idle) ctx |= CTX_BIT_IDLE; return ctx; @@ -207,11 +209,12 @@ static void update_runtime_stat(struct runtime_stat *st, * more semantic information such as miss/hit ratios, * instruction rates, etc: */ -void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count, +void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int cpu, struct runtime_stat *st) { int ctx = evsel_context(counter); u64 count_ns = count; + struct saved_value *v; count *= counter->scale; @@ -266,9 +269,15 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count, update_runtime_stat(st, STAT_APERF, ctx, cpu, count); if (counter->collect_stat) { - struct saved_value *v = saved_value_lookup(counter, cpu, true, - STAT_NONE, 0, st); + v = saved_value_lookup(counter, cpu, true, STAT_NONE, 0, st); update_stats(&v->stats, count); + if (counter->metric_leader) + v->metric_total += count; + } else if (counter->metric_leader) { + v = saved_value_lookup(counter->metric_leader, + cpu, true, STAT_NONE, 0, st); + v->metric_total += count; + v->metric_other++; } } @@ -299,10 +308,10 @@ static const char *get_ratio_color(enum grc_type type, double ratio) return color; } -static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list, +static struct evsel *perf_stat__find_event(struct evlist *evsel_list, const char *name) { - struct perf_evsel *c2; + struct evsel *c2; evlist__for_each_entry (evsel_list, c2) { if (!strcasecmp(c2->name, name) && !c2->collect_stat) @@ -312,9 +321,9 @@ static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list, } /* Mark MetricExpr target events and link events using them to them. */ -void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list) +void perf_stat__collect_metric_expr(struct evlist *evsel_list) { - struct perf_evsel *counter, *leader, **metric_events, *oc; + struct evsel *counter, *leader, **metric_events, *oc; bool found; const char **metric_names; int i; @@ -332,7 +341,7 @@ void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list) &metric_names, &num_metric_names) < 0) continue; - metric_events = calloc(sizeof(struct perf_evsel *), + metric_events = calloc(sizeof(struct evsel *), num_metric_names + 1); if (!metric_events) return; @@ -415,7 +424,7 @@ static double runtime_stat_n(struct runtime_stat *st, static void print_stalled_cycles_frontend(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, double avg, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) { @@ -439,7 +448,7 @@ static void print_stalled_cycles_frontend(struct perf_stat_config *config, static void print_stalled_cycles_backend(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, double avg, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) { @@ -459,7 +468,7 @@ static void print_stalled_cycles_backend(struct perf_stat_config *config, static void print_branch_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -480,7 +489,7 @@ static void print_branch_misses(struct perf_stat_config *config, static void print_l1_dcache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -502,7 +511,7 @@ static void print_l1_dcache_misses(struct perf_stat_config *config, static void print_l1_icache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -523,7 +532,7 @@ static void print_l1_icache_misses(struct perf_stat_config *config, static void print_dtlb_cache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -543,7 +552,7 @@ static void print_dtlb_cache_misses(struct perf_stat_config *config, static void print_itlb_cache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -563,7 +572,7 @@ static void print_itlb_cache_misses(struct perf_stat_config *config, static void print_ll_cache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -686,7 +695,7 @@ static double td_be_bound(int ctx, int cpu, struct runtime_stat *st) } static void print_smi_cost(struct perf_stat_config *config, - int cpu, struct perf_evsel *evsel, + int cpu, struct evsel *evsel, struct perf_stat_output_ctx *out, struct runtime_stat *st) { @@ -712,9 +721,10 @@ static void print_smi_cost(struct perf_stat_config *config, static void generic_metric(struct perf_stat_config *config, const char *metric_expr, - struct perf_evsel **metric_events, + struct evsel **metric_events, char *name, const char *metric_name, + const char *metric_unit, double avg, int cpu, struct perf_stat_output_ctx *out, @@ -722,17 +732,16 @@ static void generic_metric(struct perf_stat_config *config, { print_metric_t print_metric = out->print_metric; struct parse_ctx pctx; - double ratio; + double ratio, scale; int i; void *ctxp = out->ctx; char *n, *pn; expr__ctx_init(&pctx); - expr__add_id(&pctx, name, avg); for (i = 0; metric_events[i]; i++) { struct saved_value *v; struct stats *stats; - double scale; + u64 metric_total = 0; if (!strcmp(metric_events[i]->name, "duration_time")) { stats = &walltime_nsecs_stats; @@ -744,6 +753,9 @@ static void generic_metric(struct perf_stat_config *config, break; stats = &v->stats; scale = 1.0; + + if (v->metric_other) + metric_total = v->metric_total; } n = strdup(metric_events[i]->name); @@ -757,21 +769,44 @@ static void generic_metric(struct perf_stat_config *config, pn = strchr(n, ' '); if (pn) *pn = 0; - expr__add_id(&pctx, n, avg_stats(stats)*scale); + + if (metric_total) + expr__add_id(&pctx, n, metric_total); + else + expr__add_id(&pctx, n, avg_stats(stats)*scale); } + + expr__add_id(&pctx, name, avg); + if (!metric_events[i]) { const char *p = metric_expr; - if (expr__parse(&ratio, &pctx, &p) == 0) - print_metric(config, ctxp, NULL, "%8.1f", - metric_name ? - metric_name : - out->force_header ? name : "", - ratio); - else + if (expr__parse(&ratio, &pctx, &p) == 0) { + char *unit; + char metric_bf[64]; + + if (metric_unit && metric_name) { + if (perf_pmu__convert_scale(metric_unit, + &unit, &scale) >= 0) { + ratio *= scale; + } + + scnprintf(metric_bf, sizeof(metric_bf), + "%s %s", unit, metric_name); + print_metric(config, ctxp, NULL, "%8.1f", + metric_bf, ratio); + } else { + print_metric(config, ctxp, NULL, "%8.1f", + metric_name ? + metric_name : + out->force_header ? name : "", + ratio); + } + } else { print_metric(config, ctxp, NULL, NULL, out->force_header ? (metric_name ? metric_name : name) : "", 0); + } } else print_metric(config, ctxp, NULL, NULL, "", 0); @@ -780,7 +815,7 @@ static void generic_metric(struct perf_stat_config *config, } void perf_stat__print_shadow_stats(struct perf_stat_config *config, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out, struct rblist *metric_events, @@ -829,8 +864,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all branches", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1D | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -839,8 +874,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all L1-dcache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1I | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -849,8 +884,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all L1-icache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_DTLB | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -859,8 +894,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all dTLB cache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_ITLB | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -869,8 +904,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all iTLB cache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_LL | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -992,7 +1027,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, print_metric(config, ctxp, NULL, NULL, name, 0); } else if (evsel->metric_expr) { generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name, - evsel->metric_name, avg, cpu, out, st); + evsel->metric_name, NULL, avg, cpu, out, st); } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) { char unit = 'M'; char unit_buf[10]; @@ -1021,7 +1056,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, out->new_line(config, ctxp); generic_metric(config, mexp->metric_expr, mexp->metric_events, evsel->name, mexp->metric_name, - avg, cpu, out, st); + mexp->metric_unit, avg, cpu, out, st); } } if (num == 0) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index db8a6cf336be..8f1ea27f976f 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -2,7 +2,13 @@ #include <errno.h> #include <inttypes.h> #include <math.h> +#include <string.h> +#include "counts.h" +#include "debug.h" +#include "header.h" #include "stat.h" +#include "session.h" +#include "target.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" @@ -68,7 +74,7 @@ double rel_stddev_stats(double stddev, double avg) return pct; } -bool __perf_evsel_stat__is(struct perf_evsel *evsel, +bool __perf_evsel_stat__is(struct evsel *evsel, enum perf_stat_evsel_id id) { struct perf_stat_evsel *ps = evsel->stats; @@ -93,7 +99,7 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { }; #undef ID -static void perf_stat_evsel_id_init(struct perf_evsel *evsel) +static void perf_stat_evsel_id_init(struct evsel *evsel) { struct perf_stat_evsel *ps = evsel->stats; int i; @@ -108,7 +114,7 @@ static void perf_stat_evsel_id_init(struct perf_evsel *evsel) } } -static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) +static void perf_evsel__reset_stat_priv(struct evsel *evsel) { int i; struct perf_stat_evsel *ps = evsel->stats; @@ -119,7 +125,7 @@ static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) perf_stat_evsel_id_init(evsel); } -static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) +static int perf_evsel__alloc_stat_priv(struct evsel *evsel) { evsel->stats = zalloc(sizeof(struct perf_stat_evsel)); if (evsel->stats == NULL) @@ -128,7 +134,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) return 0; } -static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) +static void perf_evsel__free_stat_priv(struct evsel *evsel) { struct perf_stat_evsel *ps = evsel->stats; @@ -137,7 +143,7 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) zfree(&evsel->stats); } -static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, +static int perf_evsel__alloc_prev_raw_counts(struct evsel *evsel, int ncpus, int nthreads) { struct perf_counts *counts; @@ -149,16 +155,16 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, return counts ? 0 : -ENOMEM; } -static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) +static void perf_evsel__free_prev_raw_counts(struct evsel *evsel) { perf_counts__delete(evsel->prev_raw_counts); evsel->prev_raw_counts = NULL; } -static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) +static int perf_evsel__alloc_stats(struct evsel *evsel, bool alloc_raw) { int ncpus = perf_evsel__nr_cpus(evsel); - int nthreads = thread_map__nr(evsel->threads); + int nthreads = perf_thread_map__nr(evsel->core.threads); if (perf_evsel__alloc_stat_priv(evsel) < 0 || perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 || @@ -168,9 +174,9 @@ static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) return 0; } -int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) +int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (perf_evsel__alloc_stats(evsel, alloc_raw)) @@ -184,9 +190,9 @@ out_free: return -1; } -void perf_evlist__free_stats(struct perf_evlist *evlist) +void perf_evlist__free_stats(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { perf_evsel__free_stat_priv(evsel); @@ -195,9 +201,9 @@ void perf_evlist__free_stats(struct perf_evlist *evlist) } } -void perf_evlist__reset_stats(struct perf_evlist *evlist) +void perf_evlist__reset_stats(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { perf_evsel__reset_stat_priv(evsel); @@ -205,17 +211,17 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist) } } -static void zero_per_pkg(struct perf_evsel *counter) +static void zero_per_pkg(struct evsel *counter) { if (counter->per_pkg_mask) - memset(counter->per_pkg_mask, 0, MAX_NR_CPUS); + memset(counter->per_pkg_mask, 0, cpu__max_cpu()); } -static int check_per_pkg(struct perf_evsel *counter, +static int check_per_pkg(struct evsel *counter, struct perf_counts_values *vals, int cpu, bool *skip) { unsigned long *mask = counter->per_pkg_mask; - struct cpu_map *cpus = perf_evsel__cpus(counter); + struct perf_cpu_map *cpus = evsel__cpus(counter); int s; *skip = false; @@ -223,11 +229,11 @@ static int check_per_pkg(struct perf_evsel *counter, if (!counter->per_pkg) return 0; - if (cpu_map__empty(cpus)) + if (perf_cpu_map__empty(cpus)) return 0; if (!mask) { - mask = zalloc(MAX_NR_CPUS); + mask = zalloc(cpu__max_cpu()); if (!mask) return -ENOMEM; @@ -254,7 +260,7 @@ static int check_per_pkg(struct perf_evsel *counter, } static int -process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel, +process_counter_values(struct perf_stat_config *config, struct evsel *evsel, int cpu, int thread, struct perf_counts_values *count) { @@ -306,9 +312,9 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel } static int process_counter_maps(struct perf_stat_config *config, - struct perf_evsel *counter) + struct evsel *counter) { - int nthreads = thread_map__nr(counter->threads); + int nthreads = perf_thread_map__nr(counter->core.threads); int ncpus = perf_evsel__nr_cpus(counter); int cpu, thread; @@ -327,7 +333,7 @@ static int process_counter_maps(struct perf_stat_config *config, } int perf_stat_process_counter(struct perf_stat_config *config, - struct perf_evsel *counter) + struct evsel *counter) { struct perf_counts_values *aggr = &counter->counts->aggr; struct perf_stat_evsel *ps = counter->stats; @@ -380,8 +386,8 @@ int perf_event__process_stat_event(struct perf_session *session, union perf_event *event) { struct perf_counts_values count; - struct stat_event *st = &event->stat; - struct perf_evsel *counter; + struct perf_record_stat *st = &event->stat; + struct evsel *counter; count.val = st->val; count.ena = st->ena; @@ -400,12 +406,12 @@ int perf_event__process_stat_event(struct perf_session *session, size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) { - struct stat_event *st = (struct stat_event *) event; + struct perf_record_stat *st = (struct perf_record_stat *)event; size_t ret; - ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n", + ret = fprintf(fp, "\n... id %" PRI_lu64 ", cpu %d, thread %d\n", st->id, st->cpu, st->thread); - ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n", + ret += fprintf(fp, "... value %" PRI_lu64 ", enabled %" PRI_lu64 ", running %" PRI_lu64 "\n", st->val, st->ena, st->run); return ret; @@ -413,10 +419,10 @@ size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp) { - struct stat_round_event *rd = (struct stat_round_event *)event; + struct perf_record_stat_round *rd = (struct perf_record_stat_round *)event; size_t ret; - ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time, + ret = fprintf(fp, "\n... time %" PRI_lu64 ", type %s\n", rd->time, rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL"); return ret; @@ -437,12 +443,12 @@ size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) return ret; } -int create_perf_stat_counter(struct perf_evsel *evsel, +int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, struct target *target) { - struct perf_event_attr *attr = &evsel->attr; - struct perf_evsel *leader = evsel->leader; + struct perf_event_attr *attr = &evsel->core.attr; + struct evsel *leader = evsel->leader; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; @@ -452,7 +458,7 @@ int create_perf_stat_counter(struct perf_evsel *evsel, * the group read (for leader) and ID retrieval for all * members. */ - if (leader->nr_members > 1) + if (leader->core.nr_members > 1) attr->read_format |= PERF_FORMAT_ID|PERF_FORMAT_GROUP; attr->inherit = !config->no_inherit; @@ -483,14 +489,14 @@ int create_perf_stat_counter(struct perf_evsel *evsel, } if (target__has_cpu(target) && !target__has_per_thread(target)) - return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); + return perf_evsel__open_per_cpu(evsel, evsel__cpus(evsel)); - return perf_evsel__open_per_thread(evsel, evsel->threads); + return perf_evsel__open_per_thread(evsel, evsel->core.threads); } int perf_stat_synthesize_config(struct perf_stat_config *config, struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process, bool attrs) { @@ -507,14 +513,14 @@ int perf_stat_synthesize_config(struct perf_stat_config *config, err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); - err = perf_event__synthesize_thread_map2(tool, evlist->threads, + err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); if (err < 0) { pr_err("Couldn't synthesize thread map.\n"); return err; } - err = perf_event__synthesize_cpu_map(tool, evlist->cpus, + err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); if (err < 0) { pr_err("Couldn't synthesize thread map.\n"); diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 7032dd1eeac2..14fe3e548229 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -5,14 +5,12 @@ #include <linux/types.h> #include <stdio.h> #include <sys/types.h> -#include <sys/time.h> #include <sys/resource.h> -#include <sys/wait.h> -#include "xyarray.h" #include "rblist.h" -#include "perf.h" #include "event.h" +struct timespec; + struct stats { double n, mean, M2; u64 max, min; @@ -92,7 +90,7 @@ struct runtime_stat { }; typedef int (*aggr_get_id_t)(struct perf_stat_config *config, - struct cpu_map *m, int cpu); + struct perf_cpu_map *m, int cpu); struct perf_stat_config { enum aggr_mode aggr_mode; @@ -122,9 +120,9 @@ struct perf_stat_config { const char *csv_sep; struct stats *walltime_nsecs_stats; struct rusage ru_data; - struct cpu_map *aggr_map; + struct perf_cpu_map *aggr_map; aggr_get_id_t aggr_get_id; - struct cpu_map *cpus_aggr_map; + struct perf_cpu_map *cpus_aggr_map; u64 *walltime_run; struct rblist metric_events; }; @@ -143,11 +141,11 @@ static inline void init_stats(struct stats *stats) stats->max = 0; } -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct perf_aggr_thread_value { - struct perf_evsel *counter; + struct evsel *counter; int id; double uval; u64 val; @@ -155,7 +153,7 @@ struct perf_aggr_thread_value { u64 ena; }; -bool __perf_evsel_stat__is(struct perf_evsel *evsel, +bool __perf_evsel_stat__is(struct evsel *evsel, enum perf_stat_evsel_id id); #define perf_stat_evsel__is(evsel, id) \ @@ -174,7 +172,7 @@ void runtime_stat__exit(struct runtime_stat *st); void perf_stat__init_shadow_stats(void); void perf_stat__reset_shadow_stats(void); void perf_stat__reset_shadow_per_stat(struct runtime_stat *st); -void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count, +void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int cpu, struct runtime_stat *st); struct perf_stat_output_ctx { void *ctx; @@ -184,22 +182,24 @@ struct perf_stat_output_ctx { }; void perf_stat__print_shadow_stats(struct perf_stat_config *config, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out, struct rblist *metric_events, struct runtime_stat *st); -void perf_stat__collect_metric_expr(struct perf_evlist *); +void perf_stat__collect_metric_expr(struct evlist *); -int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); -void perf_evlist__free_stats(struct perf_evlist *evlist); -void perf_evlist__reset_stats(struct perf_evlist *evlist); +int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw); +void perf_evlist__free_stats(struct evlist *evlist); +void perf_evlist__reset_stats(struct evlist *evlist); int perf_stat_process_counter(struct perf_stat_config *config, - struct perf_evsel *counter); + struct evsel *counter); struct perf_tool; union perf_event; struct perf_session; +struct target; + int perf_event__process_stat_event(struct perf_session *session, union perf_event *event); @@ -207,16 +207,16 @@ size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp); size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp); size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); -int create_perf_stat_counter(struct perf_evsel *evsel, +int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, struct target *target); int perf_stat_synthesize_config(struct perf_stat_config *config, struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process, bool attrs); void -perf_evlist__print_counters(struct perf_evlist *evlist, +perf_evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, struct target *_target, struct timespec *ts, diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 2ce0dc887364..a64a37628f12 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 +#include "cache.h" #include "debug.h" +#include "strbuf.h" #include <linux/kernel.h> +#include <linux/string.h> #include <linux/zalloc.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> +#include <unistd.h> /* * Used as the default ->buf value, so that people can always assume diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 76cc54000483..582f4a69cd48 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -14,10 +14,12 @@ #include <unistd.h> #include <string.h> #include <linux/bitmap.h> +#include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> +#include <perf/cpumap.h> -#include "perf.h" +#include "env.h" #include "svghelper.h" #include "cpumap.h" @@ -694,7 +696,8 @@ struct topology { int sib_thr_nr; }; -static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos) +static void scan_thread_topology(int *map, struct topology *t, int cpu, + int *pos, int nr_cpus) { int i; int thr; @@ -703,41 +706,37 @@ static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i]))) continue; - for_each_set_bit(thr, - cpumask_bits(&t->sib_thr[i]), - MAX_NR_CPUS) + for_each_set_bit(thr, cpumask_bits(&t->sib_thr[i]), nr_cpus) if (map[thr] == -1) map[thr] = (*pos)++; } } -static void scan_core_topology(int *map, struct topology *t) +static void scan_core_topology(int *map, struct topology *t, int nr_cpus) { int pos = 0; int i; int cpu; for (i = 0; i < t->sib_core_nr; i++) - for_each_set_bit(cpu, - cpumask_bits(&t->sib_core[i]), - MAX_NR_CPUS) - scan_thread_topology(map, t, cpu, &pos); + for_each_set_bit(cpu, cpumask_bits(&t->sib_core[i]), nr_cpus) + scan_thread_topology(map, t, cpu, &pos, nr_cpus); } -static int str_to_bitmap(char *s, cpumask_t *b) +static int str_to_bitmap(char *s, cpumask_t *b, int nr_cpus) { int i; int ret = 0; - struct cpu_map *m; + struct perf_cpu_map *m; int c; - m = cpu_map__new(s); + m = perf_cpu_map__new(s); if (!m) return -1; for (i = 0; i < m->nr; i++) { c = m->map[i]; - if (c >= MAX_NR_CPUS) { + if (c >= nr_cpus) { ret = -1; break; } @@ -745,29 +744,34 @@ static int str_to_bitmap(char *s, cpumask_t *b) set_bit(c, cpumask_bits(b)); } - cpu_map__put(m); + perf_cpu_map__put(m); return ret; } -int svg_build_topology_map(char *sib_core, int sib_core_nr, - char *sib_thr, int sib_thr_nr) +int svg_build_topology_map(struct perf_env *env) { - int i; + int i, nr_cpus; struct topology t; + char *sib_core, *sib_thr; + + nr_cpus = min(env->nr_cpus_online, MAX_NR_CPUS); + + t.sib_core_nr = env->nr_sibling_cores; + t.sib_thr_nr = env->nr_sibling_threads; + t.sib_core = calloc(env->nr_sibling_cores, sizeof(cpumask_t)); + t.sib_thr = calloc(env->nr_sibling_threads, sizeof(cpumask_t)); - t.sib_core_nr = sib_core_nr; - t.sib_thr_nr = sib_thr_nr; - t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t)); - t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t)); + sib_core = env->sibling_cores; + sib_thr = env->sibling_threads; if (!t.sib_core || !t.sib_thr) { fprintf(stderr, "topology: no memory\n"); goto exit; } - for (i = 0; i < sib_core_nr; i++) { - if (str_to_bitmap(sib_core, &t.sib_core[i])) { + for (i = 0; i < env->nr_sibling_cores; i++) { + if (str_to_bitmap(sib_core, &t.sib_core[i], nr_cpus)) { fprintf(stderr, "topology: can't parse siblings map\n"); goto exit; } @@ -775,8 +779,8 @@ int svg_build_topology_map(char *sib_core, int sib_core_nr, sib_core += strlen(sib_core) + 1; } - for (i = 0; i < sib_thr_nr; i++) { - if (str_to_bitmap(sib_thr, &t.sib_thr[i])) { + for (i = 0; i < env->nr_sibling_threads; i++) { + if (str_to_bitmap(sib_thr, &t.sib_thr[i], nr_cpus)) { fprintf(stderr, "topology: can't parse siblings map\n"); goto exit; } @@ -784,16 +788,16 @@ int svg_build_topology_map(char *sib_core, int sib_core_nr, sib_thr += strlen(sib_thr) + 1; } - topology_map = malloc(sizeof(int) * MAX_NR_CPUS); + topology_map = malloc(sizeof(int) * nr_cpus); if (!topology_map) { fprintf(stderr, "topology: no memory\n"); goto exit; } - for (i = 0; i < MAX_NR_CPUS; i++) + for (i = 0; i < nr_cpus; i++) topology_map[i] = -1; - scan_core_topology(topology_map, &t); + scan_core_topology(topology_map, &t, nr_cpus); return 0; diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index e55338d5c3bd..81823e8bae3e 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -4,6 +4,8 @@ #include <linux/types.h> +struct perf_env; + void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); @@ -28,7 +30,7 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc void svg_interrupt(u64 start, int row, const char *backtrace); void svg_text(int Yslot, u64 start, const char *text); void svg_close(void); -int svg_build_topology_map(char *sib_core, int sib_core_nr, char *sib_thr, int sib_thr_nr); +int svg_build_topology_map(struct perf_env *env); extern int svg_page_width; extern u64 svg_highlight; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 7d504dc22108..9428639872a6 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -10,6 +10,7 @@ #include "map.h" #include "map_groups.h" #include "symbol.h" +#include "symsrc.h" #include "demangle-java.h" #include "demangle-rust.h" #include "machine.h" @@ -40,6 +41,12 @@ typedef Elf64_Nhdr GElf_Nhdr; +#ifndef DMGL_PARAMS +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#endif + #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT extern char *cplus_demangle(const char *, int); diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 3bc8b7e3300e..7e2813ec9498 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 +#include "dso.h" #include "symbol.h" +#include "symsrc.h" #include "util.h" #include <errno.h> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4efde7879474..765c75df2904 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -4,8 +4,10 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <linux/capability.h> #include <linux/kernel.h> #include <linux/mman.h> +#include <linux/string.h> #include <linux/time64.h> #include <sys/types.h> #include <sys/stat.h> @@ -15,11 +17,17 @@ #include <inttypes.h> #include "annotate.h" #include "build-id.h" +#include "cap.h" +#include "dso.h" #include "util.h" #include "debug.h" +#include "event.h" #include "machine.h" #include "map.h" #include "symbol.h" +#include "map_symbol.h" +#include "mem-events.h" +#include "symsrc.h" #include "strlist.h" #include "intlist.h" #include "namespaces.h" @@ -2195,13 +2203,19 @@ static bool symbol__read_kptr_restrict(void) char line[8]; if (fgets(line, sizeof(line), fp) != NULL) - value = ((geteuid() != 0) || (getuid() != 0)) ? - (atoi(line) != 0) : - (atoi(line) == 2); + value = perf_cap__capable(CAP_SYSLOG) ? + (atoi(line) >= 2) : + (atoi(line) != 0); fclose(fp); } + /* Per kernel/kallsyms.c: + * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG + */ + if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) + value = true; + return value; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 183f630cb5f1..0b0c6b5b1899 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -3,13 +3,12 @@ #define __PERF_SYMBOL 1 #include <linux/types.h> +#include <linux/refcount.h> #include <stdbool.h> #include <stdint.h> #include <linux/list.h> #include <linux/rbtree.h> #include <stdio.h> -#include "map_symbol.h" -#include "branch.h" #include "path.h" #include "symbol_conf.h" @@ -19,8 +18,7 @@ #endif #include <elf.h> -#include "dso.h" - +struct dso; struct map; struct map_groups; struct option; @@ -40,15 +38,6 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, GElf_Shdr *shp, const char *name, size_t *idx); #endif -#ifndef DMGL_PARAMS -#define DMGL_NO_OPTS 0 /* For readability... */ -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#endif - -#define DSO__NAME_KALLSYMS "[kernel.kallsyms]" -#define DSO__NAME_KCORE "[kernel.kcore]" - /** struct symbol - symtab entry * * @ignore - resolvable but tools ignore it (e.g. idle routines) @@ -116,21 +105,6 @@ struct ref_reloc_sym { u64 unrelocated_addr; }; -struct branch_info { - struct addr_map_symbol from; - struct addr_map_symbol to; - struct branch_flags flags; - char *srcline_from; - char *srcline_to; -}; - -struct mem_info { - struct addr_map_symbol iaddr; - struct addr_map_symbol daddr; - union perf_mem_data_src data_src; - refcount_t refcnt; -}; - struct block_info { struct symbol *sym; u64 start; @@ -156,37 +130,6 @@ struct addr_location { s32 socket; }; -struct symsrc { - char *name; - int fd; - enum dso_binary_type type; - -#ifdef HAVE_LIBELF_SUPPORT - Elf *elf; - GElf_Ehdr ehdr; - - Elf_Scn *opdsec; - size_t opdidx; - GElf_Shdr opdshdr; - - Elf_Scn *symtab; - GElf_Shdr symshdr; - - Elf_Scn *dynsym; - size_t dynsym_idx; - GElf_Shdr dynshdr; - - bool adjust_symbols; - bool is_64_bit; -#endif -}; - -void symsrc__destroy(struct symsrc *ss); -int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, - enum dso_binary_type type); -bool symsrc__has_symtab(struct symsrc *ss); -bool symsrc__possibly_runtime(struct symsrc *ss); - int dso__load(struct dso *dso, struct map *map); int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, bool vmlinux_allocated); @@ -240,6 +183,8 @@ bool symbol__restricted_filename(const char *filename, int symbol__config_symfs(const struct option *opt __maybe_unused, const char *dir, int unset __maybe_unused); +struct symsrc; + int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, struct symsrc *runtime_ss, int kmodule); int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss); diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c index 02e89b02c2ce..35c936ce33ef 100644 --- a/tools/perf/util/symbol_fprintf.c +++ b/tools/perf/util/symbol_fprintf.c @@ -3,6 +3,7 @@ #include <inttypes.h> #include <stdio.h> +#include "dso.h" #include "map.h" #include "symbol.h" diff --git a/tools/perf/util/symsrc.h b/tools/perf/util/symsrc.h new file mode 100644 index 000000000000..2665b4bde751 --- /dev/null +++ b/tools/perf/util/symsrc.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_SYMSRC_ +#define __PERF_SYMSRC_ 1 + +#include <stdbool.h> +#include <stddef.h> +#include "dso.h" + +#ifdef HAVE_LIBELF_SUPPORT +#include <libelf.h> +#include <gelf.h> +#endif +#include <elf.h> + +struct symsrc { + char *name; + int fd; + enum dso_binary_type type; + +#ifdef HAVE_LIBELF_SUPPORT + Elf *elf; + GElf_Ehdr ehdr; + + Elf_Scn *opdsec; + size_t opdidx; + GElf_Shdr opdshdr; + + Elf_Scn *symtab; + GElf_Shdr symshdr; + + Elf_Scn *dynsym; + size_t dynsym_idx; + GElf_Shdr dynshdr; + + bool adjust_symbols; + bool is_64_bit; +#endif +}; + +int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, enum dso_binary_type type); +void symsrc__destroy(struct symsrc *ss); + +bool symsrc__has_symtab(struct symsrc *ss); +bool symsrc__possibly_runtime(struct symsrc *ss); + +#endif /* __PERF_SYMSRC_ */ diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index 022a9c670338..820fceeb19a9 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c @@ -79,6 +79,7 @@ static int syscalltbl__init_native(struct syscalltbl *tbl) qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp); tbl->syscalls.nr_entries = nr_entries; + tbl->syscalls.max_id = syscalltbl_native_max_id; return 0; } diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h index c8e7e9ce0f01..9172613028d0 100644 --- a/tools/perf/util/syscalltbl.h +++ b/tools/perf/util/syscalltbl.h @@ -6,6 +6,7 @@ struct syscalltbl { union { int audit_machine; struct { + int max_id; int nr_entries; void *entries; } syscalls; diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 3adc65480349..565f7aef7e6c 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -10,8 +10,11 @@ #include "debug.h" #include <pwd.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <linux/kernel.h> +#include <linux/string.h> enum target_errno target__validate(struct target *target) { diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index 15134ac9b8f1..cd8a948d03ec 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c @@ -10,6 +10,7 @@ #include <linux/zalloc.h> #include <errno.h> #include <stdlib.h> +#include <string.h> #include "thread.h" #include "event.h" #include "machine.h" diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 590793cc5142..b64e9e049636 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../perf.h" #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <linux/kernel.h> #include <linux/zalloc.h> +#include "dso.h" #include "session.h" #include "thread.h" #include "thread-stack.h" @@ -105,7 +105,6 @@ void thread__delete(struct thread *thread) } up_write(&thread->comm_lock); - unwind__finish_access(thread); nsinfo__zput(thread->nsinfo); srccode_state_free(&thread->srccode_state); @@ -170,7 +169,7 @@ struct namespaces *thread__namespaces(struct thread *thread) } static int __thread__set_namespaces(struct thread *thread, u64 timestamp, - struct namespaces_event *event) + struct perf_record_namespaces *event) { struct namespaces *new, *curr = __thread__namespaces(thread); @@ -194,7 +193,7 @@ static int __thread__set_namespaces(struct thread *thread, u64 timestamp, } int thread__set_namespaces(struct thread *thread, u64 timestamp, - struct namespaces_event *event) + struct perf_record_namespaces *event) { int ret; @@ -252,7 +251,7 @@ static int ____thread__set_comm(struct thread *thread, const char *str, list_add(&new->list, &thread->comm_list); if (exec) - unwind__flush_access(thread); + unwind__flush_access(thread->mg); } thread->comm_set = true; @@ -332,7 +331,7 @@ int thread__insert_map(struct thread *thread, struct map *map) { int ret; - ret = unwind__prepare_access(thread, map, NULL); + ret = unwind__prepare_access(thread->mg, map, NULL); if (ret) return ret; @@ -352,7 +351,7 @@ static int __thread__prepare_access(struct thread *thread) down_read(&maps->lock); for (map = maps__first(maps); map; map = map__next(map)) { - err = unwind__prepare_access(thread, map, &initialized); + err = unwind__prepare_access(thread->mg, map, &initialized); if (err || initialized) break; } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e97ef6977eb9..51bdb9a7af7f 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -16,7 +16,7 @@ struct addr_location; struct map; -struct namespaces_event; +struct perf_record_namespaces; struct thread_stack; struct unwind_libunwind_ops; @@ -44,10 +44,6 @@ struct thread { struct thread_stack *ts; struct nsinfo *nsinfo; struct srccode_state srccode_state; -#ifdef HAVE_LIBUNWIND_SUPPORT - void *addr_space; - struct unwind_libunwind_ops *unwind_libunwind_ops; -#endif bool filter; int filter_entry_depth; }; @@ -78,7 +74,7 @@ static inline void thread__exited(struct thread *thread) struct namespaces *thread__namespaces(struct thread *thread); int thread__set_namespaces(struct thread *thread, u64 timestamp, - struct namespaces_event *event); + struct perf_record_namespaces *event); int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, bool exec); diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 5b3511f2b6b1..c9bfe4696943 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -28,34 +28,11 @@ static int filter(const struct dirent *dir) return 1; } -static void thread_map__reset(struct thread_map *map, int start, int nr) -{ - size_t size = (nr - start) * sizeof(map->map[0]); - - memset(&map->map[start], 0, size); - map->err_thread = -1; -} +#define thread_map__alloc(__nr) perf_thread_map__realloc(NULL, __nr) -static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) +struct perf_thread_map *thread_map__new_by_pid(pid_t pid) { - size_t size = sizeof(*map) + sizeof(map->map[0]) * nr; - int start = map ? map->nr : 0; - - map = realloc(map, size); - /* - * We only realloc to add more items, let's reset new items. - */ - if (map) - thread_map__reset(map, start, nr); - - return map; -} - -#define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) - -struct thread_map *thread_map__new_by_pid(pid_t pid) -{ - struct thread_map *threads; + struct perf_thread_map *threads; char name[256]; int items; struct dirent **namelist = NULL; @@ -69,7 +46,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) threads = thread_map__alloc(items); if (threads != NULL) { for (i = 0; i < items; i++) - thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); + perf_thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); threads->nr = items; refcount_set(&threads->refcnt, 1); } @@ -81,12 +58,12 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) return threads; } -struct thread_map *thread_map__new_by_tid(pid_t tid) +struct perf_thread_map *thread_map__new_by_tid(pid_t tid) { - struct thread_map *threads = thread_map__alloc(1); + struct perf_thread_map *threads = thread_map__alloc(1); if (threads != NULL) { - thread_map__set_pid(threads, 0, tid); + perf_thread_map__set_pid(threads, 0, tid); threads->nr = 1; refcount_set(&threads->refcnt, 1); } @@ -94,13 +71,13 @@ struct thread_map *thread_map__new_by_tid(pid_t tid) return threads; } -static struct thread_map *__thread_map__new_all_cpus(uid_t uid) +static struct perf_thread_map *__thread_map__new_all_cpus(uid_t uid) { DIR *proc; int max_threads = 32, items, i; char path[NAME_MAX + 1 + 6]; struct dirent *dirent, **namelist = NULL; - struct thread_map *threads = thread_map__alloc(max_threads); + struct perf_thread_map *threads = thread_map__alloc(max_threads); if (threads == NULL) goto out; @@ -140,9 +117,9 @@ static struct thread_map *__thread_map__new_all_cpus(uid_t uid) } if (grow) { - struct thread_map *tmp; + struct perf_thread_map *tmp; - tmp = thread_map__realloc(threads, max_threads); + tmp = perf_thread_map__realloc(threads, max_threads); if (tmp == NULL) goto out_free_namelist; @@ -150,8 +127,8 @@ static struct thread_map *__thread_map__new_all_cpus(uid_t uid) } for (i = 0; i < items; i++) { - thread_map__set_pid(threads, threads->nr + i, - atoi(namelist[i]->d_name)); + perf_thread_map__set_pid(threads, threads->nr + i, + atoi(namelist[i]->d_name)); } for (i = 0; i < items; i++) @@ -180,17 +157,17 @@ out_free_closedir: goto out_closedir; } -struct thread_map *thread_map__new_all_cpus(void) +struct perf_thread_map *thread_map__new_all_cpus(void) { return __thread_map__new_all_cpus(UINT_MAX); } -struct thread_map *thread_map__new_by_uid(uid_t uid) +struct perf_thread_map *thread_map__new_by_uid(uid_t uid) { return __thread_map__new_all_cpus(uid); } -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) +struct perf_thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) { if (pid != -1) return thread_map__new_by_pid(pid); @@ -201,9 +178,9 @@ struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) return thread_map__new_by_tid(tid); } -static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) +static struct perf_thread_map *thread_map__new_by_pid_str(const char *pid_str) { - struct thread_map *threads = NULL, *nt; + struct perf_thread_map *threads = NULL, *nt; char name[256]; int items, total_tasks = 0; struct dirent **namelist = NULL; @@ -233,14 +210,14 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) goto out_free_threads; total_tasks += items; - nt = thread_map__realloc(threads, total_tasks); + nt = perf_thread_map__realloc(threads, total_tasks); if (nt == NULL) goto out_free_namelist; threads = nt; for (i = 0; i < items; i++) { - thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name)); + perf_thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name)); zfree(&namelist[i]); } threads->nr = total_tasks; @@ -263,21 +240,9 @@ out_free_threads: goto out; } -struct thread_map *thread_map__new_dummy(void) -{ - struct thread_map *threads = thread_map__alloc(1); - - if (threads != NULL) { - thread_map__set_pid(threads, 0, -1); - threads->nr = 1; - refcount_set(&threads->refcnt, 1); - } - return threads; -} - -struct thread_map *thread_map__new_by_tid_str(const char *tid_str) +struct perf_thread_map *thread_map__new_by_tid_str(const char *tid_str) { - struct thread_map *threads = NULL, *nt; + struct perf_thread_map *threads = NULL, *nt; int ntasks = 0; pid_t tid, prev_tid = INT_MAX; char *end_ptr; @@ -287,7 +252,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) /* perf-stat expects threads to be generated even if tid not given */ if (!tid_str) - return thread_map__new_dummy(); + return perf_thread_map__new_dummy(); slist = strlist__new(tid_str, &slist_config); if (!slist) @@ -304,13 +269,13 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) continue; ntasks++; - nt = thread_map__realloc(threads, ntasks); + nt = perf_thread_map__realloc(threads, ntasks); if (nt == NULL) goto out_free_threads; threads = nt; - thread_map__set_pid(threads, ntasks - 1, tid); + perf_thread_map__set_pid(threads, ntasks - 1, tid); threads->nr = ntasks; } out: @@ -324,7 +289,7 @@ out_free_threads: goto out; } -struct thread_map *thread_map__new_str(const char *pid, const char *tid, +struct perf_thread_map *thread_map__new_str(const char *pid, const char *tid, uid_t uid, bool all_threads) { if (pid) @@ -339,39 +304,13 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid, return thread_map__new_by_tid_str(tid); } -static void thread_map__delete(struct thread_map *threads) -{ - if (threads) { - int i; - - WARN_ONCE(refcount_read(&threads->refcnt) != 0, - "thread map refcnt unbalanced\n"); - for (i = 0; i < threads->nr; i++) - free(thread_map__comm(threads, i)); - free(threads); - } -} - -struct thread_map *thread_map__get(struct thread_map *map) -{ - if (map) - refcount_inc(&map->refcnt); - return map; -} - -void thread_map__put(struct thread_map *map) -{ - if (map && refcount_dec_and_test(&map->refcnt)) - thread_map__delete(map); -} - -size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) +size_t thread_map__fprintf(struct perf_thread_map *threads, FILE *fp) { int i; size_t printed = fprintf(fp, "%d thread%s: ", threads->nr, threads->nr > 1 ? "s" : ""); for (i = 0; i < threads->nr; ++i) - printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i)); + printed += fprintf(fp, "%s%d", i ? ", " : "", perf_thread_map__pid(threads, i)); return printed + fprintf(fp, "\n"); } @@ -400,9 +339,9 @@ static int get_comm(char **comm, pid_t pid) return err; } -static void comm_init(struct thread_map *map, int i) +static void comm_init(struct perf_thread_map *map, int i) { - pid_t pid = thread_map__pid(map, i); + pid_t pid = perf_thread_map__pid(map, i); char *comm = NULL; /* dummy pid comm initialization */ @@ -421,7 +360,7 @@ static void comm_init(struct thread_map *map, int i) map->map[i].comm = comm; } -void thread_map__read_comms(struct thread_map *threads) +void thread_map__read_comms(struct perf_thread_map *threads) { int i; @@ -429,24 +368,24 @@ void thread_map__read_comms(struct thread_map *threads) comm_init(threads, i); } -static void thread_map__copy_event(struct thread_map *threads, - struct thread_map_event *event) +static void thread_map__copy_event(struct perf_thread_map *threads, + struct perf_record_thread_map *event) { unsigned i; threads->nr = (int) event->nr; for (i = 0; i < event->nr; i++) { - thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid); + perf_thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid); threads->map[i].comm = strndup(event->entries[i].comm, 16); } refcount_set(&threads->refcnt, 1); } -struct thread_map *thread_map__new_event(struct thread_map_event *event) +struct perf_thread_map *thread_map__new_event(struct perf_record_thread_map *event) { - struct thread_map *threads; + struct perf_thread_map *threads; threads = thread_map__alloc(event->nr); if (threads) @@ -455,7 +394,7 @@ struct thread_map *thread_map__new_event(struct thread_map_event *event) return threads; } -bool thread_map__has(struct thread_map *threads, pid_t pid) +bool thread_map__has(struct perf_thread_map *threads, pid_t pid) { int i; @@ -467,7 +406,7 @@ bool thread_map__has(struct thread_map *threads, pid_t pid) return false; } -int thread_map__remove(struct thread_map *threads, int idx) +int thread_map__remove(struct perf_thread_map *threads, int idx) { int i; diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 2f689c90a8c6..3bb860a32b8e 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h @@ -5,61 +5,27 @@ #include <sys/types.h> #include <stdio.h> #include <linux/refcount.h> +#include <internal/threadmap.h> +#include <perf/threadmap.h> -struct thread_map_data { - pid_t pid; - char *comm; -}; +struct perf_record_thread_map; -struct thread_map { - refcount_t refcnt; - int nr; - int err_thread; - struct thread_map_data map[]; -}; +struct perf_thread_map *thread_map__new_dummy(void); +struct perf_thread_map *thread_map__new_by_pid(pid_t pid); +struct perf_thread_map *thread_map__new_by_tid(pid_t tid); +struct perf_thread_map *thread_map__new_by_uid(uid_t uid); +struct perf_thread_map *thread_map__new_all_cpus(void); +struct perf_thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); +struct perf_thread_map *thread_map__new_event(struct perf_record_thread_map *event); -struct thread_map_event; - -struct thread_map *thread_map__new_dummy(void); -struct thread_map *thread_map__new_by_pid(pid_t pid); -struct thread_map *thread_map__new_by_tid(pid_t tid); -struct thread_map *thread_map__new_by_uid(uid_t uid); -struct thread_map *thread_map__new_all_cpus(void); -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); -struct thread_map *thread_map__new_event(struct thread_map_event *event); - -struct thread_map *thread_map__get(struct thread_map *map); -void thread_map__put(struct thread_map *map); - -struct thread_map *thread_map__new_str(const char *pid, +struct perf_thread_map *thread_map__new_str(const char *pid, const char *tid, uid_t uid, bool all_threads); -struct thread_map *thread_map__new_by_tid_str(const char *tid_str); - -size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); - -static inline int thread_map__nr(struct thread_map *threads) -{ - return threads ? threads->nr : 1; -} - -static inline pid_t thread_map__pid(struct thread_map *map, int thread) -{ - return map->map[thread].pid; -} - -static inline void -thread_map__set_pid(struct thread_map *map, int thread, pid_t pid) -{ - map->map[thread].pid = pid; -} +struct perf_thread_map *thread_map__new_by_tid_str(const char *tid_str); -static inline char *thread_map__comm(struct thread_map *map, int thread) -{ - return map->map[thread].comm; -} +size_t thread_map__fprintf(struct perf_thread_map *threads, FILE *fp); -void thread_map__read_comms(struct thread_map *threads); -bool thread_map__has(struct thread_map *threads, pid_t pid); -int thread_map__remove(struct thread_map *threads, int idx); +void thread_map__read_comms(struct perf_thread_map *threads); +bool thread_map__has(struct perf_thread_map *threads, pid_t pid); +int thread_map__remove(struct perf_thread_map *threads, int idx); #endif /* __PERF_THREAD_MAP_H */ diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index c2abc259b51d..9796a2e43f67 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c @@ -10,7 +10,6 @@ #include <math.h> #include <linux/ctype.h> -#include "perf.h" #include "debug.h" #include "time-utils.h" #include "session.h" diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h index 72a42ea1d513..4f42988eb2f7 100644 --- a/tools/perf/util/time-utils.h +++ b/tools/perf/util/time-utils.h @@ -3,6 +3,7 @@ #define _TIME_UTILS_H_ #include <stddef.h> +#include <time.h> #include <linux/types.h> struct perf_time_interval { @@ -34,4 +35,12 @@ int timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz); int fetch_current_timestamp(char *buf, size_t sz); +static inline unsigned long long rdclock(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} + #endif diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 9096a6e3de59..2abbf668b8de 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -8,8 +8,8 @@ struct perf_session; union perf_event; -struct perf_evlist; -struct perf_evsel; +struct evlist; +struct evsel; struct perf_sample; struct perf_tool; struct machine; @@ -17,14 +17,14 @@ struct ordered_events; typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, struct machine *machine); + struct evsel *evsel, struct machine *machine); typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); typedef int (*event_attr_op)(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist); + struct evlist **pevlist); typedef int (*event_op2)(struct perf_session *session, union perf_event *event); typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event); @@ -56,7 +56,7 @@ struct perf_tool { throttle, unthrottle, ksymbol, - bpf_event; + bpf; event_attr_op attr; event_attr_op event_update; diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 251bbf124fb0..51fb574998bb 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -12,6 +12,7 @@ #include "parse-events.h" #include "symbol.h" #include "top.h" +#include "../perf.h" #include <inttypes.h> #define SNPRINTF(buf, size, fmt, args...) \ @@ -70,10 +71,10 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) esamples_percent); } - if (top->evlist->nr_entries == 1) { - struct perf_evsel *first = perf_evlist__first(top->evlist); + if (top->evlist->core.nr_entries == 1) { + struct evsel *first = perf_evlist__first(top->evlist); ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", - (uint64_t)first->attr.sample_period, + (uint64_t)first->core.attr.sample_period, opts->freq ? "Hz" : ""); } @@ -95,15 +96,15 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) if (target->cpu_list) ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", - top->evlist->cpus->nr > 1 ? "s" : "", + top->evlist->core.cpus->nr > 1 ? "s" : "", target->cpu_list); else { if (target->tid) ret += SNPRINTF(bf + ret, size - ret, ")"); else ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", - top->evlist->cpus->nr, - top->evlist->cpus->nr > 1 ? "s" : ""); + top->evlist->core.cpus->nr, + top->evlist->core.cpus->nr > 1 ? "s" : ""); } perf_top__reset_sample_counters(top); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 19f95eaf75c8..f117d4f4821e 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -3,21 +3,25 @@ #define __PERF_TOP_H 1 #include "tool.h" +#include "evswitch.h" #include "annotate.h" +#include "ordered-events.h" +#include "record.h" #include <linux/types.h> #include <stddef.h> #include <stdbool.h> #include <sys/ioctl.h> -struct perf_evlist; -struct perf_evsel; +struct evlist; +struct evsel; struct perf_session; struct perf_top { struct perf_tool tool; - struct perf_evlist *evlist; + struct evlist *evlist; struct record_opts record_opts; struct annotation_options annotation_opts; + struct evswitch evswitch; /* * Symbols will be added here in perf_event__process_sample and will * get out after decayed. @@ -33,7 +37,7 @@ struct perf_top { bool vmlinux_warned; bool dump_symtab; struct hist_entry *sym_filter_entry; - struct perf_evsel *sym_evsel; + struct evsel *sym_evsel; struct perf_session *session; struct winsize winsize; int realtime_prio; diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 4550015b9d5d..d63d542b2cde 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/zalloc.h> -#include "../perf.h" #include "trace-event.h" #include <api/fs/tracing_path.h> #include "evsel.h" @@ -405,11 +404,11 @@ static struct tracepoint_path * get_tracepoints_path(struct list_head *pattrs) { struct tracepoint_path path, *ppath = &path; - struct perf_evsel *pos; + struct evsel *pos; int nr_tracepoints = 0; - list_for_each_entry(pos, pattrs, node) { - if (pos->attr.type != PERF_TYPE_TRACEPOINT) + list_for_each_entry(pos, pattrs, core.node) { + if (pos->core.attr.type != PERF_TYPE_TRACEPOINT) continue; ++nr_tracepoints; @@ -425,7 +424,7 @@ get_tracepoints_path(struct list_head *pattrs) } try_id: - ppath->next = tracepoint_id_to_path(pos->attr.config); + ppath->next = tracepoint_id_to_path(pos->core.attr.config); if (!ppath->next) { error: pr_debug("No memory to alloc tracepoints list\n"); @@ -441,10 +440,10 @@ next: bool have_tracepoints(struct list_head *pattrs) { - struct perf_evsel *pos; + struct evsel *pos; - list_for_each_entry(pos, pattrs, node) - if (pos->attr.type == PERF_TYPE_TRACEPOINT) + list_for_each_entry(pos, pattrs, core.node) + if (pos->core.attr.type == PERF_TYPE_TRACEPOINT) return true; return false; diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index b3982e1bb4c5..5d6bfc70b210 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -7,7 +7,6 @@ #include <string.h> #include <errno.h> -#include "../perf.h" #include "debug.h" #include "trace-event.h" @@ -110,7 +109,7 @@ void event_format__fprintf(struct tep_event *event, record.data = data; trace_seq_init(&s); - tep_event_info(&s, event, &record); + tep_print_event(event->tep, &s, &record, "%s", TEP_PRINT_INFO); trace_seq_do_fprintf(&s, fp); trace_seq_destroy(&s); } diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 13c1cf60d1bc..b6c0db068be0 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -15,7 +15,6 @@ #include <unistd.h> #include <errno.h> -#include "../perf.h" #include "util.h" #include "trace-event.h" #include "debug.h" diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index ba58f69777a1..714581b0de65 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -10,7 +10,6 @@ #include <string.h> #include <errno.h> -#include "../perf.h" #include "debug.h" #include "trace-event.h" #include <linux/zalloc.h> @@ -29,7 +28,7 @@ static int stop_script_unsupported(void) static void process_event_unsupported(union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct addr_location *al __maybe_unused) { } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index c7002fe11673..2e158387b3d7 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -3,7 +3,6 @@ #define _PERF_UTIL_TRACE_EVENT_H #include <traceevent/event-parse.h> -#include <traceevent/trace-seq.h> #include "parse-events.h" struct machine; @@ -79,13 +78,13 @@ struct scripting_ops { int (*stop_script) (void); void (*process_event) (union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al); void (*process_switch)(union perf_event *event, struct perf_sample *sample, struct machine *machine); void (*process_stat)(struct perf_stat_config *config, - struct perf_evsel *evsel, u64 tstamp); + struct evsel *evsel, u64 tstamp); void (*process_stat_interval)(u64 tstamp); int (*generate_script) (struct tep_handle *pevent, const char *outfile); }; diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h index 88223bc7c82b..33e997f9ccc8 100644 --- a/tools/perf/util/trigger.h +++ b/tools/perf/util/trigger.h @@ -2,7 +2,6 @@ #ifndef __TRIGGER_H_ #define __TRIGGER_H_ 1 -#include "util/debug.h" #include "asm/bug.h" /* diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 28f71ca6ce1c..9ece188ae48a 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -5,6 +5,7 @@ #include <inttypes.h> #include <errno.h> #include "debug.h" +#include "dso.h" #include "unwind.h" #include "unwind-libdw.h" #include "machine.h" diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 71a788921b62..ebdbb056510c 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -616,26 +616,26 @@ static unw_accessors_t accessors = { .get_proc_name = get_proc_name, }; -static int _unwind__prepare_access(struct thread *thread) +static int _unwind__prepare_access(struct map_groups *mg) { - thread->addr_space = unw_create_addr_space(&accessors, 0); - if (!thread->addr_space) { + mg->addr_space = unw_create_addr_space(&accessors, 0); + if (!mg->addr_space) { pr_err("unwind: Can't create unwind address space.\n"); return -ENOMEM; } - unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL); + unw_set_caching_policy(mg->addr_space, UNW_CACHE_GLOBAL); return 0; } -static void _unwind__flush_access(struct thread *thread) +static void _unwind__flush_access(struct map_groups *mg) { - unw_flush_cache(thread->addr_space, 0, 0); + unw_flush_cache(mg->addr_space, 0, 0); } -static void _unwind__finish_access(struct thread *thread) +static void _unwind__finish_access(struct map_groups *mg) { - unw_destroy_addr_space(thread->addr_space); + unw_destroy_addr_space(mg->addr_space); } static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, @@ -660,7 +660,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, */ if (max_stack - 1 > 0) { WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); - addr_space = ui->thread->addr_space; + addr_space = ui->thread->mg->addr_space; if (addr_space == NULL) return -1; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index c0811977d7d5..a24fb57c9b2c 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "unwind.h" +#include "dso.h" #include "map.h" #include "thread.h" #include "session.h" @@ -11,13 +12,13 @@ struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; -static void unwind__register_ops(struct thread *thread, +static void unwind__register_ops(struct map_groups *mg, struct unwind_libunwind_ops *ops) { - thread->unwind_libunwind_ops = ops; + mg->unwind_libunwind_ops = ops; } -int unwind__prepare_access(struct thread *thread, struct map *map, +int unwind__prepare_access(struct map_groups *mg, struct map *map, bool *initialized) { const char *arch; @@ -28,7 +29,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map, if (!dwarf_callchain_users) return 0; - if (thread->addr_space) { + if (mg->addr_space) { pr_debug("unwind: thread map already set, dso=%s\n", map->dso->name); if (initialized) @@ -37,14 +38,14 @@ int unwind__prepare_access(struct thread *thread, struct map *map, } /* env->arch is NULL for live-mode (i.e. perf top) */ - if (!thread->mg->machine->env || !thread->mg->machine->env->arch) + if (!mg->machine->env || !mg->machine->env->arch) goto out_register; - dso_type = dso__type(map->dso, thread->mg->machine); + dso_type = dso__type(map->dso, mg->machine); if (dso_type == DSO__TYPE_UNKNOWN) return 0; - arch = perf_env__arch(thread->mg->machine->env); + arch = perf_env__arch(mg->machine->env); if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) @@ -59,37 +60,31 @@ int unwind__prepare_access(struct thread *thread, struct map *map, return 0; } out_register: - unwind__register_ops(thread, ops); + unwind__register_ops(mg, ops); - err = thread->unwind_libunwind_ops->prepare_access(thread); + err = mg->unwind_libunwind_ops->prepare_access(mg); if (initialized) *initialized = err ? false : true; return err; } -void unwind__flush_access(struct thread *thread) +void unwind__flush_access(struct map_groups *mg) { - if (!dwarf_callchain_users) - return; - - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->flush_access(thread); + if (mg->unwind_libunwind_ops) + mg->unwind_libunwind_ops->flush_access(mg); } -void unwind__finish_access(struct thread *thread) +void unwind__finish_access(struct map_groups *mg) { - if (!dwarf_callchain_users) - return; - - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->finish_access(thread); + if (mg->unwind_libunwind_ops) + mg->unwind_libunwind_ops->finish_access(mg); } int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack) { - if (thread->unwind_libunwind_ops) - return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); + if (thread->mg->unwind_libunwind_ops) + return thread->mg->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); return 0; } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 8a44a1569a21..3a7d00c20d86 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -6,6 +6,7 @@ #include <linux/types.h> struct map; +struct map_groups; struct perf_sample; struct symbol; struct thread; @@ -19,9 +20,9 @@ struct unwind_entry { typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); struct unwind_libunwind_ops { - int (*prepare_access)(struct thread *thread); - void (*flush_access)(struct thread *thread); - void (*finish_access)(struct thread *thread); + int (*prepare_access)(struct map_groups *mg); + void (*flush_access)(struct map_groups *mg); + void (*finish_access)(struct map_groups *mg); int (*get_entries)(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack); @@ -46,20 +47,20 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, #endif int LIBUNWIND__ARCH_REG_ID(int regnum); -int unwind__prepare_access(struct thread *thread, struct map *map, +int unwind__prepare_access(struct map_groups *mg, struct map *map, bool *initialized); -void unwind__flush_access(struct thread *thread); -void unwind__finish_access(struct thread *thread); +void unwind__flush_access(struct map_groups *mg); +void unwind__finish_access(struct map_groups *mg); #else -static inline int unwind__prepare_access(struct thread *thread __maybe_unused, +static inline int unwind__prepare_access(struct map_groups *mg __maybe_unused, struct map *map __maybe_unused, bool *initialized __maybe_unused) { return 0; } -static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} -static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__flush_access(struct map_groups *mg __maybe_unused) {} +static inline void unwind__finish_access(struct map_groups *mg __maybe_unused) {} #endif #else static inline int @@ -72,14 +73,14 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, return 0; } -static inline int unwind__prepare_access(struct thread *thread __maybe_unused, +static inline int unwind__prepare_access(struct map_groups *mg __maybe_unused, struct map *map __maybe_unused, bool *initialized __maybe_unused) { return 0; } -static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} -static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__flush_access(struct map_groups *mg __maybe_unused) {} +static inline void unwind__finish_access(struct map_groups *mg __maybe_unused) {} #endif /* HAVE_DWARF_UNWIND_SUPPORT */ #endif /* __UNWIND_H */ diff --git a/tools/perf/util/util-cxx.h b/tools/perf/util/util-cxx.h deleted file mode 100644 index 80a99e458d4e..000000000000 --- a/tools/perf/util/util-cxx.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support C++ source use utilities defined in util.h - */ - -#ifndef PERF_UTIL_UTIL_CXX_H -#define PERF_UTIL_UTIL_CXX_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Now 'new' is the only C++ keyword found in util.h: - * in tools/include/linux/rbtree.h - * - * Other keywords, like class and delete, should be - * redefined if necessary. - */ -#define new _new -#include "util.h" -#undef new - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index a61535cf1bca..32322a20a68b 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../perf.h" #include "util.h" #include "debug.h" +#include "event.h" #include "namespaces.h" #include <api/fs/fs.h> #include <sys/mman.h> @@ -16,10 +16,12 @@ #include <string.h> #include <errno.h> #include <limits.h> +#include <linux/capability.h> #include <linux/kernel.h> #include <linux/log2.h> #include <linux/time64.h> #include <unistd.h> +#include "cap.h" #include "strlist.h" #include "string2.h" @@ -41,26 +43,6 @@ void perf_set_multithreaded(void) unsigned int page_size; -#ifdef _SC_LEVEL1_DCACHE_LINESIZE -#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) -#else -static void cache_line_size(int *cacheline_sizep) -{ - if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) - pr_debug("cannot determine cache line size"); -} -#endif - -int cacheline_size(void) -{ - static int size; - - if (!size) - cache_line_size(&size); - - return size; -} - int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; @@ -384,46 +366,6 @@ int copyfile(const char *from, const char *to) return copyfile_mode(from, to, 0755); } -static ssize_t ion(bool is_read, int fd, void *buf, size_t n) -{ - void *buf_start = buf; - size_t left = n; - - while (left) { - /* buf must be treated as const if !is_read. */ - ssize_t ret = is_read ? read(fd, buf, left) : - write(fd, buf, left); - - if (ret < 0 && errno == EINTR) - continue; - if (ret <= 0) - return ret; - - left -= ret; - buf += ret; - } - - BUG_ON((size_t)(buf - buf_start) != n); - return n; -} - -/* - * Read exactly 'n' bytes or return an error. - */ -ssize_t readn(int fd, void *buf, size_t n) -{ - return ion(true, fd, buf, n); -} - -/* - * Write exactly 'n' bytes or return an error. - */ -ssize_t writen(int fd, const void *buf, size_t n) -{ - /* ion does not modify buf. */ - return ion(false, fd, (void *)buf, n); -} - size_t hex_width(u64 v) { size_t n = 1; @@ -443,6 +385,13 @@ int perf_event_paranoid(void) return value; } + +bool perf_event_paranoid_check(int max_level) +{ + return perf_cap__capable(CAP_SYS_ADMIN) || + perf_event_paranoid() <= max_level; +} + static int fetch_ubuntu_kernel_version(unsigned int *puint) { diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index dc7a469921e9..45a5c6f20197 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -11,6 +11,7 @@ #include <stddef.h> #include <linux/compiler.h> #include <sys/types.h> +#include <internal/lib.h> /* General helper functions */ void usage(const char *err) __noreturn; @@ -30,13 +31,9 @@ int copyfile_mode(const char *from, const char *to, mode_t mode); int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size); -ssize_t readn(int fd, void *buf, size_t n); -ssize_t writen(int fd, const void *buf, size_t n); - size_t hex_width(u64 v); extern unsigned int page_size; -int __pure cacheline_size(void); int sysctl__max_stack(void); diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index c59154e2d124..b9823f414f10 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -2,6 +2,7 @@ #include <inttypes.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 7f427bab6c12..e5e6599603f4 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include "vdso.h" +#include "dso.h" #include "util.h" #include "map.h" #include "symbol.h" diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c index 512ad7c09b13..59d456f716e9 100644 --- a/tools/perf/util/zlib.c +++ b/tools/perf/util/zlib.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <fcntl.h> #include <stdio.h> +#include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/mman.h> |