时间子系统三——低精度定时器和高精度定时器

纵然是瞬间 提交于 2020-02-17 05:32:48

先有低精度定时器,后来引入了高精度定时器。低精度定时器只能提供毫秒级别的定时时间,因为它实际上是依赖于jiffies的,一个jiffies的时间,就是其能够提供的最小定时时间,比如CONFIG_HZ配置为250,那么一个jiffies就是4ms,所以低精度定时器的精度就是4ms;而高精度定时器则不一样,它不依赖于jiffies,甚至jiffies是依赖于高精度定时器的,因为jiffies的累加实际上也是通过一个特殊的高精度定时器来实现的,高精度定时器只依赖于硬件timer,所以可以提供纳秒级别的精度。那么除了从函数接口上看到的定时事件精度的差异之外,高精度定时器和低精度定时器还有哪些不一样呢?下面通过实例来探讨一下。

  • 高精度定时器测试代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time64.h>
#include <linux/hrtimer.h>
#include <linux/timekeeper_internal.h>

#define GET_TIME_SAMPLES_CNT  32 

#define HRTIMER_TIMEOUT_NSECOND    1000000000

static int g_get_time_index = 0;
static struct hrtimer g_hrtimer;
static struct timespec64 current_time[GET_TIME_SAMPLES_CNT];

static enum hrtimer_restart timer_test_func(struct hrtimer *hrtimer)
{
	if(g_get_time_index >= GET_TIME_SAMPLES_CNT){
		printk("timer test done!\n");
		return HRTIMER_NORESTART;
	}
	hrtimer_forward_now(hrtimer, ns_to_ktime(HRTIMER_TIMEOUT_NSECOND));
	getnstimeofday64(&current_time[g_get_time_index++]);
	
	return HRTIMER_RESTART;
}

