On Sun, 12 Sep 2004 16:33:19 +0200 Henry Margies wrote:
| Hello
| | Why is nobody answering my question? I tested my application also on
| x86. The result is the same. For me, it looks like there is a problem.
| The only difference is, that my x86 has a TICK value of 1ms and my arm
| device a value of 10ms
| | Imagine, there are 3 timers. | | timer1 is for 1s,
| timer2 is for 0.1s,
| timer3 is for 0.01s.
| | Now, timer1 should finish after 10 times of timer2 and 100 times of
| timer3. But this is not, because every interval is 1ms (10ms on arm)
| longer than it should be.
| | (on x86)1000.8488 expected That number looks a few nanoseconds too small.
| timer1 finishes after 1001ms,
| timer2 after 10*101ms = 1010ms,
| timer3 after 100*11ms = 1100ms | | (on arm)
| timer1 finishes after 1010ms,
| timer2 after 10*110ms = 1100ms,
| timer3 after 100*20ms = 2000ms!!! | | The output of my test application is the following on x86:
| | (timer1)
| TIMER_INTERVAL =1000ms
| COUNTER =1
| expected elapsed time =1000ms
| elapsed time =1000ms and 845ns
| | (timer2)10 * 100.9847ms is 1009.847ms Looks good.
| TIMER_INTERVAL =100ms
| COUNTER =10
| expected elapsed time =1000ms
| elapsed time =1010ms and 29ns
| | (timer3)100 * 10.998ms is 1099.8 This also looks good.
| TIMER_INTERVAL =10ms
| COUNTER =100
| expected elapsed time =1000ms
| elapsed time =1099ms and 744ns
| | | Please have a look into my test application:For the x86 this is correct as 10 ticks would be 9.99849 ms which is less than the asked for 10ms. As to the ARM, we need to know the CLOCK_TICK_RATE. This is used to determine the actual tick size using the following:
| | void sig_alarm(int i)
| {
| struct timeval tv;
| | gettimeofday(&tv, NULL);
| | if (c>=COUNTER) {
| int elapsed;
| c = 0;
| elapsed = (tv.tv_sec-start.tv_sec)*1000000
| + tv.tv_usec-start.tv_usec;
| | printf( "TIMER_INTERVAL =%dms\n"
| "COUNTER =%d\n"
| "expected elapsed time =%dms\n",
| TIMER_INTERVAL,
| COUNTER,
| TIMER_INTERVAL*COUNTER);
| | printf("elapsed time =%dms and %dns\n\n\n",
| elapsed/1000, elapsed%1000);
| | }
| | if (!c) | start = tv;
| | c++;
| | }
| | int main()
| {
| struct itimerval itimer;
| | itimer.it_interval.tv_sec = 0;
| itimer.it_interval.tv_usec= TIMER_INTERVAL*1000;
| | itimer.it_value.tv_sec = 0;
| itimer.it_value.tv_usec= TIMER_INTERVAL*1000;
| | signal(SIGALRM, sig_alarm);
| | setitimer(ITIMER_REAL, &itimer, NULL);
| | getc(stdin);
| | return 0;
| }
| | | As I wrote, I think the problem is in timeval_to_jiffies. On my arm
| device 10ms are converted to 20ticks. On x86, 10ms are converted to
| 11ticks.
| | Can somebody agree on that or at least point me to my mistakes?What you are missing here is that the tick size for HZ=1000 is 999849 nano seconds. THIS is why the scaled math was done.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I agree that timeval_to_jiffies() has some serious rounding errors.
I don't see why it even cares about any of the scaled math in the
(inline) function. I rewrote it (for userspace, not kernelspace)
like so, with expected results:
static __inline__ unsigned long
tv_to_jifs(const struct timeval *value)
{
unsigned long sec = value->tv_sec;
long usec = value->tv_usec;
if (sec >= MAX_SEC_IN_JIFFIES){
sec = MAX_SEC_IN_JIFFIES;
usec = 0;
}
return (((u64)sec * (u64)HZ) +
(((u64)usec + (u64)HZ - 1LL) / (unsigned long)HZ));
}
Results of timeval_to_jiffies() compared to tv_to_jifs() [small sample]:
(tv_sec is fixed at 5, with tv_usec varying)
+--- timeval_to_jiffies()
V v--- tv_to_jifs()
tv_usec: 499000, jifs: 5500, jf2: 5499
tv_usec: 499100, jifs: 5500, jf2: 5500
tv_usec: 499900, jifs: 5501, jf2: 5500
tv_usec: 500000, jifs: 5501, jf2: 5500
tv_usec: 500100, jifs: 5501, jf2: 5501
tv_usec: 500900, jifs: 5502, jf2: 5501
tv_usec: 501000, jifs: 5502, jf2: 5501
tv_usec: 501100, jifs: 5502, jf2: 5502
tv_usec: 501900, jifs: 5503, jf2: 5502
tv_usec: 502000, jifs: 5503, jf2: 5502
tv_usec: 502100, jifs: 5503, jf2: 5503
I think that tv_to_jifs() can be written for kernel use by using
do_div(), but I haven't tried that yet.
If you would like I could send you the test code I used to test the conversion functions.