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 endifLong 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。
沒有留言:
張貼留言