arch/x86/events/amd/lbr.c

Source file repositories/reference/linux-study-clean/arch/x86/events/amd/lbr.c

File Facts

System
Linux kernel
Corpus path
arch/x86/events/amd/lbr.c
Extension
.c
Size
11027 bytes
Lines
439
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct branch_entry {
	union {
		struct {
			u64	ip:58;
			u64	ip_sign_ext:5;
			u64	mispredict:1;
		} split;
		u64		full;
	} from;

	union {
		struct {
			u64	ip:58;
			u64	ip_sign_ext:3;
			u64	reserved:1;
			u64	spec:1;
			u64	valid:1;
		} split;
		u64		full;
	} to;
};

static __always_inline void amd_pmu_lbr_set_from(unsigned int idx, u64 val)
{
	wrmsrq(MSR_AMD_SAMP_BR_FROM + idx * 2, val);
}

static __always_inline void amd_pmu_lbr_set_to(unsigned int idx, u64 val)
{
	wrmsrq(MSR_AMD_SAMP_BR_FROM + idx * 2 + 1, val);
}

static __always_inline u64 amd_pmu_lbr_get_from(unsigned int idx)
{
	u64 val;

	rdmsrq(MSR_AMD_SAMP_BR_FROM + idx * 2, val);

	return val;
}

static __always_inline u64 amd_pmu_lbr_get_to(unsigned int idx)
{
	u64 val;

	rdmsrq(MSR_AMD_SAMP_BR_FROM + idx * 2 + 1, val);

	return val;
}

static __always_inline u64 sign_ext_branch_ip(u64 ip)
{
	u32 shift = 64 - boot_cpu_data.x86_virt_bits;

	return (u64)(((s64)ip << shift) >> shift);
}

static void amd_pmu_lbr_filter(void)
{
	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
	int br_sel = cpuc->br_sel, offset, type, i, j;
	bool compress = false;
	bool fused_only = false;
	u64 from, to;

	/* If sampling all branches, there is nothing to filter */
	if (((br_sel & X86_BR_ALL) == X86_BR_ALL) &&
	    ((br_sel & X86_BR_TYPE_SAVE) != X86_BR_TYPE_SAVE))
		fused_only = true;

	for (i = 0; i < cpuc->lbr_stack.nr; i++) {
		from = cpuc->lbr_entries[i].from;
		to = cpuc->lbr_entries[i].to;
		type = branch_type_fused(from, to, 0, &offset);

		/*
		 * Adjust the branch from address in case of instruction
		 * fusion where it points to an instruction preceding the
		 * actual branch
		 */
		if (offset) {
			cpuc->lbr_entries[i].from += offset;
			if (fused_only)
				continue;
		}

		/* If type does not correspond, then discard */
		if (type == X86_BR_NONE || (br_sel & type) != type) {
			cpuc->lbr_entries[i].from = 0;	/* mark invalid */
			compress = true;

Annotation

Implementation Notes