Blame view

kernel/sched/clock.c 8 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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  	struct sched_clock_data *my_scd = this_scd();
  	u64 this_clock, remote_clock;
  	u64 *ptr, old_val, val;
  
  	sched_clock_local(my_scd);
  again:
  	this_clock = my_scd->clock;
  	remote_clock = scd->clock;
  
  	/*
  	 * 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...
191
  	} else {
def0a9b25   Peter Zijlstra   sched_clock: Make...
192
193
194
195
196
197
  		/*
  		 * Should be rare, but possible:
  		 */
  		ptr = &my_scd->clock;
  		old_val = this_clock;
  		val = remote_clock;
3e51f33fc   Peter Zijlstra   sched: add option...
198
  	}
def0a9b25   Peter Zijlstra   sched_clock: Make...
199

152f9d071   Eric Dumazet   sched_clock: Fix ...
200
  	if (cmpxchg64(ptr, old_val, val) != old_val)
def0a9b25   Peter Zijlstra   sched_clock: Make...
201
202
203
  		goto again;
  
  	return val;
3e51f33fc   Peter Zijlstra   sched: add option...
204
  }
c676329ab   Peter Zijlstra   sched_clock: Add ...
205
206
207
208
209
  /*
   * Similar to cpu_clock(), but requires local IRQs to be disabled.
   *
   * See cpu_clock().
   */
3e51f33fc   Peter Zijlstra   sched: add option...
210
211
  u64 sched_clock_cpu(int cpu)
  {
b342501cd   Ingo Molnar   sched: allow arch...
212
  	struct sched_clock_data *scd;
def0a9b25   Peter Zijlstra   sched_clock: Make...
213
214
215
  	u64 clock;
  
  	WARN_ON_ONCE(!irqs_disabled());
3e51f33fc   Peter Zijlstra   sched: add option...
216

b342501cd   Ingo Molnar   sched: allow arch...
217
218
  	if (sched_clock_stable)
  		return sched_clock();
a381759d6   Peter Zijlstra   sched: fix sched_...
219

a381759d6   Peter Zijlstra   sched: fix sched_...
220
221
  	if (unlikely(!sched_clock_running))
  		return 0ull;
def0a9b25   Peter Zijlstra   sched_clock: Make...
222
  	scd = cpu_sdc(cpu);
3e51f33fc   Peter Zijlstra   sched: add option...
223

def0a9b25   Peter Zijlstra   sched_clock: Make...
224
225
226
227
  	if (cpu != smp_processor_id())
  		clock = sched_clock_remote(scd);
  	else
  		clock = sched_clock_local(scd);
e4e4e534f   Ingo Molnar   sched clock: reve...
228

3e51f33fc   Peter Zijlstra   sched: add option...
229
230
231
232
233
  	return clock;
  }
  
  void sched_clock_tick(void)
  {
8325d9c09   Peter Zijlstra   sched_clock: clea...
234
  	struct sched_clock_data *scd;
3e51f33fc   Peter Zijlstra   sched: add option...
235
  	u64 now, now_gtod;
8325d9c09   Peter Zijlstra   sched_clock: clea...
236
237
  	if (sched_clock_stable)
  		return;
a381759d6   Peter Zijlstra   sched: fix sched_...
238
239
  	if (unlikely(!sched_clock_running))
  		return;
3e51f33fc   Peter Zijlstra   sched: add option...
240
  	WARN_ON_ONCE(!irqs_disabled());
8325d9c09   Peter Zijlstra   sched_clock: clea...
241
  	scd = this_scd();
3e51f33fc   Peter Zijlstra   sched: add option...
242
  	now_gtod = ktime_to_ns(ktime_get());
a83bc47c3   Steven Rostedt   sched_clock: reco...
243
  	now = sched_clock();
3e51f33fc   Peter Zijlstra   sched: add option...
244

3e51f33fc   Peter Zijlstra   sched: add option...
245
246
  	scd->tick_raw = now;
  	scd->tick_gtod = now_gtod;
def0a9b25   Peter Zijlstra   sched_clock: Make...
247
  	sched_clock_local(scd);
3e51f33fc   Peter Zijlstra   sched: add option...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  }
  
  /*
   * 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...
264
265
  	if (timekeeping_suspended)
  		return;
354879bb9   Peter Zijlstra   sched_clock: fix ...
266
  	sched_clock_tick();
3e51f33fc   Peter Zijlstra   sched: add option...
267
268
269
  	touch_softlockup_watchdog();
  }
  EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
c676329ab   Peter Zijlstra   sched_clock: Add ...
270
271
272
273
274
275
276
277
278
279
280
  /*
   * 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...
281
  {
c676329ab   Peter Zijlstra   sched_clock: Add ...
282
  	u64 clock;
b9f8fcd55   David Miller   sched: Fix cpu_cl...
283
284
285
286
287
288
289
290
  	unsigned long flags;
  
  	local_irq_save(flags);
  	clock = sched_clock_cpu(cpu);
  	local_irq_restore(flags);
  
  	return clock;
  }
c676329ab   Peter Zijlstra   sched_clock: Add ...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  /*
   * 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...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  #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 ...
323
  u64 cpu_clock(int cpu)
76a2a6ee8   Peter Zijlstra   sched: sched_cloc...
324
  {
b9f8fcd55   David Miller   sched: Fix cpu_cl...
325
326
  	return sched_clock_cpu(cpu);
  }
76a2a6ee8   Peter Zijlstra   sched: sched_cloc...
327

c676329ab   Peter Zijlstra   sched_clock: Add ...
328
329
330
331
  u64 local_clock(void)
  {
  	return sched_clock_cpu(0);
  }
b9f8fcd55   David Miller   sched: Fix cpu_cl...
332
  #endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
76a2a6ee8   Peter Zijlstra   sched: sched_cloc...
333

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