亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Linux時間系統:時鐘源clocsource

2019-11-09 19:04:09
字體:
來源:轉載
供稿:網友

時鐘源(clock source)

clock source顧名思義就是提供給系統提供時鐘的時鐘源。 clock source負責讀取芯片中按時間增加的值(所謂cycle),并提供給timekeeper,當然也要提供按cycle的值計算時間間隔的內容。 clocksource以及timer相關的內容都在kernel/kernel/time目錄下面。

obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.oobj-y += timeconv.o posix-clock.o alarmtimer.oobj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.oobj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.oobj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o tick-broadcast-hrtimer.oobj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.oobj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.oobj-$(CONFIG_TICK_ONESHOT) += tick-sched.oobj-$(CONFIG_TIMER_STATS) += timer_stats.o

下面來看一下時鐘源是怎么注冊上去,怎么提供計算時間的內容給timekeeper。

1. 時鐘源注冊過程:

linux可以有很多時鐘源,其中一種時鐘源是jiffies。還有就是平臺相關的時鐘源,精度較高。 當然在注冊了很多種時鐘源之后,linux內核也用某種方式去選擇當前的時鐘源來保證最好的精度。 這里寫圖片描述

1)jiffies時鐘源注冊過程:

jiffies我們知道就是一秒鐘會增加相當于HZ大小的一個變量。 首先需要根據時鐘源,填充clocksource相關數據結構中的成員。

static struct clocksource clocksource_jiffies = { .name= "jiffies", .rating= 1, .read= jiffies_read, /*讀取當前jiffies*/ .mask= 0xffffffff, /*32bits*/ .mult= NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */ .shift= JIFFIES_SHIFT,};

從這個例子,可以看出來 (mult>>shift)*cloclsource->read() 這個讀的就是jiffies數。 當然如果要注冊一些更高精度的時鐘源,mult和shift要進行小心的計算,以保證其值不會溢出。這個后面再看。

2. 平臺相關的時鐘源

