Currently cd.read_data.suspended is read by the hotpath function sched_clock(). This variable need not be accessed on the hotpath; we can instead check whether the timer is suspended by checking the validity of the read_sched_clock function pointer.
The new master copy of the function pointer (actual_read_sched_clock) is introduced and is used this for all reads of the clock hardware except those within sched_clock itself.
Suggested-by: Thomas Gleixner tglx@linutronix.de Signed-off-by: Daniel Thompson daniel.thompson@linaro.org Cc: Russell King linux@arm.linux.org.uk Cc: Will Deacon will.deacon@arm.com Cc: Catalin Marinas catalin.marinas@arm.com --- kernel/time/sched_clock.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c index cb69a47dfee4..638c765131fa 100644 --- a/kernel/time/sched_clock.c +++ b/kernel/time/sched_clock.c @@ -22,7 +22,7 @@ * struct clock_read_data - data required to read from sched_clock * * Care must be taken when updating this structure; it is read by - * some very hot code paths. It occupies <=48 bytes and, when combined + * some very hot code paths. It occupies <=40 bytes and, when combined * with the seqcount used to synchronize access, comfortably fits into * a 64 byte cache line. */ @@ -33,7 +33,6 @@ struct clock_read_data { u64 (*read_sched_clock)(void); u32 mult; u32 shift; - bool suspended; };
/** @@ -49,6 +48,7 @@ struct clock_data { struct clock_read_data read_data; ktime_t wrap_kt; unsigned long rate; + u64 (*actual_read_sched_clock)(void); };
static struct hrtimer sched_clock_timer; @@ -68,6 +68,8 @@ static u64 notrace jiffy_sched_clock_read(void) static struct clock_data cd ____cacheline_aligned = { .read_data = { .mult = NSEC_PER_SEC / HZ, .read_sched_clock = jiffy_sched_clock_read, }, + .actual_read_sched_clock = jiffy_sched_clock_read, + };
static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift) @@ -85,7 +87,7 @@ unsigned long long notrace sched_clock(void) seq = raw_read_seqcount_begin(&cd.seq);
res = rd->epoch_ns; - if (!rd->suspended) { + if (rd->read_sched_clock) { cyc = rd->read_sched_clock(); cyc = (cyc - rd->epoch_cyc) & rd->sched_clock_mask; res += cyc_to_ns(cyc, rd->mult, rd->shift); @@ -105,7 +107,7 @@ static void notrace update_sched_clock(void) u64 ns; struct clock_read_data *rd = &cd.read_data;
- cyc = rd->read_sched_clock(); + cyc = cd.actual_read_sched_clock(); ns = rd->epoch_ns + cyc_to_ns((cyc - rd->epoch_cyc) & rd->sched_clock_mask, rd->mult, rd->shift); @@ -151,10 +153,11 @@ void __init sched_clock_register(u64 (*read)(void), int bits,
/* update epoch for new counter and update epoch_ns from old counter*/ new_epoch = read(); - cyc = rd->read_sched_clock(); + cyc = cd.actual_read_sched_clock(); ns = rd->epoch_ns + cyc_to_ns((cyc - rd->epoch_cyc) & rd->sched_clock_mask, rd->mult, rd->shift); + cd.actual_read_sched_clock = read;
raw_write_seqcount_begin(&cd.seq); rd->read_sched_clock = read; @@ -194,7 +197,7 @@ void __init sched_clock_postinit(void) * If no sched_clock function has been provided at that point, * make it the final one one. */ - if (cd.read_data.read_sched_clock == jiffy_sched_clock_read) + if (cd.actual_read_sched_clock == jiffy_sched_clock_read) sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
update_sched_clock(); @@ -214,7 +217,7 @@ static int sched_clock_suspend(void)
update_sched_clock(); hrtimer_cancel(&sched_clock_timer); - rd->suspended = true; + rd->read_sched_clock = NULL; return 0; }
@@ -222,9 +225,9 @@ static void sched_clock_resume(void) { struct clock_read_data *rd = &cd.read_data;
- rd->epoch_cyc = rd->read_sched_clock(); + rd->epoch_cyc = cd.actual_read_sched_clock(); hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); - rd->suspended = false; + rd->read_sched_clock = cd.actual_read_sched_clock; }
static struct syscore_ops sched_clock_ops = {