I make a function like this
trace_printk("111111");
udelay(4000);
trace_printk("222222");
and the log shows it's 4.01 ms , it'OK
But when i call like this
trace_printk("111111");
ndelay(10000);
ndelay(10000);
ndelay(10000);
ndelay(10000);
....
....//totally 400 ndelay calls
trace_printk("222222");
the log will shows 4.7 ms. It's not acceptable. Why the error of ndelay is so huge like this?
Look deep in the kernel code i found the implemention of this two functions
void __udelay(unsigned long usecs)
{
__const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
}
void __ndelay(unsigned long nsecs)
{
__const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
}
I thought udelay will be 1000 times than ndelay, but it's not, why?
Every time you call it, a rounding error is added. Note the comment
2**32 / 1000000000
. That value is really ~4.29, but it was rounded up to 5. That's a pretty hefty error.By contrast the udelay error is small: (~4294.97 versus 4295 [0x10c7]).
As you've already noticed, the nanosecond delay implementation is quite a coarse approximation compared to the millisecond delay, because of the
0x5
constant factor used.0x10c7 / 0x5
is approximately 859. Using0x4
would be closer to 1000 (approximately 1073).However, using 0x4 would cause the
ndelay
to be less than the number of nanoseconds requested. In general, delay functions aim to provide a delay at least as long as requested by the user (see here: http://practicepeople.blogspot.jp/2013/08/kernel-programming-busy-waiting-delay.html).You can use ktime_get_ns() to get high precision time since boot. So you can use it not only as high precision delay but also as high precision timer. There is example: