Linux time Subsystem 3: Time maintainer: timekeeper

Source: Internet
Author: User

The first two sections of this series discuss clock sources for timing: clocksource and some representation of kernel internal time, but for real users, we perceive the real time of the real world, that is, the so-called wall time. clocksource can only provide a period of continuous increase at a given frequency, how to associate it with real wall time? The content of this section is to discuss this point.

1. Time Type

The kernel manages a variety of times, including:

  • RTC time
  • Wall time: Wall time
  • Monotonic time
  • Raw monotonic time
  • Boot time: Total Start Time

RTC timeIn PC, RTC time is also called CMOS time, which is usually implemented by a dedicated timing hardware. The software can read the hardware to obtain time information such as year, month, day, hour, minute, and second, in an embedded system, a dedicated RTC chip is used, and RTC is directly integrated into the SoC chip to read a register in the SOC to obtain the current time information. In general, RTC is a kind of sustainable timing. That is to say, no matter whether the system is powered on or not, the time information in RTC will not be lost, and the timing will continue, A backup battery is usually used to separately power the RTC hardware. Due to the diversity of RTC hardware, developers need to provide drivers for each RTC clock hardware. The kernel and user space access the RTC hardware through the driver to obtain or set the time information.

XtimeLike RTC time, xtime is the wall time used by people in daily life, but the accuracy of RTC time is usually relatively low. In most cases, it can only reach the precision in milliseconds, if the external RTC chip is used, the access speed is also slow. Therefore, the kernel maintains another wall time: xtime, depending on the clocksource used for xtime timing, its precision can even reach the nanosecond level, because xtime is actually a variable in the memory, and its access speed is very fast. The kernel uses xtime for most of the time to obtain the current time information. Xtime records the number of nanoseconds that have elapsed since the 24th hour of January 1, 1970 to the current time.

Monotonic timeThis time has been increasing monotonically since the system started up. It does not generate a hop because of the user's adjustment time, but does not calculate the system sleep time. That is to say, when the system sleep, the monotoic time does not increase progressively.

Raw monotonic timeThis time is similar to the monotonic time, and it is also a monotonically increasing time. The only difference is that raw monotonic time is "purer" and will not be affected by NTP time adjustment, it represents the time statistics of the system's independent clock hardware.

Boot timeIt is the same as monotonic time, but will be tired and the system sleep time, it represents the total time after the system is powered on.

Time Type Precision (Statistical Unit) Access speed Accumulated sleep time Affected by NTP Adjustment
RTC Low Slow Yes Yes
Xtime High Fast Yes Yes
Monotonic High Fast No Yes
Raw monotonic High Fast No No
Boot time High Fast Yes Yes

2. struct timekeeper

The kernel uses the timekeeper structure to organize time-related data. Its definition is as follows:

struct timekeeper {struct clocksource *clock;    /* Current clocksource used for timekeeping. */u32mult;    /* NTP adjusted clock multiplier */intshift;/* The shift value of the current clocksource. */cycle_t cycle_interval;/* Number of clock cycles in one NTP interval. */u64xtime_interval;/* Number of clock shifted nano seconds in one NTP interval. */s64xtime_remainder;/* shifted nano seconds left over when rounding cycle_interval */u32raw_interval;/* Raw nano seconds accumulated per NTP interval. */u64xtime_nsec;/* Clock shifted nano seconds remainder not stored in xtime.tv_nsec. *//* Difference between accumulated time and NTP time in ntp * shifted nano seconds. */s64ntp_error;/* Shift conversion between clock shifted nano seconds and * ntp shifted nano seconds. */intntp_error_shift;struct timespec xtime;/* The current time */struct timespec wall_to_monotonic;struct timespec total_sleep_time;/* time spent in suspend */struct timespec raw_time;/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ktime_t offs_real;/* Offset clock monotonic -> clock realtime */ktime_t offs_boot;/* Offset clock monotonic -> clock boottime */seqlock_t lock;/* Seqlock for all timekeeper values */};

