linux內(nèi)核里面用了很多的時(shí)鐘,其實(shí)這些時(shí)鐘的用處無外乎就幾種:1.作為心跳,中斷cpu;2.使得用戶可以獲取當(dāng)前時(shí)間;3.實(shí)時(shí)
測(cè)量;4.定時(shí)
服務(wù)。知道了使用目的后,我們來看看到底有哪些時(shí)鐘供我們選擇使用:關(guān)于這些時(shí)鐘的概念,網(wǎng)上已經(jīng)存在不少文章了,為了不重復(fù)(浪費(fèi)互聯(lián)網(wǎng)空間),咱就先
來個(gè)引用。
/*摘錄開始:http://blog./u1/55599/showart.php?id=1179259
1):實(shí)時(shí)時(shí)鐘(RTC)
該時(shí)鐘獨(dú)立于CPU和其它芯片.即使PC斷電,該時(shí)鐘還是繼續(xù)運(yùn)行.該計(jì)時(shí)由一塊單獨(dú)的芯片處理,并把時(shí)鐘值存放CMOS.該時(shí)間可參在IRQ8上周期性的產(chǎn)生時(shí)間信號(hào).頻率在2Hz ~ 8192Hz之間.但在linux中,只是用RTC來獲取當(dāng)前時(shí)間.
2):時(shí)間戳計(jì)時(shí)器(TSC)
CPU附帶了一個(gè)64位的時(shí)間戳寄存器,當(dāng)時(shí)鐘信號(hào)到來的時(shí)候.該寄存器內(nèi)容自動(dòng)加1
3):可編程中斷定時(shí)器(PIC)
該設(shè)備可以周期性的發(fā)送一個(gè)時(shí)間中斷信號(hào).發(fā)送中斷信號(hào)的間隔可以對(duì)其進(jìn)行編程控制.在linux系統(tǒng)中,該中斷時(shí)間間隔由HZ表示.這個(gè)時(shí)間間隔也被稱為一個(gè)節(jié)拍(tick).
在 ./include/asm-i386/param.h 定義
10#ifndef HZ
11#define HZ 100
12#endif
4):CPU本地定時(shí)器
在處理器的本地APIC還提供了另外的一定定時(shí)設(shè)備.CPU本地定時(shí)器也可以單次或者周期性的產(chǎn)生中斷信號(hào).與上次描述的PIC相比.它有以下幾點(diǎn)的區(qū)別:
APIC本地計(jì)時(shí)器是32位.而PIC是16位.由此APIC本地計(jì)時(shí)器可以提供更低頻率的中斷信號(hào)
本地APIC只把中斷信號(hào)發(fā)送給本地CPU.而PIC發(fā)送的中斷信號(hào)任何CPU都可以處理
APIC定時(shí)器是基于總線時(shí)鐘信號(hào)的.而PIC有自己的內(nèi)部時(shí)鐘振蕩器
5):高精度計(jì)時(shí)器(HPET)
在
linux2.6中增加了對(duì)HPET的支持.HPET是一種由intel開發(fā)的新型定時(shí)芯片.該設(shè)備有一組寄時(shí)器,每個(gè)寄時(shí)器對(duì)應(yīng)有自己的時(shí)鐘信號(hào),時(shí)鐘
信號(hào)到來的時(shí)候就會(huì)自動(dòng)加1.一個(gè)
hpet包括了一個(gè)固定頻率的數(shù)值增加的計(jì)數(shù)器以及3到32個(gè)獨(dú)立的計(jì)時(shí)器,這每一個(gè)計(jì)時(shí)器有包涵了一個(gè)比較器和一個(gè)寄存器(保存一個(gè)數(shù)值,表示觸發(fā)中斷
時(shí)機(jī))。每一個(gè)比較器都比較計(jì)數(shù)器中的數(shù)值和寄存器中的數(shù)值,當(dāng)這兩個(gè)數(shù)值相等時(shí),將產(chǎn)生一個(gè)中斷
實(shí)際上,在intel多理器系統(tǒng)與單處理器系統(tǒng)還有所不同:
在單處理系統(tǒng)中.所有計(jì)時(shí)活動(dòng)過由PIC產(chǎn)生的時(shí)鐘中斷信號(hào)觸發(fā)的
在多處理系統(tǒng)中,所有普通活動(dòng)是由PIC產(chǎn)生的中斷觸發(fā).所有具體的CPU活動(dòng),都由本地APIC觸發(fā)的.
*/摘錄完畢
好了,上面對(duì)這么多種時(shí)鐘的概念已經(jīng)闡述的很清楚了,那么他們之間到底有何聯(lián)系呢?幸運(yùn)的是,在2.6.21內(nèi)核以后,一切變得不言自明了,2.6.21以上內(nèi)核將時(shí)鐘框架進(jìn)行了進(jìn)一步的抽象整理,抽象出了兩個(gè)概念:
struct clocksource :對(duì)硬件時(shí)鐘設(shè)備的抽象,描述時(shí)鐘源,強(qiáng)調(diào)靜態(tài)事物,源頭
struct clock_event_device :時(shí)鐘的事件的抽象,描述硬件時(shí)鐘中斷發(fā)生時(shí)要執(zhí)行的動(dòng)作,強(qiáng)調(diào)在時(shí)鐘源上面的動(dòng)態(tài)方面。
這
兩個(gè)概念被抽象出來以后,我們就可以用面向?qū)ο蟮乃悸穪矸治隽恕W屑?xì)看看這兩個(gè)概念,它們的偶合性極低,但是還是有聯(lián)系的,比如如果你將
clock_event_device設(shè)置成one-shot,而clocksource確是一個(gè)精度及其低的時(shí)鐘源,那么系統(tǒng)的響應(yīng)將會(huì)相當(dāng)慢,它們實(shí)
際上會(huì)影響到對(duì)方。
仔細(xì)研究一下上面的眾多時(shí)鐘,有的可以產(chǎn)生中斷,有的僅僅是一個(gè)計(jì)數(shù)器,有的...,那么我們?cè)趺醋x時(shí)鐘源啊,不要急,每個(gè)clocksource都有一個(gè)回調(diào)函數(shù)用來讀取時(shí)鐘源當(dāng)前值:
struct clocksource {
char *name;
struct list_head list;
int rating;
cycle_t (*read)(void);//這就是讀取回調(diào)函數(shù)
cycle_t mask;
u32 mult;
u32 shift;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
...
/* timekeeping specific data, ignore */
cycle_t cycle_interval;
u64 xtime_interval;
/*
* Second part is written at each timer interrupt
* Keep it in a different cache line to dirty no
* more than one cache line.
*/
cycle_t cycle_last ____cacheline_aligned_in_smp;
u64 xtime_nsec;
...
};
仔
細(xì)看看那個(gè)read回調(diào)函數(shù)的返回值,竟然是個(gè)cycle_t。內(nèi)核的設(shè)計(jì)者簡(jiǎn)直就是神,cycle_t這個(gè)值沒有和任何時(shí)間的概念關(guān)聯(lián),具體怎么關(guān)聯(lián)就
留給clock_event_device和具體的環(huán)境了,你可以通過兩個(gè)cycle_t相減得到一個(gè)值,你也可以...那么現(xiàn)在看一個(gè)具體的:
static struct clocksource clocksource_pit = {
.name = "pit",
.rating = 110,
.read = pit_read,
.mask = CLOCKSOURCE_MASK(32),
.mult = 0,
.shift = 20,
};
這回明白了嗎?clocksource最重要的就是隨時(shí)我調(diào)用你的read函數(shù),你能返回我一個(gè)cycle_t,告訴我當(dāng)前時(shí)鐘源的一個(gè)計(jì)數(shù)器的值就行了,至于我要這個(gè)值有什么用,你就別管了。實(shí)際上內(nèi)核可以通過這個(gè)計(jì)數(shù)器的值計(jì)算很多東西。
像
tsc時(shí)鐘源,你指望它產(chǎn)生中斷嗎?那是不可能的,但是它卻真的是一個(gè)時(shí)鐘源,pit也是一個(gè)時(shí)鐘源,但是他卻可以產(chǎn)生中斷,hpet也是一個(gè),它不但
可以產(chǎn)生中斷,還可以代替tsc,這豈不亂套了嗎?產(chǎn)生中斷的時(shí)鐘怎么能和僅僅是個(gè)計(jì)數(shù)器的時(shí)鐘是并列關(guān)系,一起注冊(cè)并競(jìng)爭(zhēng)全局clocksource
呢?如果是一個(gè)tsc競(jìng)爭(zhēng)取得勝利怎么辦啊,誰來產(chǎn)生中斷呢?
如果誰有以上問題,那就是沒有理解clocksource和
clock_event_device
產(chǎn)生的初衷,它們哥倆的出現(xiàn)僅僅是為了協(xié)作管理時(shí)鐘,為了使內(nèi)核可以提供更加靈活的策略同時(shí)為了更加方便的擴(kuò)展各個(gè)不同平臺(tái)的時(shí)鐘框架。如果tsc注冊(cè)并
取得全局clocksource權(quán),那么也是沒有關(guān)系的,產(chǎn)生中斷的時(shí)鐘不管你的軟件怎么樣,總會(huì)存在的,若不存在,你的計(jì)算機(jī)根本起不來,那就是出大問
題了,仔細(xì)看看下面的代碼:
void __init time_init_hook(void)
{
irq0.mask = cpumask_of_cpu(0);
setup_irq(0, &irq0);
}
在
一切就緒后(比如,tsc就是全局clocksource了),上述函數(shù)被調(diào)用,開始了心跳處理,也就是中斷處理,而在這之前,時(shí)鐘中斷也是有的,只不過
沒有處理函數(shù),進(jìn)去中斷馬上就出來了,現(xiàn)在全局的clocksource有了,全局的clock_event_device也有了,于是它們便開始了各司
其職完成時(shí)鐘處理。
tsc僅僅是一個(gè)計(jì)數(shù)器,hpet可以產(chǎn)生中斷同時(shí)有很多計(jì)數(shù)器,pit可以產(chǎn)生中斷也有計(jì)數(shù)器,可以產(chǎn)生中斷的產(chǎn)生中斷,有計(jì)數(shù)器的開始計(jì)數(shù),這些在你
按下計(jì)算機(jī)電源的那一瞬間就開始了,而不是等你在軟件里面設(shè)置了一些東西才開始的,當(dāng)然你完全可以用軟件控制它們,一個(gè)很好的例子就是one-shot模
式,這個(gè)就不說了,看代碼吧