linux時鐘有很多種,粗略來分可分成兩類:提供中斷的週期性時鐘(rtc、pit等),提供計數的遞增型時鐘(如tsc)
這裏簡單羅列幾種常見的。
(1)RTC
(2)TSC
(3)KVM_CLOCK
(4)acpi_pm
查看當前系統支持的時鐘
cat /sys/devices/system/clocksource/clocksource0/available_clocksource
查看當前使用的時鐘
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
RTC
RTC通過獨立電池供電,系統可從RTC讀取時間信息,來確保斷電後時間運行連續性。在內核中RTC驅動可分爲兩層,一層爲抽象層(與硬件無關)用於管理RTC設備、設備節點、屬性節點註冊及操作。另一層爲底層驅動層(硬件相關)
抽象層程序在/drivers/rtc目錄下,主要涉及下面幾個文件:
class.c 用於管理和註冊RTC設備結構、sysfs、procfs及RTC類;
rtc-dev.c 用於註冊和管理RTC設備節點,爲用戶空間提供devfs操作接口,主要操作有rtc_read,rtc_ioctl;
rtc-proc.c 用於管理rtc的procfs屬性節點,提供一些中斷狀態、標誌查詢;
rtc-sysfs.c 用於管理rtc設備的sysfs屬性,如獲取RTC設備名字、日期、時間等屬性信息;
interface.c 爲rtc-dev.c 和RTC低層驅動提供操作接口;
RTC設備驅動通過rtc_device_register向系統註冊rtc設備,並在proc、sys等目錄下生成相應屬性文件。當用戶通過/dev/rtcx設備節點發起操作的時候,都需要通過interface接口才能訪問到真實的設備驅動。
在低頻業務場景下,用戶進程通過read(2)、select(2)讀取/dev/rtc來獲取這些中斷。當中斷調用時,進程會阻塞或者退出直到下一個中斷到來。在高頻業務場景下,用戶進程會檢查一箇中斷數來判斷當前是否有未處理的中斷。
中斷頻率可以通過/proc/sys/dev/rtc/max-user-freq文件來修改(默認是64hz)
RTC底層操作接口
這些操作接口都封裝在
int (*open)(struct device *); 打開設備
void (*release)(struct device *); 釋放設備
int (*ioctl)(struct device *, unsigned int, unsigned long);
int (*read_time)(struct device *, struct rtc_time *); 讀取RTC時間;
int (*set_time)(struct device *, struct rtc_time *); 設置RTC時間;
int (*read_alarm)(struct device *, struct rtc_wkalrm *); 讀取RTC報警時間;
int (*set_alarm)(struct device *, struct rtc_wkalrm *); 設置RTC報警時間;
int (*proc)(struct device *, struct seq_file *); 用於提供procfs查詢rtc狀態接口;
int (*set_mmss)(struct device *, unsigned long secs); 設置以S爲單位RTC時間接口;
int (*read_callback)(struct device *, int data);
int (*alarm_irq_enable)(struct device *, unsigned int enabled); 中斷使能接口;
可以通過hwclock來同步系統時鐘和硬件時鐘信息,或者可通過0x70、0x71端口訪問RTC
系統時間同步到硬件時間:hwclock –w、hwclock --systohc
在用hwclock進行顯示,設置RTC硬件時間之前都會先通過進行時鐘tick同步,同步方法是開啓1S 一次update interrupt,每過1S RTC都會產生一次報警中斷,並更新相應的中斷數據,在應用層通過select來監控是否有RTC數據可讀,如果有數據則會繼續顯示或設置硬件時間操作
TSC
TSC是位於CPU裏面的一個64位的TSC寄存器,它記錄自啓動以來處理器消耗的時鐘週期數,每個CPU時鐘週期其值加一。TSC精度很高,因爲TSC隨着處理器週期速率的變化而變化。
可以通過rdtsc指令來讀取。
[秒 = TSC值/CPU時鐘速率]
通過rdtsc指令來讀取TSC值
taticinline unsigned longlong native_read_tsc(void){
unsigned long longval;
asm volatile("rdtsc": "=A" (val));
return val;
}
這個函數將TSC值放在eax和edx寄存器中,然後再存往val變量中。
KVM_CLOCK
kvm_clock是kvm半虛擬化默認時鐘源。大概原理是在客戶機上實現一個kvmclock驅動,然後客戶機通過這個驅動向VMM查詢時間。
工作流程:客戶機先分配一個內存頁,這個內存頁通過MSR寄存器告知給VMM,VMM將母機系統時間寫入這個內存頁,然後客戶機通過讀取這個內存頁來獲取時間。
cpu steal time 指vcpu等待cpu的時間,vcpu通過vm-exit進入vmm,再從vmm進入guest,這個過程就是cpu steal time。這個可用來衡量虛機性能。