The xtime field is the wall time mentioned above. It is a variable in the timespec structure and records the time passed since January 1, January 1, 1970. Because it is a timespec structure, therefore, its precision can reach the nanosecond level. Of course, it depends on whether the system hardware supports this precision.

In addition to using xtime to express the real time on the wall, the kernel also maintains another time: Monotonic time, which can be understood as the time elapsed since the system was started, this time can only increase monotonically. It can be understood that although xtime is also increasing normally, after all, you can adjust the time on the wall forward or backward to modify the xtime value. However, the monotonic time cannot be used in the past and can only be increased progressively after the system is started. The strange thing is that the kernel does not directly define such a variable to record monotonic time. Instead, it defines a variable wall_to_monotonic and records the offset between the wall time and monotonic time, to obtain the monotonic time, add xtime and wall_to_monotonic. Because the default monotonic time at startup is 0, the value of wall_to_monotonic is actually a negative number, which is initialized at the same time as xtime, see the timekeeping_init function.

To calculate the monotonic time, you need to remove the time spent during system sleep. The kernel uses total_sleep_time to record the sleep time. After each sleep, it reaccumulates the time and adjusts the value of wall_to_monotonic, after the system sleep, the monotonic time will not change. Because the wall_to_monotonic value is adjusted. Therefore, to obtain the boot time, you must add the value of this variable:

void get_monotonic_boottime(struct timespec *ts){        ......do {seq = read_seqbegin(&timekeeper.lock);*ts = timekeeper.xtime;tomono = timekeeper.wall_to_monotonic;sleep = timekeeper.total_sleep_time;nsecs = timekeeping_get_ns();} while (read_seqretry(&timekeeper.lock, seq));set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);}

Raw_timeThe field is used to indicate the real hardware time, that is, the raw monotonic time mentioned above. It is not affected by the time adjustment. Although monotonic time is not affected by settimeofday, but it will be affected by NTP adjustment, but raw_time is not affected by NTP. It is actually increasing monotonically after the machine is started. Xtime, monotonic-time, and raw_time can be obtained through the clock_gettime function of the user space. The corresponding ID parameters are clock_realtime, clock_monotonic, and clock_monotonic_raw.

The clock field points to the clock source currently used by Timekeeper. The xtime, monotonic time, and raw time are all timing operations based on the clock source, when a new clock source with higher precision is registered, the change_clocksource function will be called through the timekeeping_notify function, timekeeper. the clock field is updated and points to the new clocksource.

In earlier kernel versions, xtime, wall_to_monotonic, and raw_time were actually defined as Global static variables. In my current version (v3.4.10), these variables were moved into the timekeeper structure, now you only need to maintain a global static timekeeper variable:

static struct timekeeper timekeeper;

3. timekeeper Initialization

Timekeeper Initialization is completed by timekeeping_init. This function is called in the initialization sequence of start_kernel. timekeeping_init first obtains the current time from RTC:

void __init timekeeping_init(void){struct clocksource *clock;unsigned long flags;struct timespec now, boot;read_persistent_clock(&now);read_boot_clock(&boot);

Then perform necessary initialization for the lock and NTP:

seqlock_init(&timekeeper.lock);ntp_init();

Then obtain the default clocksource. If the platform does not implement the clocksource_default_clock function again, the default clocksource is the clocksource_jiffies Based on jiffies, and then associate the timekeeper and clocksource through the internal functions of the listener:

write_seqlock_irqsave(&timekeeper.lock, flags);clock = clocksource_default_clock();if (clock->enable)clock->enable(clock);timekeeper_setup_internals(clock);

Use the current RTC time to initialize xtime, raw_time, wall_to_monotonic and other fields:

timekeeper.xtime.tv_sec = now.tv_sec;timekeeper.xtime.tv_nsec = now.tv_nsec;timekeeper.raw_time.tv_sec = 0;timekeeper.raw_time.tv_nsec = 0;if (boot.tv_sec == 0 && boot.tv_nsec == 0) {boot.tv_sec = timekeeper.xtime.tv_sec;boot.tv_nsec = timekeeper.xtime.tv_nsec;}set_normalized_timespec(&timekeeper.wall_to_monotonic,-boot.tv_sec, -boot.tv_nsec);

Finally, initialization represents the offs_real field of the Offset between the real-time and monotonic time. The total_sleep_time field is initialized to 0:

update_rt_offset();timekeeper.total_sleep_time.tv_sec = 0;timekeeper.total_sleep_time.tv_nsec = 0;write_sequnlock_irqrestore(&timekeeper.lock, flags);
}

