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

Commit 3d3a6021 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/pseries: lparcfg calculate PURR on demand



For SPLPAR, lparcfg provides a sum of PURR registers for all CPUs.
Currently this is done by reading PURR in context switch and timer
interrupt, and storing that into a per-CPU variable. These are summed
to provide the value.

This does not work with all timer schemes (e.g., NO_HZ_FULL), and it
is sub-optimal for performance because it reads the PURR register on
every context switch, although that's been difficult to distinguish
from noise in the contxt_switch microbenchmark.

This patch implements the sum by calling a function on each CPU, to
read and add PURR values of each CPU.

Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 36d632ea
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -196,14 +196,6 @@ extern u64 mulhdu(u64, u64);
extern void div128_by_32(u64 dividend_high, u64 dividend_low,
			 unsigned divisor, struct div_result *dr);

/* Used to store Processor Utilization register (purr) values */

struct cpu_usage {
        u64 current_tb;  /* Holds the current purr register values */
};

DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);

extern void secondary_cpu_time_init(void);
extern void __init time_init(void);

+0 −14
Original line number Diff line number Diff line
@@ -846,10 +846,6 @@ bool ppc_breakpoint_available(void)
}
EXPORT_SYMBOL_GPL(ppc_breakpoint_available);

#ifdef CONFIG_PPC64
DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
#endif

static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
			      struct arch_hw_breakpoint *b)
{
@@ -1182,16 +1178,6 @@ struct task_struct *__switch_to(struct task_struct *prev,

	WARN_ON(!irqs_disabled());

#ifdef CONFIG_PPC64
	/*
	 * Collect processor utilization data per process
	 */
	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
		struct cpu_usage *cu = this_cpu_ptr(&cpu_usage_array);
		cu->current_tb = mfspr(SPRN_PURR);
	}
#endif /* CONFIG_PPC64 */

#ifdef CONFIG_PPC_BOOK3S_64
	batch = this_cpu_ptr(&ppc64_tlb_batch);
	if (batch->active) {
+0 −8
Original line number Diff line number Diff line
@@ -597,14 +597,6 @@ static void __timer_interrupt(void)
		__this_cpu_inc(irq_stat.timer_irqs_others);
	}

#ifdef CONFIG_PPC64
	/* collect purr register values often, for accurate calculations */
	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
		struct cpu_usage *cu = this_cpu_ptr(&cpu_usage_array);
		cu->current_tb = mfspr(SPRN_PURR);
	}
#endif

	trace_timer_interrupt_exit(regs);
}

+10 −8
Original line number Diff line number Diff line
@@ -52,18 +52,20 @@
 * Track sum of all purrs across all processors. This is used to further
 * calculate usage values by different applications
 */
static void cpu_get_purr(void *arg)
{
	atomic64_t *sum = arg;

	atomic64_add(mfspr(SPRN_PURR), sum);
}

static unsigned long get_purr(void)
{
	unsigned long sum_purr = 0;
	int cpu;
	atomic64_t purr = ATOMIC64_INIT(0);

	for_each_possible_cpu(cpu) {
		struct cpu_usage *cu;
	on_each_cpu(cpu_get_purr, &purr, 1);

		cu = &per_cpu(cpu_usage_array, cpu);
		sum_purr += cu->current_tb;
	}
	return sum_purr;
	return atomic64_read(&purr);
}

/*