HZ:
每隔固定週期Linux Kernel會發出timer interrupt,HZ定義每一秒有幾次timer interrupts,而HZ變數是儲存在Kernel變數中,在編譯Kernel之前,可以透過make menuconfig設定此值,設定路徑Processor type and features → Timer frequency (250 HZ): 如果適當調高HZ值,可以提升系統performance,讓timer interrupts次數變高,相對tasks之間的切換頻率也會變高,對於server而言,在回應clients時間會縮短。但如果HZ值設定太大,會導致系統資源與電源消耗,因為更多的CPU cycles會耗在timer interrupts。可以透過下列指令,檢查系統上的HZ值:
cat /boot/config-`uname -r` | grep '^CONFIG_HZ='Jiffies:
用來紀錄系統自開幾以來,已經過多少的tick(jiffy),每發生一次timer interrupt,Jiffies變數會被加一。
底下是一個範例,透過Linux timer再搭配jffies與HZ使用,讓console每五秒印一次訊息。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Renee Ciou");
MODULE_DESCRIPTION("Timer Module");
MODULE_ALIAS("timer module");
struct timer_list timer;
unsigned long ticks, count;
void timer_func(unsigned long data)
{
mod_timer(&timer, jiffies + (5 * HZ)); /* 修改或者重新設定timer */
printk("Timer rescheduled %lu times in %lu seconds\n",
count++, (jiffies - ticks)/HZ);
}
int timer_module_init(void)
{
init_timer(&timer); /* 初始化timer struct */
timer.data = 10; /* 丟給time_func的參數 */
timer.expires = jiffies + (5 * HZ); /* 5秒後timeout */
timer.function = timer_func; /* 計時5秒timeout後執行time_func */
add_timer(&timer); /* 啟動timer */
ticks = jiffies; /* 紀錄當前的jiffies */
printk("Timer module loaded");
return 0;
}
void timer_module_exit(void)
{
del_timer(&timer); /* 移除timer */
printk("Timer module unloaded");
}
module_init(timer_module_init);
module_exit(timer_module_exit);
如果要在x86平台上執行,請用下面的Makefile:
ifneq ($(KERNELRELEASE),)
obj-m := timer.o
else
KDIR := /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
如果要在ARM平台上執行,請用下面的Makefile:
ifneq ($(KERNELRELEASE),)
obj-m := timer.o
else
KDIR := /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
Long Delays在kernel的世界中,透過jiffies達成的時間延遲,通常被視為long delays。long delays可以用兩種方式實現,分別為busy-looping與sleep-waiting,這兩種方式延遲的優缺點,前面已經解釋過了。底下的範例,3, 4行code實現1秒busy-looping的long delays:
void timer_func(unsigned long data)
{
unsigned long timeout = jiffies + HZ;
while (time_before(jiffies, timeout)) continue;
mod_timer(&timer, jiffies + (5 * HZ));
printk("Timer rescheduled %lu times in %lu seconds\n",
count++, (jiffies - ticks)/HZ);
}
上面透過busy-looping實現的long delays會浪費掉1秒CPU時間,不是很好的方式。不過,下面的範例,3, 4行code則是由sleep-waiting實現1秒的long delays,程式在等待過程中,會將CPU讓給其他的process使用。
void timer_func(unsigned long data)
{
unsigned long timeout = HZ;
schedule_timeout(timeout);
mod_timer(&timer, jiffies + (5 * HZ));
printk("Timer rescheduled %lu times in %lu seconds\n",
count++, (jiffies - ticks)/HZ);
}
Short Delays在kernel世界中,小於tick(jiffy)的時間延遲,被視為short delays。這種延遲普遍用於process與interrupt執行環境,但是無法基於jiffy實現此種極短且精準的延遲,由於jiffy單位不夠小。此外,sleep-waiting也不能用於short delays,由於interrupt handlers不允許被shedule或進入sleep,所以short delays只能採用busy-looping方式實現。在kernel API中,已經實現short delays,分別提供 mdelay(), udelay(), 和 ndelay() 這三個函式來達到極短且精準的延遲,而這三個函式是透過loops_per_jiffy實現,去計算需要多少個loop operation來得到精確的delay。

沒有留言:
張貼留言