First there is a low-precision timer, and then a high-precision timer is introduced. Low precision timer can only provide millisecond level timing time, because it actually depends on jiffies. A jiffies time is the minimum timing time that it can provide. For example, if config Hz is configured as 250, then a jiffies is 4ms, so the precision of low precision timer is 4ms; while high precision timer is different, it does not depend on jiffies, or even jif FIEs relies on a high-precision timer, because the accumulation of jiffies is actually realized by a special high-precision timer. The high-precision timer only depends on the hardware timer, so it can provide nanosecond level precision. In addition to the difference in timing event accuracy seen from the function interface, what are the differences between high-precision timers and low-precision timers? Let's discuss it with examples.
- High precision timer test code
#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(¤t_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);
- Low precision timer test code
#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(¤t_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);
The above two codes set a high priority timer and a low priority timer respectively. The timeout time is 1 second. The current time is obtained in the timeout processing function, and the actual time interval of the two timeouts is finally calculated.
- High priority timer test results
[ 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
- Low priority timer test results
[ 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
Hardware platform, interrupt resource competition and CPU resource competition will lead to some errors in the accuracy of timeout, but under the same conditions, we can see that the timeout accuracy of high priority timer is at microsecond level, while that of low priority timer is at millisecond level. We can find that the high priority timer is processed in the interrupt context, while the low priority timer is processed in the soft interrupt context. In my test environment, the soft interrupt is threaded, so in fact, the low priority timer is processed in the process context. It is inevitable that there is such a difference in precision.