Understanding the Linux Kernel 读书笔记 -Timing Measurements
文章目录
We can distinguish two main kinds of timing measurement that must be performed by the Linux kernel:
- Keeping the current time and date so they can be returned to user programs through the time(), ftime(), and gettimeofday() APIs and used by the kernel itself as timestamps for files and network packets
- Maintaining timers—mechanisms that are able to notify the kernel or a user program that a certain interval of time has elapsed
1 Clock and Timer Circuits
The clock circuits are used both to keep track of the current time of day and to make precise time measurements. The timer circuits are programmed by the kernel, so that they issue interrupts at a fixed, predefined frequency.
1.1 Real Time Clock (RTC)
All PCs include a clock called Real Time Clock (RTC), which is independent of the CPU and all other chips.
Linux uses the RTC only to derive the time and date.
1.2 Time Stamp Counter (TSC)
Starting with the Pentium, 80×86 microprocessors sport a counter that is increased at each clock signal. The counter is accessible through the 64-bit Time Stamp Counter (TSC) register. When using this register, the kernel has to take into consideration the frequency of the clock signal: if, for instance, the clock ticks at 1 GHz, the Time Stamp Counter is increased once every nanosecond.
Linux may take advantage of this register to get much more accurate time measurements than those delivered by the Programmable Interval Timer.
1.3 Programmable Interval Timer (PIT)
Besides the Real Time Clock and the Time Stamp Counter, IBM-compatible PCs include another type of time-measuring device called Programmable Interval Timer (PIT ). The role of a PIT is similar to the alarm clock of a microwave oven: it makes the user aware that the cooking time interval has elapsed. Instead of ringing a bell, this device issues a special interrupt called timer interrupt, which notifies the kernel that one more time interval has elapsed. Another difference from the alarm clock is that the PIT goes on issuing interrupts forever at some fixed frequency established by the kernel.
1.4 CPU Local Timer
The local APIC present in recent 80×86 microprocessors provides yet another time-measuring device: the CPU local timer.
The CPU local timer is a device similar to the Programmable Interval Timer just described that can issue one-shot or periodic interrupts. There are, however, a few differences:
- The APIC’s timer counter is 32bits long,while the PIT’s timer counter is 16 bits long;
- The local APIC timer sends an interrupt only to its processor, while the PIT raises a global interrupt, which may be handled by any CPU in the system.
- The APIC’s timer is based on the bus clock signal,the PIT, which makes use of its own clock signals, can be programmed in a more flexible way.
1.5 High Precision Event Timer (HPET)
The HPET provides a number of hardware timers that can be exploited by the kernel.
The next generation of motherboards will likely support both the HPET and the 8254 PIT; in some future time, however, the HPET is expected to completely replace the PIT.
1.6 ACPI Power Management Timer
The device is actually a simple counter increased at each clock tick.Its clock signal has a fixed frequency of roughly 3.58 MHz.
The ACPI Power Management Timer is preferable to the TSC if the operating system or the BIOS may dynamically lower the frequency or voltage of the CPU to save battery power. On the other hand, the high-frequency of the TSC counter is quite handy for measuring very small time intervals.
However, if an HPET device is present, it should always be preferred to the other circuits because of its richer architecture.
2 The Linux Timekeeping Architecture
Linux’s timekeeping architecture is the set of kernel data structures and functions related to the flow of time.
Linux’s timekeeping architecture depends also on the availability of the Time Stamp Counter (TSC), of the ACPI Power Management Timer, and of the High Precision Event Timer (HPET). The kernel uses two basic timekeeping functions: one to keep the current time up-to-date and another to count the number of nanoseconds that have elapsed within the current second. There are different ways to get the last value. Some methods are more precise and are available if the CPU has a Time Stamp Counter or a HPET; a less-precise method is used in the opposite case.
2.1 Data Structures of the Timekeeping Architecture
2.1.1 The timer object
In order to handle the possible timer sources in a uniform way, the kernel makes use of a “timer object,” which is a descriptor of type timer_opts
consisting of the timer name and of four standard methods.
The cur_timer
variable stores the address of the timer object corresponding to the “best” timer source available in the system.
2.1.2 The jiffies variable
The jiffies
variable is a counter that stores the number of elapsed ticks since the system was started. It is increased by one when a timer interrupt occurs—that is, on every tick.
2.1.3 The xtime variable
The xtime
variable stores the current time and date; it is a structure of type timespec
.
2.2 Timekeeping Architecture in Uniprocessor Systems
2.3 Timekeeping Architecture in Multiprocessor Systems
3 Updating the Time and Date
User programs get the current time and date from the xtime variable. The kernel must periodically update this variable, so that its value is always reasonably accurate.
The update_times()
function, which is invoked by the global timer interrupt handler, updates the value of the xtime
variable.
4 Updating System Statistics
The kernel, among the other time-related duties, must periodically collect various data used for:
- Checking the CPU resource limit of the running processes
- Updating statistics about the local CPU workload
- Computing the average system load
- Profiling the kernel code
5 Software Timers and Delay Functions
A timer is a software facility that allows functions to be invoked at some future moment, after a given time interval has elapsed; a time-out denotes a moment at which the time interval associated with a timer has elapsed.
Linux considers two types of timers called dynamic timers and interval timers. The first type is used by the kernel, while interval timers may be created by processes in User Mode.
Besides software timers, the kernel also makes use of delay functions, which execute a tight instruction loop until a given time interval elapses.
5.1 Dynamic Timers
5.2 An Application of Dynamic Timers: the nanosleep( ) System Call
5.3 Delay Functions
Software timers are useless when the kernel must wait for a short time interval—let’s say, less than a few milliseconds. For instance, often a device driver has to wait for a predefined number of microseconds until the hardware completes some operation. Because a dynamic timer has a significant setup overhead and a rather large minimum wait time (1 millisecond), the device driver cannot conveniently use it.
6 System Calls Related to Timing Measurements
Several system calls allow User Mode processes to read and modify the time and date and to create timers. Let’s briefly review these and discuss how the kernel handles them.
6.1 The time( ) and gettimeofday( ) System Calls
Processes in User Mode can get the current time and date by means of several system calls:
time()
Returns the number of elapsed seconds since midnight at the start of January 1, 1970 (UTC).gettimeofday()
Returns, in a data structure named timeval, the number of elapsed seconds since midnight of January 1, 1970 (UTC) and the number of elapsed microseconds in the last second.