schedule -> __schedule -> update_rq_clock -> sched_clock_cpu -> sched_clock_remote / sched_clock_local
static u64 sched_clock_remote(struct sched_clock_data *scd)
{
struct sched_clock_data *my_scd = this_scd();
u64 this_clock, remote_clock;
u64 *ptr, old_val, val;
#if BITS_PER_LONG != 64
again:
this_clock = sched_clock_local(my_scd);
读取本地scd
remote_clock = cmpxchg64(&scd->clock, 0, 0);
读取传入cpu的scd,强制原子
#else
sched_clock_local(my_scd);
again:
this_clock = my_scd->clock;
remote_clock = scd->clock;
64位内核读取属于原子操作,所以不强制原子
#endif
if (likely((s64)(remote_clock - this_clock) < 0)) {
如果远程clock小于当前clock
当前cpu的clock刚刚更新,所以大概率比远程cpu的clock更多
ptr = &scd->clock;
old_val = remote_clock;
val = this_clock;
} else {
ptr = &my_scd->clock;
old_val = this_clock;
val = remote_clock;
}
if (cmpxchg64(ptr, old_val, val) != old_val)
goto again;
对比远程与本地cpu的clock:
如果远程 < 本地 那么设置远程clock为本地clock
如果远程 > 本地 那么设置本地clock为远程clokc
return val;
返回最新的clock
}
static u64 sched_clock_local(struct sched_clock_data *scd)
{
u64 now, clock, old_clock, min_clock, max_clock, gtod;
s64 delta;
again:
now = sched_clock();
获取sced_clock
这里只是获取epoch_ns的值,epoch_ns会在update_sched_clock中更新
update_sched_clock主要在sched_clock_poll中执行
sched_clock_poll被注册到sched_clock_timer中
sched_clock_timer应该会定期触发
delta = now - scd->tick_raw;
if (unlikely(delta < 0))
delta = 0;
当前clock如果小于tick_raw 没搞懂这是什么东西
old_clock = scd->clock;
gtod = scd->tick_gtod + __gtod_offset;
clock = gtod + delta;
min_clock = wrap_max(gtod, old_clock);
max_clock = wrap_max(old_clock, gtod + TICK_NSEC);
clock = wrap_max(clock, min_clock);
clock = wrap_min(clock, max_clock);
if (cmpxchg64(&scd->clock, old_clock, clock) != old_clock)
goto again;
return clock;
不清楚这一大堆是啥,反正就是返回了个本地clock
}
unsigned long long notrace sched_clock(void)
{
u64 cyc, res;
unsigned int seq;
struct clock_read_data *rd;
do {
seq = raw_read_seqcount(&cd.seq);
顺序锁
rd = cd.read_data + (seq & 1);
读read_data[0]或者read_data[1],read_data[1]可能是backup
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
rd->sched_clock_mask;
read_sched_clock立刻返回经过小修改的jiffies,
epoch_cyc也是jiffies,不过这里的epoch_cyc是在update_sched_clock中更新的
sched_clock_mask是一个掩码,这里貌似是32个1,
所以返回值cyc就是上一个update_sched_clock到当前时刻的延迟值
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
延迟cyc经过加工编程ns延迟,并更新epoch_ns
即(cyc * mult )>> shift
mult与shift是通过clocks_calc_mult_shift计算出来的
} while (read_seqcount_retry(&cd.seq, seq));
return res;
}