int clocksource_register(struct clocksource *cs){ /* calculate max adjustment for given mult/shift */ cs->maxadj = clocksource_max_adjustment(cs); /*計算相當于mult值得11%賦給maxadj*/ /* calculate max idle time permitted for this clocksource */ cs->max_idle_ns = clocksource_max_deferment(cs); /*max_idle_ns計算方法看下面*/ mutex_lock(&clocksource_mutex); clocksource_enqueue(cs); //把注冊的clock source 添加到clocksource_list鏈表中,按rate的降序排序 clocksource_enqueue_watchdog(cs); clocksource_select(); //按rate選擇最佳的clocksource,當然這里rate哪個大就選哪 個,, mutex_unlock(&clocksource_mutex); return 0;}static u64 clocksource_max_deferment(struct clocksource *cs){ u64 max_nsecs, max_cycles; max_cycles = 1ULL << (63 - (ilog2(cs->mult + cs->maxadj) + 1)); /* 上面的計算出來就是2的63次方 = max_cycles*(cs->mult + cs->maxadj) ,也就是說 這個是在計算2的63次方納秒對應的cycles,也就是計算最大的cycles,因為時間對應的納秒不能超 過2的64次方,因為會溢出 */ max_cycles = min_t(u64, max_cycles, (u64) cs->mask); /*max_cycles和cs->mask中的最小值賦值給max_cycles*/ max_nsecs = clocksource_cyc2ns(max_cycles, cs->mult - cs->maxadj, cs->shift);return max_nsecs - (max_nsecs >> 3);}static struct clocksource clocksource_counter = {.name = "arch_sys_counter",.rating = 400,.read = arch_counter_read,.mask = CLOCKSOURCE_MASK(56),.flags = CLOCK_SOURCE_IS_CONTINUOUS,};static void __init arch_timer_counter_init(void){ clocksource_register_hz(&clocksource_counter, arch_timer_rate); setup_sched_clock(arch_timer_update_sched_clock, 32, arch_timer_rate);/* Use the architected timer for the delay loop. */ arch_delay_timer.read_current_timer = &arch_timer_read_current_timer; arch_delay_timer.freq = arch_timer_rate; register_current_timer_delay(&arch_delay_timer);}static inline int clocksource_register_hz(struct clocksource *cs, u32 hz){ return __clocksource_register_scale(cs, 1, hz);}int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq){ /* Initialize mult/shift and max_idle_ns */ __clocksource_updatefreq_scale(cs, scale, freq); //根據clocksource的頻 率計算mult和shit的值 /* Add clocksource to the clcoksource list */ mutex_lock(&clocksource_mutex); clocksource_enqueue(cs); clocksource_enqueue_watchdog(cs); clocksource_select(); mutex_unlock(&clocksource_mutex); return 0;}void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq){ u64 sec; sec = (cs->mask - (cs->mask >> 3)); do_div(sec, freq); do_div(sec, scale);if (!sec) sec = 1;else if (sec > 600 && cs->mask > UINT_MAX) sec = 600; clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, NSEC_PER_SEC / scale, sec * scale); cs->maxadj = clocksource_max_adjustment(cs);while ((cs->mult + cs->maxadj < cs->mult)|| (cs->mult - cs->maxadj > cs->mult)) { cs->mult >>= 1; cs->shift--; cs->maxadj = clocksource_max_adjustment(cs);} cs->max_idle_ns = clocksource_max_deferment(cs);}voidclocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec){ u64 tmp; u32 sft, sftacc= 32; tmp = ((u64)maxsec * from) >> 32; while (tmp) { tmp >>=1; sftacc--;}for (sft = 32; sft > 0; sft--) { tmp = (u64) to << sft; tmp += from / 2; do_div(tmp, from);if ((tmp >> sftacc) == 0)break;}*mult = tmp;*shift = sft;}

kernel用乘法+移位來替換除法:根據cycles來計算過去了多少ns。 單純從精度上講,肯定是mult越大越好,但是計算過程可能溢出,所以mult也不能無限制的大,這個計算中有個magic number 600 : 這個600的意思是600秒,表示的Timer兩次計算當前計數值的差不會超過10分鐘。主要考慮的是系統進入IDLE狀態之后,時間信息不會被更新,10分鐘內只要退出IDLE,clocksource還是可以成功的轉換時間。當然了,最后的這個時間不一定就是10分鐘,它由clocksource_max_deferment計算并將結果存儲在max_idle_ns中 筒子比較關心的問題是如何計算 ,精度如何,其實我不太喜歡這種計算,Kernel總是因為某些原因把代碼寫的很蛋疼.反正揣摩代碼意圖要花不少時間,收益嘛其實也不太大.如何實現我也不解釋了,我以TSC為例子我評估下這種mult+shift的精度.

#include<stdio.h>#include<stdlib.h>typedef unsigned int u32;typedef unsigned long long u64;#define NSEC_PER_SEC 1000000000Lvoidclocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec){ u64 tmp; u32 sft, sftacc= 32; /* * * Calculate the shift factor which is limiting the conversion * * range: * */ tmp = ((u64)maxsec * from) >> 32; while (tmp) { tmp >>=1; sftacc--; } /* * * Find the conversion shift/mult pair which has the best * * accuracy and fits the maxsec conversion range: * */ for (sft = 32; sft > 0; sft--) { tmp = (u64) to << sft; tmp += from / 2; //do_div(tmp, from); tmp = tmp/from; if ((tmp >> sftacc) == 0) break; } *mult = tmp; *shift = sft;}int main(){ u32 tsc_mult; u32 tsc_shift ; u32 tsc_frequency = 2127727000/1000; //TSC frequency(KHz) clocks_calc_mult_shift(&tsc_mult,&tsc_shift,tsc_frequency,NSEC_PER_SEC/1000, 600*1000); //NSEC_PER_SEC/1000是因為TSC的注冊是clocksource_register_khz f600是根據TSC clocksource的MASK算出來的的入參,感興趣可以自己推算看下結果:

mult = 7885042 shift = 24root@manu:~/code/c/self/time# pythonPython 2.7.3 (default, Apr 10 2013, 05:46:21) [GCC 4.6.3] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> (2127727000*7885042)>>241000000045L>>> 我們知道TSC的frequency是2127727000Hz,如果cycle走過2127727000,就意味過去了1秒,或者說10^9(us).按照我們的算法得出的時間是1000000045ns. 這個誤差是多大呢,每走10^9秒,誤差是45納秒,換句話說,運行257天,產生1秒的計算誤差.考慮到NTP的存在,這個運算精度還可以了.

3. clocksource watchdog

clocksource_enqueue_watchdog會將clocksource掛到watchdog鏈表.watchdog顧名思義,監控所有clocksource:

#define WATCHDOG_INTERVAL (HZ >> 1)#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)

如果0.5秒內,誤差大于0.0625s,表示這個clocksource精度極差,將rating設成0.

實際的應用場景

以高通msm8916為例,除了jiffies,其他clocksource是沒有直接使用kernel/kernel/time/clocksource.c文件里邊的接口的。 其他arm_arch_timer.c[/kernel/driver/clocksource/arm_arch_timer.c] 和 arch_timer.c [kernel/arch/arm/kernel/arch_timer.c] 兩個都是使用 sched_clock.c[/kernel/kernel/time/sched_clock.c]文件里邊的 sched_clock_register()來進行注冊,并使用sched_clock_32()函數讀取當前時間。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产成人精品网站| 国产精品午夜国产小视频| 久久久久亚洲精品成人网小说| 国产不卡在线观看| 国产亚洲欧洲在线| 亚洲黄页视频免费观看| 成人国产在线激情| 久久精品99久久久香蕉| 91成人在线观看国产| 国产日韩中文字幕| 日韩欧美国产免费播放| 色妞色视频一区二区三区四区| 久久精品福利视频| 久久国产加勒比精品无码| 欧美怡春院一区二区三区| 国产精品久久久久久久久久三级| 日韩免费视频在线观看| 26uuu另类亚洲欧美日本老年| 日韩av片电影专区| 亚洲香蕉伊综合在人在线视看| 国产成人精品国内自产拍免费看| 国产精品亚洲综合天堂夜夜| 日韩在线观看免费全| 欧美夜福利tv在线| 欧美成人自拍视频| 中文字幕亚洲综合久久筱田步美| 伊人久久久久久久久久| 欧美日韩人人澡狠狠躁视频| 亚洲免费视频观看| 久久久久久久久久久久久久久久久久av| 久久久亚洲影院| 97色伦亚洲国产| 亚洲理论片在线观看| 欧美韩国理论所午夜片917电影| 国产在线精品成人一区二区三区| 日韩成人中文字幕在线观看| 亚洲性线免费观看视频成熟| 亚洲mm色国产网站| 日韩精品视频在线免费观看| 亚洲综合视频1区| 欧美重口另类videos人妖| 中文在线资源观看视频网站免费不卡| xvideos亚洲| www.久久撸.com| 国产婷婷成人久久av免费高清| 久久久国产影院| 欧美激情一二区| 国产精品视频999| 成人欧美一区二区三区在线| 国产精品永久免费在线| 国产精品一区二区三区久久| 日韩免费在线播放| 久久伊人色综合| 久久天堂电影网| 国内精品久久久久影院 日本资源| 日韩精品高清视频| 亚洲免费视频观看| 成人乱色短篇合集| 欧美日韩亚洲视频| 日韩欧美高清在线视频| 精品成人国产在线观看男人呻吟| 国产精品一区二区三区免费视频| 欧美福利在线观看| 久久久久久九九九| 国产精品羞羞答答| 亚洲欧洲成视频免费观看| 国产91精品久久久| 欧美与欧洲交xxxx免费观看| 国产精品日韩久久久久| 97在线看免费观看视频在线观看| 26uuu另类亚洲欧美日本一| 国产91在线播放九色快色| 久久久国产视频91| 最近更新的2019中文字幕| 欧美成人精品在线观看| 色悠悠久久88| 国产精品成av人在线视午夜片| 78m国产成人精品视频| 国产一区二区三区精品久久久| 91老司机在线| 日韩av免费观影| 成人性生交xxxxx网站| 久久久91精品国产一区不卡| 91精品免费久久久久久久久| 一区二区欧美久久| 欧美在线视频在线播放完整版免费观看| 国产精品私拍pans大尺度在线| 欧美精品18videosex性欧美| 国内精品久久久久久| 96精品视频在线| 欧美性猛交xxxx乱大交蜜桃| 欧美老女人bb| 国产一区二区三区在线| 国产精品免费视频久久久| 97国产精品视频人人做人人爱| 日韩欧美在线视频观看| 精品久久久精品| 亚洲精品国产精品久久清纯直播| 91在线视频精品| 69av视频在线播放| 91手机视频在线观看| 亚洲精品一区久久久久久| 高清一区二区三区日本久| 欧美高清视频在线播放| 日韩经典一区二区三区| 久久成人国产精品| 欧美老妇交乱视频| 国产亚洲一区二区精品| 亚洲激情视频在线观看| 一区二区三区在线播放欧美| 日韩久久精品成人| 亚洲情综合五月天| 日韩精品在线观看视频| 国产精品三级久久久久久电影| 色播久久人人爽人人爽人人片视av| 久久免费福利视频| 国产精品电影网站| 日韩有码片在线观看| 蜜月aⅴ免费一区二区三区| 精品国产乱码久久久久久虫虫漫画| 久久69精品久久久久久国产越南| 成人免费淫片aa视频免费| 久久综合九色九九| 亚洲最新av网址| 日韩美女写真福利在线观看| 久久久久久尹人网香蕉| 欧美国产在线电影| 亚洲国产天堂久久综合| 欧美成人亚洲成人| 亚洲www视频| 亚洲三级黄色在线观看| 久久99精品久久久久久琪琪| 久久91精品国产91久久久| 亚洲综合av影视| 国内精品400部情侣激情| 黑人狂躁日本妞一区二区三区| 欧美亚洲国产视频小说| 欧美xxxx综合视频| 国产精品第七影院| 欧美成人精品xxx| 亚洲xxx自由成熟| 亚洲美女视频网站| 北条麻妃久久精品| 色偷偷9999www| 91亚洲国产成人精品性色| 亚洲乱码国产乱码精品精| 国产精品入口日韩视频大尺度| 亚洲黄一区二区| 欧美疯狂性受xxxxx另类| 国产综合在线观看视频| 久久精品这里热有精品| 亚洲一区www| 亚洲第一综合天堂另类专| 欧美日韩亚洲精品内裤| 中文字幕少妇一区二区三区| 日韩电影大片中文字幕| 久久韩剧网电视剧| 久久亚洲私人国产精品va| 国产91精品久久久久久| 亚洲福利在线观看| 亚洲精品在线不卡| 久久精品国产91精品亚洲| 久久久精品免费| 欧美肥婆姓交大片|