Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Kernel side changes: - Improved kbprobes robustness - Intel PEBS support for PT hardware tracing - Other Intel PT improvements: high order pages memory footprint reduction and various related cleanups - Misc cleanups The perf tooling side has been very busy in this cycle, with over 300 commits. This is an incomplete high-level summary of the many improvements done by over 30 developers: - Lots of updates to the following tools: 'perf c2c' 'perf config' 'perf record' 'perf report' 'perf script' 'perf test' 'perf top' 'perf trace' - Updates to libperf and libtraceevent, and a consolidation of the proliferation of x86 instruction decoder libraries. - Vendor event updates for Intel and PowerPC CPUs, - Updates to hardware tracing tooling for ARM and Intel CPUs, - ... and lots of other changes and cleanups - see the shortlog and Git log for details" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (322 commits) kprobes: Prohibit probing on BUG() and WARN() address perf/x86: Make more stuff static x86, perf: Fix the dependency of the x86 insn decoder selftest objtool: Ignore intentional differences for the x86 insn decoder objtool: Update sync-check.sh from perf's check-headers.sh perf build: Ignore intentional differences for the x86 insn decoder perf intel-pt: Use shared x86 insn decoder perf intel-pt: Remove inat.c from build dependency list perf: Update .gitignore file objtool: Move x86 insn decoder to a common location perf metricgroup: Support multiple events for metricgroup perf metricgroup: Scale the metric result perf pmu: Change convert_scale from static to global perf symbols: Move mem_info and branch_info out of symbol.h perf auxtrace: Uninline functions that touch perf_session perf tools: Remove needless evlist.h include directives perf tools: Remove needless evlist.h include directives perf tools: Remove needless thread_map.h include directives perf tools: Remove needless thread.h include directives perf tools: Remove needless map.h include directives ...
This commit is contained in:
commit
772c1d06bd
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -545,33 +545,62 @@ static void pt_config_buffer(void *buf, unsigned int topa_idx,
|
|||
wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct topa - ToPA metadata
|
||||
* @list: linkage to struct pt_buffer's list of tables
|
||||
* @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 list_head list;
|
||||
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 - 40) / sizeof(struct topa_entry)) - 1)
|
||||
#define TENTS_PER_PAGE \
|
||||
((PAGE_SIZE - sizeof(struct topa)) / sizeof(struct topa_entry))
|
||||
|
||||
/**
|
||||
* struct topa - page-sized ToPA table with metadata at the top
|
||||
* struct topa_page - page-sized ToPA table with metadata at the top
|
||||
* @table: actual ToPA table entries, as understood by PT hardware
|
||||
* @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
|
||||
* @topa: metadata
|
||||
*/
|
||||
struct topa {
|
||||
struct topa_page {
|
||||
struct topa_entry table[TENTS_PER_PAGE];
|
||||
struct list_head list;
|
||||
u64 phys;
|
||||
u64 offset;
|
||||
size_t size;
|
||||
int last;
|
||||
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;
|
||||
|
||||
do {
|
||||
pg++;
|
||||
pg &= buf->nr_pages - 1;
|
||||
} while (buf->topa_index[pg] == te);
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
return pg;
|
||||
/*
|
||||
* Hitting this means we have a problem in the ToPA
|
||||
* allocation code.
|
||||
*/
|
||||
WARN_ON_ONCE(1);
|
||||
|
||||
return NULL;
|
||||
|
||||
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,48 +1074,17 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
|
|||
idx = wakeup;
|
||||
|
||||
idx &= buf->nr_pages - 1;
|
||||
buf->intr_pos = idx;
|
||||
|
||||
buf->topa_index[buf->stop_pos]->stop = 1;
|
||||
buf->topa_index[buf->stop_pos]->intr = 1;
|
||||
buf->topa_index[buf->intr_pos]->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);
|
||||
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->stop_te->stop = 1;
|
||||
buf->stop_te->intr = 1;
|
||||
buf->intr_te->intr = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
@ -446,6 +447,16 @@ struct pmu {
|
|||
void (*addr_filters_sync) (struct perf_event *event);
|
||||
/* 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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
|
@ -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) \
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#define _TOOLS_LINUX_BITOPS_H_
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <limits.h>
|
||||
#ifndef __WORDSIZE
|
||||
#define __WORDSIZE (__SIZEOF_LONG__ * 8)
|
||||
#endif
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 '};'; \
|
||||
|
|
|
@ -302,33 +302,6 @@ void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian)
|
|||
tep->host_bigendian = 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
|
||||
|
@ -344,19 +317,6 @@ bool tep_is_old_format(struct tep_handle *tep)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 (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)
|
||||
{
|
||||
unsigned long secs;
|
||||
unsigned long usecs;
|
||||
unsigned long nsecs;
|
||||
int p;
|
||||
bool use_usec_format;
|
||||
|
||||
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;
|
||||
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) {
|
||||
tep_data_latency_format(tep, s, record);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
trace_seq_printf(s, " %5lu.%0*lu:", secs, p, usecs);
|
||||
} else
|
||||
trace_seq_printf(s, " %12llu:", record->ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_print_event_data - Write the event data section
|
||||
* @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.
|
||||
*/
|
||||
void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s,
|
||||
struct tep_event *event,
|
||||
struct tep_record *record)
|
||||
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)
|
||||
{
|
||||
static const char *spaces = " "; /* 20 spaces */
|
||||
int len;
|
||||
int param;
|
||||
|
||||
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_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]);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
static int tep_print_event_param_type(char *format,
|
||||
struct print_event_type *type)
|
||||
{
|
||||
char *str = format + 1;
|
||||
int i = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
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 - Write various event information
|
||||
* @tep: a handle to the trace event parser context
|
||||
* @s: the trace_seq to write to
|
||||
* @record: The record to get the event from
|
||||
* @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(struct tep_handle *tep, struct trace_seq *s,
|
||||
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;
|
||||
|
||||
if (!format)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 -
|
||||
|
|
|
@ -34,3 +34,6 @@ arch/*/include/generated/
|
|||
trace/beauty/generated/
|
||||
pmu-events/pmu-events.c
|
||||
pmu-events/jevents
|
||||
feature/
|
||||
fixdep
|
||||
libtraceevent-dynamic-list
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
--------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
u64 version; // Currently 1
|
||||
u64 block_size_bytes; // /sys/devices/system/memory/block_size_bytes
|
||||
u64 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>
|
||||
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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "map_symbol.h"
|
||||
#include "mem-events.h"
|
||||
|
||||
/* PowerPC does not support 'ldlat' parameter. */
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <regex.h>
|
||||
#include <linux/zalloc.h>
|
||||
|
||||
#include "../../perf.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
#include "../../util/debug.h"
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include "dso.h"
|
||||
#include "symbol.h"
|
||||
#include "map.h"
|
||||
#include "probe-event.h"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <string.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "../../util/debug.h"
|
||||
#include "../../util/header.h"
|
||||
|
||||
static inline void
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue