• Linux下的hrtimer高精度定时器【转】


    本文转载自:http://blog.csdn.net/waverider2012/article/details/38305785

    hrtimer高精度定时器的interval由ktime_set(const long secs, const unsigned long nsecs)决定,可做到ns级。此处的例子为5ms interval:

    [cpp] view plain copy
     
    1. #include <linux/kernel.h>  
    2. #include <linux/module.h>  
    3. #include <linux/hrtimer.h>  
    4. #include <linux/ktime.h>  
    5.   
    6. MODULE_LICENSE("GPL");  
    7.   
    8. static struct hrtimer hr_timer;  
    9. static struct work_struct wq_hrtimer;    
    10. static ktime_t ktime;  
    11. static unsigned int interval=5000; /* unit: us */  
    12. struct timespec uptimeLast;  
    13.   
    14. static unsigned int count=0;  
    15. #define COUNT_INTERVAL 4000  
    16. unsigned long long diff_tv(struct timespec start, struct timespec end) {  
    17.     return (end.tv_sec-start.tv_sec)*1000000000+(end.tv_nsec-start.tv_nsec);  
    18. }  
    19.   
    20. enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer )  
    21. {  
    22.     schedule_work(&wq_hrtimer);   
    23.     return HRTIMER_NORESTART;  
    24. }  
    25.   
    26. static void wq_func_hrtimer(struct work_struct *work)  
    27. {   
    28.     struct timespec uptime;  
    29.   
    30.     hr_timer.function = my_hrtimer_callback;   
    31.     ktime = ktime_set( interval/1000000, (interval%1000000)*1000 );  
    32.     hrtimer_start(&hr_timer, ktime, HRTIMER_MODE_REL );  
    33.   
    34.     /* print time every COUNT_INTERVAL*interval second*/  
    35.     if(count%COUNT_INTERVAL==0)   
    36.     {  
    37.         do_posix_clock_monotonic_gettime(&uptime);    
    38.         printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns, interval_delay=%lu ns ",   
    39.             (unsigned long) uptime.tv_sec, uptime.tv_nsec,  
    40.             (unsigned long)(diff_tv(uptimeLast, uptime)-interval*1000*COUNT_INTERVAL)   
    41.                 /COUNT_INTERVAL);   
    42.         uptimeLast=uptime;  
    43.     }  
    44.     count++;  
    45. }   
    46.   
    47. static int __init module_hrtimer_init( void )  
    48. {  
    49.     struct timespec uptime;   
    50.       
    51.     printk(KERN_INFO"HR Timer module installing ");  
    52.       
    53.     hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );  
    54.     
    55.     ktime = ktime_set( interval/1000000, (interval%1000000)*1000 );  
    56.     hr_timer.function = my_hrtimer_callback;  
    57.   
    58.     hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );  
    59.   
    60.     do_posix_clock_monotonic_gettime(&uptime);  
    61.     uptimeLast = uptime;  
    62.     printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns ", (unsigned long) uptime.tv_sec,    
    63.                                         uptime.tv_nsec );   
    64.   
    65.     INIT_WORK(&wq_hrtimer, wq_func_hrtimer);  
    66.     return 0;  
    67. }  
    68.   
    69. static void __exit module_hrtimer_exit( void )  
    70. {  
    71.     int ret;  
    72.   
    73.     ret = hrtimer_cancel( &hr_timer );  
    74.     if (ret)   
    75.         printk("The timer was still in use... ");  
    76.   
    77.     printk("HR Timer module uninstalling ");  
    78.     return;  
    79. }  
    80.   
    81. module_init(module_hrtimer_init);  
    82. module_exit(module_hrtimer_exit);  

    如果在my_hrtimer_callback()里面直接返回HRTIMER_RESTART会导致立即重新进入my_hrtimer_callback()。这时shell对输入没有任何响应。

    所以为了解决这个问题,创建了一个work queue,由my_hrtimer_callback() enqueue这个工作队列。在work queue的处理函数里面重启hrtimer。

    但是这样带来的负面影响是进入hrtimer_callback和wq_func被调用之间有Linux系统调度引入的延迟,导致interval出现误差。经过实测,在ZC706缺省配置下,这个延迟大约是17.5us (hrtimer interval为5ms,每20秒计算一次interval误差)。

    [plain] view plain copy
     
      1. root@zynq:~/nfs/hrtimer# insmod hrtimer.ko  
      2. HR Timer module installing  
      3. hrtimer:    2900 sec, 993366078 ns  
      4. hrtimer:    2900 sec, 998395278 ns, interval_delay=369966 ns  
      5. hrtimer:    2921 sec,  69525447 ns, interval_delay=17782 ns  
      6. hrtimer:    2941 sec, 139764655 ns, interval_delay=17559 ns  
      7. hrtimer:    2961 sec, 210029519 ns, interval_delay=17566 ns  
      8. hrtimer:    2981 sec, 280465631 ns, interval_delay=17609 ns  
      9. hrtimer:    3001 sec, 350677038 ns, interval_delay=17552 ns  
      10. hrtimer:    3021 sec, 420625114 ns, interval_delay=17487 ns  
      11. hrtimer:    3041 sec, 490744847 ns, interval_delay=17529 ns 
  • 相关阅读:
    pwnable.kr login之write up
    安装ubuntu16.4后
    HTML资源定位器-URL
    【实验吧】编程循环&&求底运算
    【SQL注入】mysql中information_schema详解
    C#之BackgroundWorker从简单入门到深入精通的用法总结
    C#使用NPOI对Excel文档进行读、写、导入、导出等操作的dll最新版2.5.1+2.3.0
    Visual Studio中Debug与Release以及x86、x64、Any CPU的区别
    C# 使用BackgroundWorker例子及注意点
    C# BackgroundWorker组件学习入门介绍
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7098243.html
Copyright © 2020-2023  润新知