diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/lockdep.c | 2 | ||||
| -rw-r--r-- | kernel/perf_event.c | 2 | ||||
| -rw-r--r-- | kernel/rcutorture.c | 3 | ||||
| -rw-r--r-- | kernel/sched.c | 2 | ||||
| -rw-r--r-- | kernel/sched_clock.c | 95 | ||||
| -rw-r--r-- | kernel/trace/trace_clock.c | 2 | 
6 files changed, 90 insertions, 16 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 54286798c37..f2852a51023 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -146,7 +146,7 @@ static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS],  static inline u64 lockstat_clock(void)  { -	return cpu_clock(smp_processor_id()); +	return local_clock();  }  static int lock_point(unsigned long points[], unsigned long ip) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 31d6afe9259..109c5ec8893 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -214,7 +214,7 @@ static void perf_unpin_context(struct perf_event_context *ctx)  static inline u64 perf_clock(void)  { -	return cpu_clock(raw_smp_processor_id()); +	return local_clock();  }  /* diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 6535ac8bc6a..2e2726d790b 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -239,8 +239,7 @@ static unsigned long  rcu_random(struct rcu_random_state *rrsp)  {  	if (--rrsp->rrs_count < 0) { -		rrsp->rrs_state += -			(unsigned long)cpu_clock(raw_smp_processor_id()); +		rrsp->rrs_state += (unsigned long)local_clock();  		rrsp->rrs_count = RCU_RANDOM_REFRESH;  	}  	rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD; diff --git a/kernel/sched.c b/kernel/sched.c index 8f351c56567..3abd8f780da 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1647,7 +1647,7 @@ static void update_shares(struct sched_domain *sd)  	if (root_task_group_empty())  		return; -	now = cpu_clock(raw_smp_processor_id()); +	now = local_clock();  	elapsed = now - sd->last_update;  	if (elapsed >= (s64)(u64)sysctl_sched_shares_ratelimit) { diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c index 906a0f718cb..52f1a149bfb 100644 --- a/kernel/sched_clock.c +++ b/kernel/sched_clock.c @@ -10,19 +10,55 @@   *   Ingo Molnar <mingo@redhat.com>   *   Guillaume Chazarain <guichaz@gmail.com>   * - * Create a semi stable clock from a mixture of other events, including: - *  - gtod + * + * What: + * + * cpu_clock(i) provides a fast (execution time) high resolution + * clock with bounded drift between CPUs. The value of cpu_clock(i) + * is monotonic for constant i. The timestamp returned is in nanoseconds. + * + * ######################### BIG FAT WARNING ########################## + * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can # + * # go backwards !!                                                  # + * #################################################################### + * + * There is no strict promise about the base, although it tends to start + * at 0 on boot (but people really shouldn't rely on that). + * + * cpu_clock(i)       -- can be used from any context, including NMI. + * sched_clock_cpu(i) -- must be used with local IRQs disabled (implied by NMI) + * local_clock()      -- is cpu_clock() on the current cpu. + * + * How: + * + * The implementation either uses sched_clock() when + * !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK, which means in that case the + * sched_clock() is assumed to provide these properties (mostly it means + * the architecture provides a globally synchronized highres time source). + * + * Otherwise it tries to create a semi stable clock from a mixture of other + * clocks, including: + * + *  - GTOD (clock monotomic)   *  - sched_clock()   *  - explicit idle events   * - * We use gtod as base and the unstable clock deltas. The deltas are filtered, - * making it monotonic and keeping it within an expected window. + * We use GTOD as base and use sched_clock() deltas to improve resolution. The + * deltas are filtered to provide monotonicity and keeping it within an + * expected window.   *   * Furthermore, explicit sleep and wakeup hooks allow us to account for time   * that is otherwise invisible (TSC gets stopped).   * - * The clock: sched_clock_cpu() is monotonic per cpu, and should be somewhat - * consistent between cpus (never more than 2 jiffies difference). + * + * Notes: + * + * The !IRQ-safetly of sched_clock() and sched_clock_cpu() comes from things + * like cpufreq interrupts that can change the base clock (TSC) multiplier + * and cause funny jumps in time -- although the filtering provided by + * sched_clock_cpu() should mitigate serious artifacts we cannot rely on it + * in general since for !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK we fully rely on + * sched_clock().   */  #include <linux/spinlock.h>  #include <linux/hardirq.h> @@ -170,6 +206,11 @@ again:  	return val;  } +/* + * Similar to cpu_clock(), but requires local IRQs to be disabled. + * + * See cpu_clock(). + */  u64 sched_clock_cpu(int cpu)  {  	struct sched_clock_data *scd; @@ -237,9 +278,19 @@ void sched_clock_idle_wakeup_event(u64 delta_ns)  }  EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event); -unsigned long long cpu_clock(int cpu) +/* + * As outlined at the top, provides a fast, high resolution, nanosecond + * time source that is monotonic per cpu argument and has bounded drift + * between cpus. + * + * ######################### BIG FAT WARNING ########################## + * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can # + * # go backwards !!                                                  # + * #################################################################### + */ +u64 cpu_clock(int cpu)  { -	unsigned long long clock; +	u64 clock;  	unsigned long flags;  	local_irq_save(flags); @@ -249,6 +300,25 @@ unsigned long long cpu_clock(int cpu)  	return clock;  } +/* + * Similar to cpu_clock() for the current cpu. Time will only be observed + * to be monotonic if care is taken to only compare timestampt taken on the + * same CPU. + * + * See cpu_clock(). + */ +u64 local_clock(void) +{ +	u64 clock; +	unsigned long flags; + +	local_irq_save(flags); +	clock = sched_clock_cpu(smp_processor_id()); +	local_irq_restore(flags); + +	return clock; +} +  #else /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */  void sched_clock_init(void) @@ -264,12 +334,17 @@ u64 sched_clock_cpu(int cpu)  	return sched_clock();  } - -unsigned long long cpu_clock(int cpu) +u64 cpu_clock(int cpu)  {  	return sched_clock_cpu(cpu);  } +u64 local_clock(void) +{ +	return sched_clock_cpu(0); +} +  #endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */  EXPORT_SYMBOL_GPL(cpu_clock); +EXPORT_SYMBOL_GPL(local_clock); diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c index 9d589d8dcd1..1723e2b8c58 100644 --- a/kernel/trace/trace_clock.c +++ b/kernel/trace/trace_clock.c @@ -56,7 +56,7 @@ u64 notrace trace_clock_local(void)   */  u64 notrace trace_clock(void)  { -	return cpu_clock(raw_smp_processor_id()); +	return local_clock();  }  |