diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-04-09 10:53:31 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-04-09 10:53:31 +1000 |
commit | 57c3440c3ceeec9680f702cfdd66dfda918eb8c8 (patch) | |
tree | d53b3428767e393564dc1b16441c7cb5863c7e90 | |
parent | d7b562b2730a4cb4bb0fdab6aafc64dafe8f088d (diff) | |
parent | 9d44b01cc8fe417ab1f33ca1d21da01187635a15 (diff) |
Merge commit 'sched-fixes/for-linus'
-rw-r--r-- | kernel/sched.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 8dcdec6fe0fe..7377222ab42f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -632,11 +632,39 @@ int sysctl_sched_rt_runtime = 950000; */ #define RUNTIME_INF ((u64)~0ULL) +static const unsigned long long time_sync_thresh = 100000; + +static DEFINE_PER_CPU(unsigned long long, time_offset); +static DEFINE_PER_CPU(unsigned long long, prev_cpu_time); + /* - * For kernel-internal use: high-speed (but slightly incorrect) per-cpu - * clock constructed from sched_clock(): + * Global lock which we take every now and then to synchronize + * the CPUs time. This method is not warp-safe, but it's good + * enough to synchronize slowly diverging time sources and thus + * it's good enough for tracing: */ -unsigned long long cpu_clock(int cpu) +static DEFINE_SPINLOCK(time_sync_lock); +static unsigned long long prev_global_time; + +static unsigned long long __sync_cpu_clock(cycles_t time, int cpu) +{ + unsigned long flags; + + spin_lock_irqsave(&time_sync_lock, flags); + + if (time < prev_global_time) { + per_cpu(time_offset, cpu) += prev_global_time - time; + time = prev_global_time; + } else { + prev_global_time = time; + } + + spin_unlock_irqrestore(&time_sync_lock, flags); + + return time; +} + +static unsigned long long __cpu_clock(int cpu) { unsigned long long now; unsigned long flags; @@ -657,6 +685,24 @@ unsigned long long cpu_clock(int cpu) return now; } + +/* + * For kernel-internal use: high-speed (but slightly incorrect) per-cpu + * clock constructed from sched_clock(): + */ +unsigned long long cpu_clock(int cpu) +{ + unsigned long long prev_cpu_time, time, delta_time; + + prev_cpu_time = per_cpu(prev_cpu_time, cpu); + time = __cpu_clock(cpu) + per_cpu(time_offset, cpu); + delta_time = time-prev_cpu_time; + + if (unlikely(delta_time > time_sync_thresh)) + time = __sync_cpu_clock(time, cpu); + + return time; +} EXPORT_SYMBOL_GPL(cpu_clock); #ifndef prepare_arch_switch |