2010年8月14日 星期六

Timing Measurements - 1

System Time and Date

Linux 的系統時間與日期是靠一顆 Real Time Clock (RTC) 的晶片所維護的,應用程式可經由 /dev/rtc 來控制晶片,
核心則是透過 I/O port 0x700x71 來控制。


Time Measurement

x86 處理器有一名為 Time Stamp Counter (TSC) 的暫存器,每當 CPU 的 clock 腳位有訊號時,TSC 就會遞增。
若 clock 的頻率是 1 GHz,則 TSC 會每 1 nanosecond 做加 1 的動作。Linux 核心使用 TSC 的值便可讓做出精準的時間量測。


Timer Interrupt

PC 硬體上會有至少一個的 Programmable Interval Timer (PIT) 裝置,如 Intel 的 8254 晶片,提供定時的功能,
並且於 timeout 時對 CPU 發出中斷通知,也就是 Timer Interrupt - IRQ 0
PIT 可以透過 I/O port 0x400x43 的 4 個埠口來控制。


tick, jiffies and xtime

Linux 核心設定 PIT 產生頻率為 1000 Hz 的 Timer Interrupt,即每 1 millisecond 會產生一次中斷,
此 1 millisecond 的時間稱為一個 "tick",該值存於變數 tick_nsec 之中,而頻率值以巨集 HZ 表示。

愈短的 tick 值會得到快速的 I/O 多工的反應時間,但亦會拖慢應用程式的執行速度。
通常較慢的機器會設定 10 millisecond 的 tick 值,而較快的機器會設定 1 millisecond 的 tick 值。

定義於 kernel/timer.c

/*
* Timekeeping variables
*/
unsigned long tick_usec = TICK_USEC;  /* USER_HZ period (usec) */
unsigned long tick_nsec = TICK_NSEC;  /* ACTHZ period (nsec) */

/*
* The current time
* wall_to_monotonic is what we need to add to xtime (or xtime corrected
* for sub jiffie times) to get to monotonic time. Monotonic is pegged
* at zero at system boot time, so wall_to_monotonic will be negative,
* however, we will ALWAYS keep the tv_nsec part positive so we can use
* the usual normalization.
*/
struct timespec xtime __attribute__ ((aligned (16)));
struct timespec wall_to_monotonic __attribute__ ((aligned (16)));

EXPORT_SYMBOL(xtime);


定義於 include/asm-i386/param.h

#ifdef __KERNEL__
# define HZ      1000    /* Internal kernel timer frequency */
# define USER_HZ  100    /* .. some user interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif

#ifndef HZ
#define HZ 100
#endif

核心變數 jiffies 用來儲存自系統啟動以來,共經過了多少次 tick 的值。故每次的 tick 就會使 jiffies 遞增。
由於 jiffies 的長度只有 32-bit,對於 tick = 1 millisecond 機器,經過約 50 天就會讓 jiffies 溢位。
因此真正用來儲存 jiffies 值的是長度為 64-bit 的變數 jiffies_64

定義於 include/linux/jiffies.h

/*
* The 64-bit value is not volatile - you MUST NOT read it
* without sampling the sequence number in xtime_lock.
* get_jiffies_64() will do this for you as appropriate.
*/
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

核心變數 xtime 用來記錄自系目前的時間與日期,其結構包含兩個欄位:
tv_sec  儲存自 1970.01.01 以來,共經過多少秒 (second)
• tv_nsec 儲存自上一秒的時間以來,共經過多少的奈秒 (nanosecond)

定義於 include/linux/time.h

#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
struct timespec {
  time_t tv_sec;   /* seconds */
  long   tv_nsec;  /* nanoseconds */
};
#endif /* _STRUCT_TIMESPEC */

沒有留言: