Blame view

kernel/sched/clock.c 8.86 KB
3e51f33fc   Peter Zijlstra   sched: add option...
1
2
3
4
5
  /*
   * sched_clock for unstable cpu clocks
   *
   *  Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
   *
c300ba252   Steven Rostedt   sched_clock: and ...
6
7
8
   *  Updates and enhancements:
   *    Copyright (C) 2008 Red Hat, Inc. Steven Rostedt <srostedt@redhat.com>
   *
3e51f33fc   Peter Zijlstra   sched: add option...
9
10
11
12
   * Based on code by:
   *   Ingo Molnar <mingo@redhat.com>
   *   Guillaume Chazarain <guichaz@gmail.com>
   *
c676329ab   Peter Zijlstra   sched_clock: Add ...
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
   *
   * 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)
3e51f33fc   Peter Zijlstra   sched: add option...
43
44
45
   *  - sched_clock()
   *  - explicit idle events
   *
c676329ab   Peter Zijlstra   sched_clock: Add ...
46
47
48
   * 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.
3e51f33fc   Peter Zijlstra   sched: add option...
49
50
51
52
   *
   * Furthermore, explicit sleep and wakeup hooks allow us to account for time
   * that is otherwise invisible (TSC gets stopped).
   *
c676329ab   Peter Zijlstra   sched_clock: Add ...
53
54
55
56
57
58
59
60
61
   *
   * 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().
3e51f33fc   Peter Zijlstra   sched: add option...
62
   */
3e51f33fc   Peter Zijlstra   sched: add option...
63
  #include <linux/spinlock.h>
6409c4da2   Ingo Molnar   sched: sched_cloc...
64
  #include <linux/hardirq.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
65
  #include <linux/export.h>
b342501cd   Ingo Molnar   sched: allow arch...
66
67
68
  #include <linux/percpu.h>
  #include <linux/ktime.h>
  #include <linux/sched.h>
3e51f33fc   Peter Zijlstra   sched: add option...
69

2c3d103ba   Hugh Dickins   sched: move sched...
70
71
72
73
74
75
76
  /*
   * Scheduler clock - returns current time in nanosec units.
   * This is default implementation.
   * Architectures and sub-architectures can override this.
   */
  unsigned long long __attribute__((weak)) sched_clock(void)
  {
92d23f703   Ron   sched: Fix fallba...
77
78
  	return (unsigned long long)(jiffies - INITIAL_JIFFIES)
  					* (NSEC_PER_SEC / HZ);
2c3d103ba   Hugh Dickins   sched: move sched...
79
  }
b6ac23af2   Divyesh Shah   blkio: fix for mo...
80
  EXPORT_SYMBOL_GPL(sched_clock);
3e51f33fc   Peter Zijlstra   sched: add option...
81

5bb6b1ea6   Peter Zijlstra   sched: Add some c...
82
  __read_mostly int sched_clock_running;
c1955a3d4   Peter Zijlstra   sched_clock: dela...
83

3e51f33fc   Peter Zijlstra   sched: add option...
84
  #ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
b342501cd   Ingo Molnar   sched: allow arch...
85
  __read_mostly int sched_clock_stable;