static int __init hrtimer_test_init(void)
{
	hrtimer_init(&g_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	g_hrtimer.function = timer_test_func;
	hrtimer_start(&g_hrtimer, ns_to_ktime(HRTIMER_TIMEOUT_NSECOND), HRTIMER_MODE_REL);
	
	return 0;
}

static void __exit hrtimer_test_exit(void)
{
	int i;
	long int delta_nsecond=0;

	for(i=1;i<GET_TIME_SAMPLES_CNT;i++){ 

		delta_nsecond = current_time[i].tv_sec*1000000000+current_time[i].tv_nsec-
			current_time[i-1].tv_sec*1000000000-current_time[i-1].tv_nsec;
		printk(KERN_ERR "%d : delta_ns %ld error %ld\n", i, delta_nsecond, delta_nsecond-HRTIMER_TIMEOUT_NSECOND);

	}
	
	hrtimer_cancel(&g_hrtimer);
}

MODULE_LICENSE("GPL");
module_init(hrtimer_test_init);
module_exit(hrtimer_test_exit);

  • 低精度定时器测试代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time64.h>
#include <linux/timekeeper_internal.h>

#define GET_TIME_SAMPLES_CNT  32 

static int g_get_time_index = 0;
static struct timer_list g_timer_test;
static struct timespec64 current_time[GET_TIME_SAMPLES_CNT];

static void timer_test_func(struct timer_list *t)
{
	if(g_get_time_index >= GET_TIME_SAMPLES_CNT){
		printk("timer test done!\n");
		return;
	}
	g_timer_test.expires = jiffies + HZ;
	add_timer(&g_timer_test);
	getnstimeofday64(&current_time[g_get_time_index++]);
	
}

static int __init timer_test_init(void)
{
	g_timer_test.function = timer_test_func;
	g_timer_test.expires = jiffies + HZ;
	add_timer(&g_timer_test);
	return 0;
}

static void __exit timer_test_exit(void)
{
	int i;
	long int delta_nsecond=0;

	for(i=1;i<GET_TIME_SAMPLES_CNT;i++){ 
		delta_nsecond = current_time[i].tv_sec*1000000000+current_time[i].tv_nsec-
			current_time[i-1].tv_sec*1000000000-current_time[i-1].tv_nsec;
		printk(KERN_ERR "%d : delta_ns %ld error %ld\n", i, delta_nsecond, delta_nsecond-1000000000);
	}
	
	del_timer_sync(&g_timer_test);
}

module_init(timer_test_init);
module_exit(timer_test_exit);

以上两段代码分别设置了一个高优先级的定时器和低优先级的定时器,超时时间都是1秒钟,超时处理函数中获取当前的时间,最终计算两次超时实际的时间间隔。

  • 高优先级定时器测试结果
[ 1815.080114] 1 : delta_ns 1000104199 error 104199
[ 1815.080117] 2 : delta_ns 1000985662 error 985662
[ 1815.080118] 3 : delta_ns 999045351 error -954649
[ 1815.080119] 4 : delta_ns 999858212 error -141788
[ 1815.080120] 5 : delta_ns 1000389033 error 389033
[ 1815.080120] 6 : delta_ns 999779512 error -220488
[ 1815.080121] 7 : delta_ns 999822153 error -177847
[ 1815.080122] 8 : delta_ns 999995822 error -4178
[ 1815.080123] 9 : delta_ns 999997841 error -2159
[ 1815.080124] 10 : delta_ns 1000022538 error 22538
[ 1815.080125] 11 : delta_ns 999972266 error -27734
[ 1815.080126] 12 : delta_ns 1000000459 error 459
[ 1815.080127] 13 : delta_ns 1000002233 error 2233
[ 1815.080128] 14 : delta_ns 1000408763 error 408763
[ 1815.080129] 15 : delta_ns 999891452 error -108548
[ 1815.080130] 16 : delta_ns 999782798 error -217202
[ 1815.080130] 17 : delta_ns 1000357035 error 357035
[ 1815.080131] 18 : delta_ns 999578118 error -421882
[ 1815.080132] 19 : delta_ns 1000711701 error 711701
[ 1815.080133] 20 : delta_ns 999277300 error -722700
[ 1815.080134] 21 : delta_ns 1000775753 error 775753
[ 1815.080135] 22 : delta_ns 999254177 error -745823
[ 1815.080136] 23 : delta_ns 999970711 error -29289
[ 1815.080137] 24 : delta_ns 1000174230 error 174230
[ 1815.080137] 25 : delta_ns 1000377856 error 377856
[ 1815.080138] 26 : delta_ns 999783111 error -216889
[ 1815.080139] 27 : delta_ns 1000397950 error 397950
[ 1815.080140] 28 : delta_ns 999646197 error -353803
[ 1815.080141] 29 : delta_ns 999666266 error -333734
[ 1815.080142] 30 : delta_ns 1000101736 error 101736
[ 1815.080143] 31 : delta_ns 999861476 error -138524
  • 低优先级定时器测试结果
[  238.694774] 1 : delta_ns 1023593664 error 23593664
[  238.694777] 2 : delta_ns 1023963113 error 23963113
[  238.694778] 3 : delta_ns 1024269354 error 24269354
[  238.694779] 4 : delta_ns 1024182681 error 24182681
[  238.694780] 5 : delta_ns 1023548489 error 23548489
[  238.694781] 6 : delta_ns 1024354479 error 24354479
[  238.694782] 7 : delta_ns 1023658693 error 23658693
[  238.694783] 8 : delta_ns 1024084116 error 24084116
[  238.694783] 9 : delta_ns 1023966840 error 23966840
[  238.694784] 10 : delta_ns 1024025003 error 24025003
[  238.694785] 11 : delta_ns 1024026478 error 24026478
[  238.694786] 12 : delta_ns 1024050789 error 24050789
[  238.694787] 13 : delta_ns 1023933148 error 23933148
[  238.694788] 14 : delta_ns 1024643709 error 24643709
[  238.694789] 15 : delta_ns 1023341602 error 23341602
[  238.694790] 16 : delta_ns 1024425521 error 24425521
[  238.694791] 17 : delta_ns 1023577560 error 23577560
[  238.694791] 18 : delta_ns 1024521450 error 24521450
[  238.694792] 19 : delta_ns 1024383405 error 24383405
[  238.694793] 20 : delta_ns 1023009118 error 23009118
[  238.694794] 21 : delta_ns 1024113967 error 24113967
[  238.694795] 22 : delta_ns 1024608789 error 24608789
[  238.694796] 23 : delta_ns 1023282831 error 23282831
[  238.694797] 24 : delta_ns 1023994059 error 23994059
[  238.694798] 25 : delta_ns 1024220482 error 24220482
[  238.694798] 26 : delta_ns 1024653903 error 24653903
[  238.694799] 27 : delta_ns 1023813451 error 23813451
[  238.694800] 28 : delta_ns 1023387878 error 23387878
[  238.694801] 29 : delta_ns 1024397183 error 24397183
[  238.694802] 30 : delta_ns 1024205149 error 24205149
[  238.694803] 31 : delta_ns 1023730694 error 23730694

硬件平台,中断资源的竞争,CPU资源的竞争都会导致在超时时间的精准度上存在一定的误差,但是在同等条件下,我们可以看到高优先级定时器的超时时间精准度在微秒级别,而低优先级定时器在毫秒级别。我们通过dump_stack打印出调用函数栈可以发现高优先级定时器是在中断上下文处理的,而低优先级定时器是在软中断上下文处理的,而在我的测试环境中,软中断被线程化,所以实际上低优先级定时器是在进程上下文处理的,存在这种精度的差异实属必然。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!