From: Martin Z. <co...@mz...> - 2010-02-06 21:20:26
|
Dear Michael! > I hope you all do understand what I'm talking about.... To be honest, I don't... :) First, I think we have to define the problem, because in my opinion there are two of them that need separate solving. One is the time-shift that is introduced by processing. The other one is that of unsynchronised widgets, and I have already solved that, at least partially. So let's talk about time-shifts. On looking through the code again, I think I have pinpointed the problem. First, using one-shot timers for widgets doesn't seem to make sense to me. First, there is the overhead of deleting the old one and creating a new one. Second, most (if not all) widgets are triggered regularly, so using one-shot timers isn't the best solution. If this was changed (I have temporally done this for "widget_icon.c" while so far ignoring the problem of timer deletion or widget deletion), we can now move on to "timer.c". First, have a look at line 182, which is where a single *continuous* timer is being respawned: } else { Timers[i].when = now; timer_inc(&Timers[i].when, Timers[i].interval); } I think the second line (which sets the timer to "now") is plain wrong because it automatically delays a timer by the time the callback needs for processing. So this line should be removed as fast as possible! Another, albeit smaller, problem lies in line 206: /* delay until next timer event */ struct timeval diff; timersub(&Timers[min].when, &now, &diff); delay->tv_sec = diff.tv_sec; /* microseconds to nanoseconds!! */ delay->tv_nsec = diff.tv_usec * 1000; Here, the delay to the next timer event is too long, because we ignore the processing time between reading the value for "now" and calculating the delay. What we need here is to update the value for "now" and only then calculate the delay: /* delay until next timer event */ struct timeval diff; timersub(&Timers[min].when, &now, &diff); gettimeofday(&now, NULL); [...] Now for a real time test: one single icon widget with update set to 1000 ms. I have also removed the timers with id 0, as they are used for updating the X11 driver. They do, however, behave just as the other timers. Before the changes mentioned above (continuous timers and the two code sections): Timers[ 1]: 1265490676.166966 Timers[ 2]: 1265490677.167110 Timers[ 1]: 1265490678.167248 Timers[ 2]: 1265490679.167385 Timers[ 1]: 1265490680.167532 Timers[ 2]: 1265490681.167672 Timers[ 1]: 1265490682.167822 Timers[ 2]: 1265490683.167960 Timers[ 1]: 1265490684.168108 Timers[ 2]: 1265490685.168249 Timers[ 1]: 1265490686.168387 Timers[ 2]: 1265490687.168525 Timers[ 1]: 1265490688.168652 Timers[ 2]: 1265490689.168780 Timers[ 1]: 1265490690.168908 After 15 seconds (and therefore 15 updates), we have a time-shift of 1.9 ms. Just for one single widget! After applying the changes: Timers[ 1]: 1265490514.609078 Timers[ 1]: 1265490515.609079 Timers[ 1]: 1265490516.609078 Timers[ 1]: 1265490517.609078 Timers[ 1]: 1265490518.609079 Timers[ 1]: 1265490519.609078 Timers[ 1]: 1265490520.609076 Timers[ 1]: 1265490521.609079 Timers[ 1]: 1265490522.609078 Timers[ 1]: 1265490523.609079 Timers[ 1]: 1265490524.609079 Timers[ 1]: 1265490525.609079 Timers[ 1]: 1265490526.609078 Timers[ 1]: 1265490527.609094 <-- glitch Timers[ 1]: 1265490528.609078 Here we only have a time-shift of only 1 *microsecond*! Also note that the "glitch" is recovered later on. So it seems that we don't need any "processing magic" at all. Just convert the widgets to continuous timers and make the two changes in "timer.c", and we're set! Actually, I didn't think it was *that* easy, and maybe I have overseen something -- but maybe that's just it! :) Have a nice week-end, Martin -- www.mzuther.de www.radix-musik.de |