Skip to the content.

time keeping 机制中为什么忽视 85ns 的延迟

原来在这里:

认为问题的关键在:

	/*
	 * With NO_HZ we may have to accumulate many cycle_intervals
	 * (think "ticks") worth of time at once. To do this efficiently,
	 * we calculate the largest doubling multiple of cycle_intervals
	 * that is smaller than the offset.  We then accumulate that
	 * chunk in one go, and then try to consume the next smaller
	 * doubled multiple.
	 */
	shift = ilog2(offset) - ilog2(tk->cycle_interval); // tk->cycle_interval = 2995200
	shift = max(0, shift);
	/* Bound shift to one less than what overflows tick_length */
	maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
	shift = min(shift, maxshift);
	while (offset >= tk->cycle_interval) {
    // cycle_interval 的单位是 khz ,而 offset 是 cycle
    // 可以理解 tk->cycle_interval 为,多少个 cycle 作为一个 interval 来统计一次
		offset = logarithmic_accumulation(tk, offset, shift, &clock_set);
		if (offset < tk->cycle_interval<<shift)
			shift--;
	}
$ p tk->tkr_raw.shift
$9 = 24

$ p tk->tkr_raw.mult
$10 = 5601368

$ p tk->raw_interval
$12 = 16777217433600

$ p  tk->cycle_interval
$15 = 2995200

raw_interval 就是用的 mult * interval

In [1]: 5601368 * 2995200
Out[1]: 16777217433600
	tk->raw_interval = interval * clock->mult;

关键在于这里:

	/* Accumulate raw time */
	tk->tkr_raw.xtime_nsec += tk->raw_interval << shift;
	snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
	while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) {
		tk->tkr_raw.xtime_nsec -= snsec_per_sec;
		tk->raw_sec++;
	}

此外还有这里

static inline void tk_normalize_xtime(struct timekeeper *tk)
{
	while (tk->tkr_mono.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_mono.shift)) {
		tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
		tk->xtime_sec++;
	}
	while (tk->tkr_raw.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_raw.shift)) {
		tk->tkr_raw.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
		tk->raw_sec++;
	}
}

以及这里

static void tk_xtime_add(struct timekeeper *tk, const struct timespec64 *ts)
{
	tk->xtime_sec += ts->tv_sec;
	tk->tkr_mono.xtime_nsec += (u64)ts->tv_nsec << tk->tkr_mono.shift;
	tk_normalize_xtime(tk);
}

基于原则就是,当和 xtime_nsec ,尽量使用 mult * cycle 才可以

以及在 accumulate_nsecs_to_secs 中

static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
{
	u64 nsecps = (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
	unsigned int clock_set = 0;

	while (tk->tkr_mono.xtime_nsec >= nsecps) {
		int leap;

总之,就是任何 shift 和 hz 的时候都是需要小心的。

但是 timekeeping_apply_adjustment 中会去调整 interval

	tk->xtime_interval += interval;

但是还好,tk_setup_internals 中,这里有很多

	tk->cycle_interval = interval;

	/* Go back from cycles -> shifted ns */
	tk->xtime_interval = interval * clock->mult;
	tk->xtime_remainder = ntpinterval - tk->xtime_interval;
	tk->raw_interval = interval * clock->mult;

还好,不是去调整 raw_interval 。

xtime_remainder 是用于解决这个问题的吗?

	tk->xtime_interval = interval * clock->mult;
	tk->xtime_remainder = ntpinterval - tk->xtime_interval;
	tk->raw_interval = interval * clock->mult;

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。