Blame view

Documentation/timers/timekeeping.txt 8.77 KB
7806f60e1   Linus Walleij   clocksource: docu...
1
2
3
4
5
6
7
8
9
10
11
12
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  Clock sources, Clock events, sched_clock() and delay timers
  -----------------------------------------------------------
  
  This document tries to briefly explain some basic kernel timekeeping
  abstractions. It partly pertains to the drivers usually found in
  drivers/clocksource in the kernel tree, but the code may be spread out
  across the kernel.
  
  If you grep through the kernel source you will find a number of architecture-
  specific implementations of clock sources, clockevents and several likewise
  architecture-specific overrides of the sched_clock() function and some
  delay timers.
  
  To provide timekeeping for your platform, the clock source provides
  the basic timeline, whereas clock events shoot interrupts on certain points
  on this timeline, providing facilities such as high-resolution timers.
  sched_clock() is used for scheduling and timestamping, and delay timers
  provide an accurate delay source using hardware counters.
  
  
  Clock sources
  -------------
  
  The purpose of the clock source is to provide a timeline for the system that
  tells you where you are in time. For example issuing the command 'date' on
  a Linux system will eventually read the clock source to determine exactly
  what time it is.
  
  Typically the clock source is a monotonic, atomic counter which will provide
  n bits which count from 0 to 2^(n-1) and then wraps around to 0 and start over.
  It will ideally NEVER stop ticking as long as the system is running. It
  may stop during system suspend.
  
  The clock source shall have as high resolution as possible, and the frequency
  shall be as stable and correct as possible as compared to a real-world wall
  clock. It should not move unpredictably back and forth in time or miss a few
  cycles here and there.
  
  It must be immune to the kind of effects that occur in hardware where e.g.
  the counter register is read in two phases on the bus lowest 16 bits first
  and the higher 16 bits in a second bus cycle with the counter bits
  potentially being updated in between leading to the risk of very strange
  values from the counter.
  
  When the wall-clock accuracy of the clock source isn't satisfactory, there
  are various quirks and layers in the timekeeping code for e.g. synchronizing
  the user-visible time to RTC clocks in the system or against networked time
  servers using NTP, but all they do basically is update an offset against
  the clock source, which provides the fundamental timeline for the system.
  These measures does not affect the clock source per se, they only adapt the
  system to the shortcomings of it.
  
  The clock source struct shall provide means to translate the provided counter
  into a nanosecond value as an unsigned long long (unsigned 64 bit) number.
  Since this operation may be invoked very often, doing this in a strict
  mathematical sense is not desirable: instead the number is taken as close as
  possible to a nanosecond value using only the arithmetic operations
  multiply and shift, so in clocksource_cyc2ns() you find:
  
    ns ~= (clocksource * mult) >> shift
  
  You will find a number of helper functions in the clock source code intended
  to aid in providing these mult and shift values, such as
  clocksource_khz2mult(), clocksource_hz2mult() that help determine the
  mult factor from a fixed shift, and clocksource_register_hz() and
  clocksource_register_khz() which will help out assigning both shift and mult
  factors using the frequency of the clock source as the only input.
  
  For real simple clock sources accessed from a single I/O memory location
  there is nowadays even clocksource_mmio_init() which will take a memory
  location, bit width, a parameter telling whether the counter in the
  register counts up or down, and the timer clock rate, and then conjure all
  necessary parameters.
  
  Since a 32-bit counter at say 100 MHz will wrap around to zero after some 43
  seconds, the code handling the clock source will have to compensate for this.
  That is the reason why the clock source struct also contains a 'mask'
  member telling how many bits of the source are valid. This way the timekeeping
  code knows when the counter will wrap around and can insert the necessary
  compensation code on both sides of the wrap point so that the system timeline
  remains monotonic.
  
  
  Clock events
  ------------
  
  Clock events are the conceptual reverse of clock sources: they take a
  desired time specification value and calculate the values to poke into
  hardware timer registers.
  
  Clock events are orthogonal to clock sources. The same hardware
  and register range may be used for the clock event, but it is essentially
  a different thing. The hardware driving clock events has to be able to
  fire interrupts, so as to trigger events on the system timeline. On an SMP
  system, it is ideal (and customary) to have one such event driving timer per
  CPU core, so that each core can trigger events independently of any other
  core.
  
  You will notice that the clock event device code is based on the same basic
  idea about translating counters to nanoseconds using mult and shift
  arithmetic, and you find the same family of helper functions again for
  assigning these values. The clock event driver does not need a 'mask'
  attribute however: the system will not try to plan events beyond the time
  horizon of the clock event.
  
  
  sched_clock()
  -------------
  
  In addition to the clock sources and clock events there is a special weak
  function in the kernel called sched_clock(). This function shall return the
  number of nanoseconds since the system was started. An architecture may or
  may not provide an implementation of sched_clock() on its own. If a local
  implementation is not provided, the system jiffy counter will be used as
  sched_clock().
  
  As the name suggests, sched_clock() is used for scheduling the system,
  determining the absolute timeslice for a certain process in the CFS scheduler
  for example. It is also used for printk timestamps when you have selected to
  include time information in printk for things like bootcharts.
  
  Compared to clock sources, sched_clock() has to be very fast: it is called
  much more often, especially by the scheduler. If you have to do trade-offs
  between accuracy compared to the clock source, you may sacrifice accuracy
  for speed in sched_clock(). It however requires some of the same basic
  characteristics as the clock source, i.e. it should be monotonic.
  
  The sched_clock() function may wrap only on unsigned long long boundaries,
  i.e. after 64 bits. Since this is a nanosecond value this will mean it wraps
  after circa 585 years. (For most practical systems this means "never".)
  
  If an architecture does not provide its own implementation of this function,
  it will fall back to using jiffies, making its maximum resolution 1/HZ of the
  jiffy frequency for the architecture. This will affect scheduling accuracy
  and will likely show up in system benchmarks.
  
  The clock driving sched_clock() may stop or reset to zero during system
  suspend/sleep. This does not matter to the function it serves of scheduling
  events on the system. However it may result in interesting timestamps in
  printk().
  
  The sched_clock() function should be callable in any context, IRQ- and
  NMI-safe and return a sane value in any context.
  
  Some architectures may have a limited set of time sources and lack a nice
  counter to derive a 64-bit nanosecond value, so for example on the ARM
  architecture, special helper functions have been created to provide a
  sched_clock() nanosecond base from a 16- or 32-bit counter. Sometimes the
  same counter that is also used as clock source is used for this purpose.
  
  On SMP systems, it is crucial for performance that sched_clock() can be called
  independently on each CPU without any synchronization performance hits.
  Some hardware (such as the x86 TSC) will cause the sched_clock() function to
  drift between the CPUs on the system. The kernel can work around this by
  enabling the CONFIG_HAVE_UNSTABLE_SCHED_CLOCK option. This is another aspect
  that makes sched_clock() different from the ordinary clock source.
  
  
  Delay timers (some architectures only)
  --------------------------------------
  
  On systems with variable CPU frequency, the various kernel delay() functions
  will sometimes behave strangely. Basically these delays usually use a hard
  loop to delay a certain number of jiffy fractions using a "lpj" (loops per
  jiffy) value, calibrated on boot.
  
  Let's hope that your system is running on maximum frequency when this value
  is calibrated: as an effect when the frequency is geared down to half the
  full frequency, any delay() will be twice as long. Usually this does not
  hurt, as you're commonly requesting that amount of delay *or more*. But
  basically the semantics are quite unpredictable on such systems.
  
  Enter timer-based delays. Using these, a timer read may be used instead of
  a hard-coded loop for providing the desired delay.
  
  This is done by declaring a struct delay_timer and assigning the appropriate
  function pointers and rate settings for this delay timer.
  
  This is available on some architectures like OpenRISC or ARM.