Because the xtime field is stored in the memory, the time information cannot be saved after the system powers down, so the correct time information must be synchronized from RTC through timekeeping_init each time it is started. Among them, read_persistent_clock and read_boot_clock are platform-level functions used to obtain the RTC hardware time and startup time respectively. However, it is worth noting that so far (my code tree is based on version 3.4 ), in the arm system, only the tegra and OMAP platforms implement the read_persistent_clock function. If the platform does not implement this function, the kernel provides a default implementation:

void __attribute__((weak)) read_persistent_clock(struct timespec *ts){ts->tv_sec = 0;ts->tv_nsec = 0;}
void __attribute__((weak)) read_boot_clock(struct timespec *ts){ts->tv_sec = 0;ts->tv_nsec = 0;}

So how do other arm platforms initialize xtime? The answer is the config_rtc_hctosys Kernel configuration item. After this configuration is enabled, the driver/RTC/hctosys. C will be compiled into the system. The rtc_hctosys function initializes the xtime variable during system initialization through do_settimeofday:

static int __init rtc_hctosys(void) {         ......         err = rtc_read_time(rtc, &tm);         ......        rtc_tm_to_time(&tm, &tv.tv_sec);         do_settimeofday(&tv);         ......         return err; } late_initcall(rtc_hctosys);

4. Update Time

Once the xtime Initialization is complete, timekeeper starts to be independent of RTC and uses its associated clocksource to update the time. Depending on the Kernel configuration items, the Update time operation frequency is also different. If the no_hz option is not configured, The do_timer will be called once for each tick scheduled interruption period. On the contrary, if the no_hz option is configured, do_timer may be called only once after several tick requests. Of course, the input parameter is the number of tick cycles between this update and the last update, the system will ensure that do_timer is called within the max_idle_ns time of clocksource to prevent clocksource overflow:

void do_timer(unsigned long ticks){jiffies_64 += ticks;update_wall_time();calc_global_load(ticks);}

In do_timer, The jiffies_64 variable is accumulated accordingly, and then the xtime and other time update operations are completed in update_wall_time. The core operation of the update time is to read the Count value of the associated clocksource, add it to xtime and other fields, and design the NTP time adjustment code. The detailed code will not be pasted.

5. Get time

Timekeeper provides a series of interfaces for obtaining various time information.

  • Void getboottime (struct timespec * TS); obtains the real-time of the system startup.
  • Void get_monotonic_boottime (struct timespec * TS); obtains the time passed since the system was started, including the sleep time.
  • Ktime_t ktime_get_boottime (void); obtains the C time passed by the system since it was started, including the sleep time. The ktime type is returned.
  • Ktime_t ktime_get (void); obtain the C time passed by the system since it was started, excluding the sleep time. ktime type is returned.
  • Void ktime_get_ts (struct timespec * TS); obtains the C time passed by the system since it was started, excluding the sleep time. The timespec structure is returned.
  • Unsigned long get_seconds (void); returns the second count value in xtime.
  • Struct timespec current_kernel_time (void); returns the xtime of the last kernel update, excluding the Count value of clocksource from the last update to the present.
  • Void getnstimeofday (struct timespec * TS); get the current time and return the timespec Structure
  • Void do_gettimeofday (struct timeval * TV); get the current time, return the timeval Structure

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.