3e51f33fc   Peter Zijlstra   sched: add option...
86
87
  
  struct sched_clock_data {
3e51f33fc   Peter Zijlstra   sched: add option...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  	u64			tick_raw;
  	u64			tick_gtod;
  	u64			clock;
  };
  
  static DEFINE_PER_CPU_SHARED_ALIGNED(struct sched_clock_data, sched_clock_data);
  
  static inline struct sched_clock_data *this_scd(void)
  {
  	return &__get_cpu_var(sched_clock_data);
  }
  
  static inline struct sched_clock_data *cpu_sdc(int cpu)
  {
  	return &per_cpu(sched_clock_data, cpu);
  }
  
  void sched_clock_init(void)
  {
  	u64 ktime_now = ktime_to_ns(ktime_get());
3e51f33fc   Peter Zijlstra   sched: add option...
108
109
110
111
  	int cpu;
  
  	for_each_possible_cpu(cpu) {
  		struct sched_clock_data *scd = cpu_sdc(cpu);
a381759d6   Peter Zijlstra   sched: fix sched_...
112
  		scd->tick_raw = 0;
3e51f33fc   Peter Zijlstra   sched: add option...
113
114
115
  		scd->tick_gtod = ktime_now;
  		scd->clock = ktime_now;
  	}
a381759d6   Peter Zijlstra   sched: fix sched_...
116
117
  
  	sched_clock_running = 1;
3e51f33fc   Peter Zijlstra   sched: add option...
118
119
120
  }
  
  /*
b342501cd   Ingo Molnar   sched: allow arch...
121
   * min, max except they take wrapping into account
354879bb9   Peter Zijlstra   sched_clock: fix ...
122
123
124
125
126
127
128
129
130
131
132
133
134
   */
  
  static inline u64 wrap_min(u64 x, u64 y)
  {
  	return (s64)(x - y) < 0 ? x : y;
  }
  
  static inline u64 wrap_max(u64 x, u64 y)
  {
  	return (s64)(x - y) > 0 ? x : y;
  }
  
  /*
3e51f33fc   Peter Zijlstra   sched: add option...
135
136
137
   * update the percpu scd from the raw @now value
   *
   *  - filter out backward motion
354879bb9   Peter Zijlstra   sched_clock: fix ...
138
   *  - use the GTOD tick value to create a window to filter crazy TSC values
3e51f33fc   Peter Zijlstra   sched: add option...
139
   */
def0a9b25   Peter Zijlstra   sched_clock: Make...
140
  static u64 sched_clock_local(struct sched_clock_data *scd)
3e51f33fc   Peter Zijlstra   sched: add option...
141
  {
def0a9b25   Peter Zijlstra   sched_clock: Make...
142
143
  	u64 now, clock, old_clock, min_clock, max_clock;
  	s64 delta;
3e51f33fc   Peter Zijlstra   sched: add option...
144

def0a9b25   Peter Zijlstra   sched_clock: Make...
145
146
147
  again:
  	now = sched_clock();
  	delta = now - scd->tick_raw;
354879bb9   Peter Zijlstra   sched_clock: fix ...
148
149
  	if (unlikely(delta < 0))
  		delta = 0;
3e51f33fc   Peter Zijlstra   sched: add option...
150

def0a9b25   Peter Zijlstra   sched_clock: Make...
151
  	old_clock = scd->clock;
354879bb9   Peter Zijlstra   sched_clock: fix ...
152
153
  	/*
  	 * scd->clock = clamp(scd->tick_gtod + delta,
b342501cd   Ingo Molnar   sched: allow arch...
154
155
  	 *		      max(scd->tick_gtod, scd->clock),
  	 *		      scd->tick_gtod + TICK_NSEC);
354879bb9   Peter Zijlstra   sched_clock: fix ...
156
  	 */
3e51f33fc   Peter Zijlstra   sched: add option...
157

354879bb9   Peter Zijlstra   sched_clock: fix ...
158
  	clock = scd->tick_gtod + delta;
def0a9b25   Peter Zijlstra   sched_clock: Make...
159
160
  	min_clock = wrap_max(scd->tick_gtod, old_clock);
  	max_clock = wrap_max(old_clock, scd->tick_gtod + TICK_NSEC);
3e51f33fc   Peter Zijlstra   sched: add option...
161

354879bb9   Peter Zijlstra   sched_clock: fix ...
162
163
  	clock = wrap_max(clock, min_clock);
  	clock = wrap_min(clock, max_clock);
3e51f33fc   Peter Zijlstra   sched: add option...
164

152f9d071   Eric Dumazet   sched_clock: Fix ...
165
  	if (cmpxchg64(&scd->clock, old_clock, clock) != old_clock)
def0a9b25   Peter Zijlstra   sched_clock: Make...
166
  		goto again;
56b906126   Ingo Molnar   sched clock: simp...
167

def0a9b25   Peter Zijlstra   sched_clock: Make...
168
  	return clock;
3e51f33fc   Peter Zijlstra   sched: add option...
169
  }
def0a9b25   Peter Zijlstra   sched_clock: Make...
170
  static u64 sched_clock_remote(struct sched_clock_data *scd)
3e51f33fc   Peter Zijlstra   sched: add option...
171
  {
def0a9b25   Peter Zijlstra   sched_clock: Make...
172
173
174
  	struct sched_clock_data *my_scd = this_scd();
  	u64 this_clock, remote_clock;
  	u64 *ptr, old_val, val;
a1cbcaa9e   Thomas Gleixner   sched_clock: Prev...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  #if BITS_PER_LONG != 64
  again:
  	/*
  	 * Careful here: The local and the remote clock values need to
  	 * be read out atomic as we need to compare the values and
  	 * then update either the local or the remote side. So the
  	 * cmpxchg64 below only protects one readout.
  	 *
  	 * We must reread via sched_clock_local() in the retry case on
  	 * 32bit as an NMI could use sched_clock_local() via the
  	 * tracer and hit between the readout of
  	 * the low32bit and the high 32bit portion.
  	 */
  	this_clock = sched_clock_local(my_scd);
  	/*
  	 * We must enforce atomic readout on 32bit, otherwise the
  	 * update on the remote cpu can hit inbetween the readout of
  	 * the low32bit and the high 32bit portion.
  	 */
  	remote_clock = cmpxchg64(&scd->clock, 0, 0);
  #else
  	/*
  	 * On 64bit the read of [my]scd->clock is atomic versus the
  	 * update, so we can avoid the above 32bit dance.
  	 */
def0a9b25   Peter Zijlstra   sched_clock: Make...
200
201
202
203
  	sched_clock_local(my_scd);
  again:
  	this_clock = my_scd->clock;
  	remote_clock = scd->clock;
a1cbcaa9e   Thomas Gleixner   sched_clock: Prev...
204
  #endif
def0a9b25   Peter Zijlstra   sched_clock: Make...
205
206
207
208
209
210
211
212
213
214
215
  
  	/*
  	 * Use the opportunity that we have both locks
  	 * taken to couple the two clocks: we take the
  	 * larger time as the latest time for both
  	 * runqueues. (this creates monotonic movement)
  	 */
  	if (likely((s64)(remote_clock - this_clock) < 0)) {
  		ptr = &scd->clock;
  		old_val = remote_clock;
  		val = this_clock;
3e51f33fc   Peter Zijlstra   sched: add option...
216
  	} else {
def0a9b25   Peter Zijlstra   sched_clock: Make...
217
218
219
220
221
222
  		/*
  		 * Should be rare, but possible:
  		 */
  		ptr = &my_scd->clock;
  		old_val = this_clock;
  		val = remote_clock;
3e51f33fc   Peter Zijlstra   sched: add option...
223
  	}
def0a9b25   Peter Zijlstra   sched_clock: Make...
224

152f9d071   Eric Dumazet   sched_clock: Fix ...
225
  	if (cmpxchg64(ptr, old_val, val) != old_val)
def0a9b25   Peter Zijlstra   sched_clock: Make...
226
227
228
  		goto again;
  
  	return val;
3e51f33fc   Peter Zijlstra   sched: add option...
229
  }
c676329ab   Peter Zijlstra   sched_clock: Add ...
230
231
232
233
234
  /*
   * Similar to cpu_clock(), but requires local IRQs to be disabled.
   *
   * See cpu_clock().
   */
