sched_clock为什么要retry
来源:互联网 发布:wpsexcel数据分析工具 编辑:程序博客网 时间:2024/06/07 01:12
前面讲了sched_clock 会返回当前从arch_time 读取的时间,但是计算的时候有个epoch_cyc 和 epoch_ns也需要实时更新.
unsigned long long notrace sched_clock(void)
{
u64 cyc, res;
unsigned long seq;
struct clock_read_data *rd;
do {
seq = raw_read_seqcount(&cd.seq);
rd = cd.read_data + (seq & 1);
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
rd->sched_clock_mask;
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
} while (read_seqcount_retry(&cd.seq, seq));
return res;
}
那这两个值是在哪里更新的呢?
答案是sched_clock_postinit
void __init sched_clock_postinit(void)
{
/*
* If no sched_clock() function has been provided at that point,
* make it the final one one.
*/
if (cd.actual_read_sched_clock == jiffy_sched_clock_read)
sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
update_sched_clock();
/*
* Start the timer to keep sched_clock() properly updated and
* sets the initial epoch.
*/
hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sched_clock_timer.function = sched_clock_poll;
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
}
这个函数会初始化一个high time,这个high time的expiry time,也就是第二个参数是在sched_clock_register的时候更新的
/* Calculate how many nanosecs until we risk wrapping */
wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask, NULL);
cd.wrap_kt = ns_to_ktime(wrap);
这个high time的callback函数是sched_clock_poll。
static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
{
update_sched_clock();
hrtimer_forward_now(hrt, cd.wrap_kt);
return HRTIMER_RESTART;
}
这个函数会调用hrtimer_forward_now 来让持续推动high time向前,会在update_sched_clock->update_clock_read_data 中更新epoch_cyc 和 epoch_ns
static void update_clock_read_data(struct clock_read_data *rd)
{
/* update the backup (odd) copy with the new data */
cd.read_data[1] = *rd;
/* steer readers towards the odd copy */
raw_write_seqcount_latch(&cd.seq);
/* now its safe for us to update the normal (even) copy */
cd.read_data[0] = *rd;
/* switch readers back to the even copy */
raw_write_seqcount_latch(&cd.seq);
}
注意这个函数更新的时候分两次更新。
static inline void raw_write_seqcount_latch(seqcount_t *s)
{
smp_wmb(); /* prior stores before incrementing "sequence" */
s->sequence++;
smp_wmb(); /* increment "sequence" before following stores */
}
在raw_write_seqcount_latch 函数中会增加s->sequence++
这也是为什么在sched_clock 会retry的原因。
unsigned long long notrace sched_clock(void)
{
u64 cyc, res;
unsigned long seq;
struct clock_read_data *rd;
do {
seq = raw_read_seqcount(&cd.seq);
rd = cd.read_data + (seq & 1);
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
rd->sched_clock_mask;
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
} while (read_seqcount_retry(&cd.seq, seq));
return res;
}
在read_seqcount_retry->__read_seqcount_retry 中retry的条件如下。如果前两次读的s->sequence 不一样,就继续读。
static inline int __read_seqcount_retry(const seqcount_t *s, unsigned start)
{
return unlikely(s->sequence != start);
}
不一样的原因就是sched_clock在读的时候update_clock_read_data也在更新s->sequence。因此会持续读,直到update_clock_read_data 更新完毕
unsigned long long notrace sched_clock(void)
{
u64 cyc, res;
unsigned long seq;
struct clock_read_data *rd;
do {
seq = raw_read_seqcount(&cd.seq);
rd = cd.read_data + (seq & 1);
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
rd->sched_clock_mask;
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
} while (read_seqcount_retry(&cd.seq, seq));
return res;
}
那这两个值是在哪里更新的呢?
答案是sched_clock_postinit
void __init sched_clock_postinit(void)
{
/*
* If no sched_clock() function has been provided at that point,
* make it the final one one.
*/
if (cd.actual_read_sched_clock == jiffy_sched_clock_read)
sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
update_sched_clock();
/*
* Start the timer to keep sched_clock() properly updated and
* sets the initial epoch.
*/
hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sched_clock_timer.function = sched_clock_poll;
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
}
这个函数会初始化一个high time,这个high time的expiry time,也就是第二个参数是在sched_clock_register的时候更新的
/* Calculate how many nanosecs until we risk wrapping */
wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask, NULL);
cd.wrap_kt = ns_to_ktime(wrap);
这个high time的callback函数是sched_clock_poll。
static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
{
update_sched_clock();
hrtimer_forward_now(hrt, cd.wrap_kt);
return HRTIMER_RESTART;
}
这个函数会调用hrtimer_forward_now 来让持续推动high time向前,会在update_sched_clock->update_clock_read_data 中更新epoch_cyc 和 epoch_ns
static void update_clock_read_data(struct clock_read_data *rd)
{
/* update the backup (odd) copy with the new data */
cd.read_data[1] = *rd;
/* steer readers towards the odd copy */
raw_write_seqcount_latch(&cd.seq);
/* now its safe for us to update the normal (even) copy */
cd.read_data[0] = *rd;
/* switch readers back to the even copy */
raw_write_seqcount_latch(&cd.seq);
}
注意这个函数更新的时候分两次更新。
static inline void raw_write_seqcount_latch(seqcount_t *s)
{
smp_wmb(); /* prior stores before incrementing "sequence" */
s->sequence++;
smp_wmb(); /* increment "sequence" before following stores */
}
在raw_write_seqcount_latch 函数中会增加s->sequence++
这也是为什么在sched_clock 会retry的原因。
unsigned long long notrace sched_clock(void)
{
u64 cyc, res;
unsigned long seq;
struct clock_read_data *rd;
do {
seq = raw_read_seqcount(&cd.seq);
rd = cd.read_data + (seq & 1);
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
rd->sched_clock_mask;
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
} while (read_seqcount_retry(&cd.seq, seq));
return res;
}
在read_seqcount_retry->__read_seqcount_retry 中retry的条件如下。如果前两次读的s->sequence 不一样,就继续读。
static inline int __read_seqcount_retry(const seqcount_t *s, unsigned start)
{
return unlikely(s->sequence != start);
}
不一样的原因就是sched_clock在读的时候update_clock_read_data也在更新s->sequence。因此会持续读,直到update_clock_read_data 更新完毕
0 0
- sched_clock为什么要retry
- sched_clock
- 基于TCP的通信为什么需要RETRY
- sched_clock()、current_kernel_time()、getnstimeofday()
- ruby retry
- Retry Class
- php retry
- Retry模式
- spring-retry
- spring-retry
- Retry机制
- Default retry will not retry every command
- break, next, redo, retry
- HttpClient的retry设置
- TestNG - Failed retry
- Spring retry基本使用
- Spring Retry中文文档
- Spring Retry实现原理
- OpenMP入门程序
- Android----微信支付
- maven 工程启动找不到 Spring ContextLoaderListener 的解决办法
- Android 系列 2.9设置首次运行首选项
- windows10 oracle 00119 和 00132终于搞定了,太不容易了!
- sched_clock为什么要retry
- JAVA bean与XML互转的利器---XStream
- R--SVM支持向量机
- RxBus
- PHP代码优化细节
- ssh上传下载文件
- 80老翁谈人生(321):CSDN政治违纪的事实证据
- J2EE进阶(二十)MyEclipse无法启动--Runtime Environment (JRE) or Java Development Kit (JDK) must be available
- PHP magic_quotes_gpc的详细使用方法