Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e350de3 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

perf_counter: Accurate period data



We currently log hw.sample_period for PERF_SAMPLE_PERIOD, however this is
incorrect. When we adjust the period, it will only take effect the next
cycle but report it for the current cycle. So when we adjust the period
for every cycle, we're always wrong.

Solve this by keeping track of the last_period.

Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent df1a132b
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -767,6 +767,7 @@ static void power_pmu_unthrottle(struct perf_counter *counter)
	perf_disable();
	power_pmu_read(counter);
	left = counter->hw.sample_period;
	counter->hw.last_period = left;
	val = 0;
	if (left < 0x80000000L)
		val = 0x80000000L - left;
@@ -937,7 +938,8 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter)

	counter->hw.config = events[n];
	counter->hw.counter_base = cflags[n];
	atomic64_set(&counter->hw.period_left, counter->hw.sample_period);
	counter->hw.last_period = counter->hw.sample_period;
	atomic64_set(&counter->hw.period_left, counter->hw.last_period);

	/*
	 * See if we need to reserve the PMU.
@@ -1004,6 +1006,7 @@ static void record_and_restart(struct perf_counter *counter, long val,
		struct perf_sample_data data = {
			.regs	= regs,
			.addr	= 0,
			.period	= counter->hw.last_period,
		};

		if (counter->attr.sample_type & PERF_SAMPLE_ADDR) {
+12 −3
Original line number Diff line number Diff line
@@ -698,6 +698,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)

	if (!hwc->sample_period) {
		hwc->sample_period = x86_pmu.max_period;
		hwc->last_period = hwc->sample_period;
		atomic64_set(&hwc->period_left, hwc->sample_period);
	}

@@ -880,12 +881,14 @@ x86_perf_counter_set_period(struct perf_counter *counter,
	if (unlikely(left <= -period)) {
		left = period;
		atomic64_set(&hwc->period_left, left);
		hwc->last_period = period;
		ret = 1;
	}

	if (unlikely(left <= 0)) {
		left += period;
		atomic64_set(&hwc->period_left, left);
		hwc->last_period = period;
		ret = 1;
	}
	/*
@@ -1257,9 +1260,12 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
		if (val & (1ULL << (x86_pmu.counter_bits - 1)))
			continue;

		/* counter overflow */
		/*
		 * counter overflow
		 */
		handled		= 1;
		inc_irq_stat(apic_perf_irqs);
		data.period	= counter->hw.last_period;

		if (!x86_perf_counter_set_period(counter, hwc, idx))
			continue;

@@ -1267,6 +1273,9 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
			amd_pmu_disable_counter(hwc, idx);
	}

	if (handled)
		inc_irq_stat(apic_perf_irqs);

	return handled;
}

+4 −2
Original line number Diff line number Diff line
@@ -366,6 +366,7 @@ struct hw_perf_counter {
	};
	atomic64_t			prev_count;
	u64				sample_period;
	u64				last_period;
	atomic64_t			period_left;
	u64				interrupts;

@@ -608,6 +609,7 @@ extern void perf_counter_update_userpage(struct perf_counter *counter);
struct perf_sample_data {
	struct pt_regs		*regs;
	u64			addr;
	u64			period;
};

extern int perf_counter_overflow(struct perf_counter *counter, int nmi,
+6 −3
Original line number Diff line number Diff line
@@ -2495,7 +2495,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
		perf_output_put(&handle, cpu_entry);

	if (sample_type & PERF_SAMPLE_PERIOD)
		perf_output_put(&handle, counter->hw.sample_period);
		perf_output_put(&handle, data->period);

	/*
	 * XXX PERF_SAMPLE_GROUP vs inherited counters seems difficult.
@@ -3040,11 +3040,13 @@ static void perf_swcounter_set_period(struct perf_counter *counter)
	if (unlikely(left <= -period)) {
		left = period;
		atomic64_set(&hwc->period_left, left);
		hwc->last_period = period;
	}

	if (unlikely(left <= 0)) {
		left += period;
		atomic64_add(period, &hwc->period_left);
		hwc->last_period = period;
	}

	atomic64_set(&hwc->prev_count, -left);
@@ -3088,6 +3090,7 @@ static void perf_swcounter_overflow(struct perf_counter *counter,
	struct perf_sample_data data = {
		.regs	= regs,
		.addr	= addr,
		.period	= counter->hw.last_period,
	};

	perf_swcounter_update(counter);