3e51f33fc   Peter Zijlstra   sched: add option...
235
236
  u64 sched_clock_cpu(int cpu)
  {
b342501cd   Ingo Molnar   sched: allow arch...
237
  	struct sched_clock_data *scd;
def0a9b25   Peter Zijlstra   sched_clock: Make...
238
239
240
  	u64 clock;
  
  	WARN_ON_ONCE(!irqs_disabled());
3e51f33fc   Peter Zijlstra   sched: add option...
241

b342501cd   Ingo Molnar   sched: allow arch...
242
243
  	if (sched_clock_stable)
  		return sched_clock();
a381759d6   Peter Zijlstra   sched: fix sched_...
244

a381759d6   Peter Zijlstra   sched: fix sched_...
245
246
  	if (unlikely(!sched_clock_running))
  		return 0ull;
def0a9b25   Peter Zijlstra   sched_clock: Make...
247
  	scd = cpu_sdc(cpu);
3e51f33fc   Peter Zijlstra   sched: add option...
248

def0a9b25   Peter Zijlstra   sched_clock: Make...
249
250
251
252
  	if (cpu != smp_processor_id())
  		clock = sched_clock_remote(scd);
  	else
  		clock = sched_clock_local(scd);
e4e4e534f   Ingo Molnar   sched clock: reve...
253

3e51f33fc   Peter Zijlstra   sched: add option...
254
255
256
257
258
  	return clock;
  }
  
  void sched_clock_tick(void)
  {
8325d9c09   Peter Zijlstra   sched_clock: clea...
259
  	struct sched_clock_data *scd;
3e51f33fc   Peter Zijlstra   sched: add option...
260
  	u64 now, now_gtod;
8325d9c09   Peter Zijlstra   sched_clock: clea...
261
262
  	if (sched_clock_stable)
  		return;
a381759d6   Peter Zijlstra   sched: fix sched_...
263
264
  	if (unlikely(!sched_clock_running))
  		return;
3e51f33fc   Peter Zijlstra   sched: add option...
265
  	WARN_ON_ONCE(!irqs_disabled());
8325d9c09   Peter Zijlstra   sched_clock: clea...
266
  	scd = this_scd();
3e51f33fc   Peter Zijlstra   sched: add option...
267
  	now_gtod = ktime_to_ns(ktime_get());
a83bc47c3   Steven Rostedt   sched_clock: reco...
268
  	now = sched_clock();
3e51f33fc   Peter Zijlstra   sched: add option...
269

3e51f33fc   Peter Zijlstra   sched: add option...
270
271
  	scd->tick_raw = now;
  	scd->tick_gtod = now_gtod;
def0a9b25   Peter Zijlstra   sched_clock: Make...
272
  	sched_clock_local(scd);
3e51f33fc   Peter Zijlstra   sched: add option...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  }
  
  /*
   * We are going deep-idle (irqs are disabled):
   */
  void sched_clock_idle_sleep_event(void)
  {
  	sched_clock_cpu(smp_processor_id());
  }
  EXPORT_SYMBOL_GPL(sched_clock_idle_sleep_event);
  
  /*
   * We just idled delta nanoseconds (called with irqs disabled):
   */
  void sched_clock_idle_wakeup_event(u64 delta_ns)
  {
1c5745aa3   Thomas Gleixner   sched_clock: prev...
289
290
  	if (timekeeping_suspended)
  		return;
354879bb9   Peter Zijlstra   sched_clock: fix ...
291
  	sched_clock_tick();
3e51f33fc   Peter Zijlstra   sched: add option...
292
293
294
  	touch_softlockup_watchdog();
  }
  EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
c676329ab   Peter Zijlstra   sched_clock: Add ...
295
296
297
298
299
300
301
302
303
304
305
  /*
   * 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)
b9f8fcd55   David Miller   sched: Fix cpu_cl...
306
  {
c676329ab   Peter Zijlstra   sched_clock: Add ...
307
  	u64 clock;
b9f8fcd55   David Miller   sched: Fix cpu_cl...
308
309
310
311
312
313
314
315
  	unsigned long flags;
  
  	local_irq_save(flags);
  	clock = sched_clock_cpu(cpu);
  	local_irq_restore(flags);
  
  	return clock;
  }
c676329ab   Peter Zijlstra   sched_clock: Add ...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  /*
   * 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;
  }
8325d9c09   Peter Zijlstra   sched_clock: clea...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
  #else /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
  
  void sched_clock_init(void)
  {
  	sched_clock_running = 1;
  }
  
  u64 sched_clock_cpu(int cpu)
  {
  	if (unlikely(!sched_clock_running))
  		return 0;
  
  	return sched_clock();
  }
c676329ab   Peter Zijlstra   sched_clock: Add ...
348
  u64 cpu_clock(int cpu)
76a2a6ee8   Peter Zijlstra   sched: sched_cloc...
349
  {
b9f8fcd55   David Miller   sched: Fix cpu_cl...
350
351
  	return sched_clock_cpu(cpu);
  }
76a2a6ee8   Peter Zijlstra   sched: sched_cloc...
352

c676329ab   Peter Zijlstra   sched_clock: Add ...
353
354
355
356
  u64 local_clock(void)
  {
  	return sched_clock_cpu(0);
  }
b9f8fcd55   David Miller   sched: Fix cpu_cl...
357
  #endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
76a2a6ee8   Peter Zijlstra   sched: sched_cloc...
358

4c9fe8ad8   Ingo Molnar   sched: export cpu...
359
  EXPORT_SYMBOL_GPL(cpu_clock);
c676329ab   Peter Zijlstra   sched_clock: Add ...
360
  EXPORT_SYMBOL_GPL(local_clock);