* [Xenomai-core] ns vs. tsc as internal timer base
@ 2006-06-13 10:51 Jan Kiszka
2006-06-13 11:16 ` Philippe Gerum
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Jan Kiszka @ 2006-06-13 10:51 UTC (permalink / raw)
To: xenomai-core
[-- Attachment #1: Type: text/plain, Size: 1384 bytes --]
Hi,
between some football half-times of the last days ;), I played a bit
with a hand-optimised xnarch_tsc_to_ns() for x86. Using scaled math, I
achieved between 3 (P-I 133 MHz) to 4 times (P-M 1.3 GHz) faster
conversions than with the current variant. While this optimisation only
saves a few ten nanoseconds on high-end, slow processors can gain
several hundreds of nanos per conversion (my P-133: -600 ns).
This does not come for free: accuracy of very large values is slightly
worse, but that's likely negligible compared to the clock accuracy of
TSCs (does anyone have any real numbers on the latter, BTW?).
As we loose some bits the one way, converting back still requires "real"
division (i.e. the use of the existing slower xnarch_ns_to_tsc).
Otherwise, we would get significant errors already for small intervals.
To avoid loosing the optimisation again in ns_to_tsc, I thought about
basing the whole internal timer arithmetics on nanoseconds instead of
TSCs as it is now. Although I dug quite a lot in the current timer
subsystem the last weeks, I may still oversee aspects and I'm
x86-biased. Therefore my question before thinking or even patching
further this way: What was the motivation to choose TSCs as internal
time base? Any pitfalls down the road (except introducing regressions)?
Jan
PS: All this would be 2.3-stuff, for sure.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 10:51 [Xenomai-core] ns vs. tsc as internal timer base Jan Kiszka @ 2006-06-13 11:16 ` Philippe Gerum 2006-06-13 11:56 ` Jan Kiszka 2006-06-13 11:59 ` [Xenomai-core] ns vs. tsc as internal timer base Gilles Chanteperdrix 2006-06-13 12:00 ` Anders Blomdell 2 siblings, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 11:16 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core Jan Kiszka wrote: > Hi, > > between some football half-times of the last days ;), I played a bit > with a hand-optimised xnarch_tsc_to_ns() for x86. Using scaled math, I > achieved between 3 (P-I 133 MHz) to 4 times (P-M 1.3 GHz) faster > conversions than with the current variant. While this optimisation only > saves a few ten nanoseconds on high-end, slow processors can gain > several hundreds of nanos per conversion (my P-133: -600 ns). > I did exactely the same a few weeks ago, based on Anzinger's scaled math from i386/kernel/timers/timer_tsc.c. And indeed, I had x 20 performance improvements in some cases. > This does not come for free: accuracy of very large values is slightly > worse, but that's likely negligible compared to the clock accuracy of > TSCs (does anyone have any real numbers on the latter, BTW?). > We do start losing significant precision for 2 ms delays and above, IIRC. This could be an issue for some events in aperiodic mode, albeit we could use a plain divide for those. The cost of conditionally doing this remains to be evaluated though. > As we loose some bits the one way, converting back still requires "real" > division (i.e. the use of the existing slower xnarch_ns_to_tsc). > Otherwise, we would get significant errors already for small intervals. > > To avoid loosing the optimisation again in ns_to_tsc, I thought about > basing the whole internal timer arithmetics on nanoseconds instead of > TSCs as it is now. Although I dug quite a lot in the current timer > subsystem the last weeks, I may still oversee aspects and I'm > x86-biased. Therefore my question before thinking or even patching > further this way: What was the motivation to choose TSCs as internal > time base? TSC are not the whole nucleus time base, but only the timer management one. The motivation to use TSCs in nucleus/timer.c was to pick a unit which would not require any conversion beyond the initial one in xntimer_start. > Any pitfalls down the road (except introducing regressions)? Well, pitfalls expected from changing the core idea of time of the timer management code... :o> > > Jan > > > PS: All this would be 2.3-stuff, for sure. > > > > ------------------------------------------------------------------------ > > _______________________________________________ > Xenomai-core mailing list > Xenomai-core@domain.hid > https://mail.gna.org/listinfo/xenomai-core -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 11:16 ` Philippe Gerum @ 2006-06-13 11:56 ` Jan Kiszka 2006-06-13 12:31 ` Philippe Gerum 0 siblings, 1 reply; 27+ messages in thread From: Jan Kiszka @ 2006-06-13 11:56 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai-core [-- Attachment #1: Type: text/plain, Size: 4043 bytes --] Philippe Gerum wrote: > Jan Kiszka wrote: >> Hi, >> >> between some football half-times of the last days ;), I played a bit >> with a hand-optimised xnarch_tsc_to_ns() for x86. Using scaled math, I >> achieved between 3 (P-I 133 MHz) to 4 times (P-M 1.3 GHz) faster >> conversions than with the current variant. While this optimisation only >> saves a few ten nanoseconds on high-end, slow processors can gain >> several hundreds of nanos per conversion (my P-133: -600 ns). >> > > I did exactely the same a few weeks ago, based on Anzinger's scaled math :) We should coordinate better. > from i386/kernel/timers/timer_tsc.c. And indeed, I had x 20 performance > improvements in some cases. Oops, that sounds like a bit too extreme optimisations. Is the original version varying that much? I didn't observe this. Here is my current version, BTW: long tsc_scale; unsigned int tsc_shift = 31; static inline long long fast_tsc_to_ns(long long ts) { long long ret; __asm__ ( /* HI = HIWORD(ts) * tsc_scale */ "mov %%eax,%%ebx\n\t" "mov %%edx,%%eax\n\t" "imull %2\n\t" "mov %%eax,%%esi\n\t" "mov %%edx,%%edi\n\t" /* LO = LOWORD(ts) * tsc_scale */ "mov %%ebx,%%eax\n\t" "mull %2\n\t" /* ret = (HI << 32) + LO */ "add %%esi,%%edx\n\t" "adc $0,%%edi\n\t" /* ret = ret >> tsc_shift */ "shrd %%cl,%%edx,%%eax\n\t" "shrd %%cl,%%edi,%%edx\n\t" : "=A"(ret) : "A" (ts), "m" (tsc_scale), "c" (tsc_shift) : "ebx", "esi", "edi"); return ret; } void init_tsc(unsigned long cpu_freq) { unsigned long long scale; while (1) { scale = do_div(1000000000LL << tsc_shift, cpu_freq); if (scale <= 0x7FFFFFFF) break; tsc_shift--; } tsc_scale = scale; } This version will use 31 (GHz cpu_freq) to 26 (~32 MHz) shifts, i.e. a bit more than the Linux kernel's 22 bits. > >> This does not come for free: accuracy of very large values is slightly >> worse, but that's likely negligible compared to the clock accuracy of >> TSCs (does anyone have any real numbers on the latter, BTW?). >> > > We do start losing significant precision for 2 ms delays and above, > IIRC. This could be an issue for some events in aperiodic mode, albeit > we could use a plain divide for those. The cost of conditionally doing > this remains to be evaluated though. Maybe I tested (not calculated - math is too hard for me :o)) the wrong values, but I didn't see such high regressions. > >> As we loose some bits the one way, converting back still requires "real" >> division (i.e. the use of the existing slower xnarch_ns_to_tsc). >> Otherwise, we would get significant errors already for small intervals. >> >> To avoid loosing the optimisation again in ns_to_tsc, I thought about >> basing the whole internal timer arithmetics on nanoseconds instead of >> TSCs as it is now. Although I dug quite a lot in the current timer >> subsystem the last weeks, I may still oversee aspects and I'm >> x86-biased. Therefore my question before thinking or even patching >> further this way: What was the motivation to choose TSCs as internal >> time base? > > TSC are not the whole nucleus time base, but only the timer management > one. The motivation to use TSCs in nucleus/timer.c was to pick a unit > which would not require any conversion beyond the initial one in > xntimer_start. That helps strictly periodic application timers, not aperiodic ones like timeouts. > >> Any pitfalls down the road (except introducing regressions)? > > Well, pitfalls expected from changing the core idea of time of the timer > management code... :o> > You mean turning rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,RTHAL_CPU_FREQ)); into rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,1000000000)); e.g. ? Jan [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 11:56 ` Jan Kiszka @ 2006-06-13 12:31 ` Philippe Gerum 2006-06-13 13:07 ` Gilles Chanteperdrix ` (2 more replies) 0 siblings, 3 replies; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 12:31 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core Jan Kiszka wrote: > Philippe Gerum wrote: > >>Jan Kiszka wrote: >> >>>Hi, >>> >>>between some football half-times of the last days ;), I played a bit >>>with a hand-optimised xnarch_tsc_to_ns() for x86. Using scaled math, I >>>achieved between 3 (P-I 133 MHz) to 4 times (P-M 1.3 GHz) faster >>>conversions than with the current variant. While this optimisation only >>>saves a few ten nanoseconds on high-end, slow processors can gain >>>several hundreds of nanos per conversion (my P-133: -600 ns). >>> >> >>I did exactely the same a few weeks ago, based on Anzinger's scaled math > > > :) We should coordinate better. > The answer is published roadmap + todo list, but this requires some organisation we have not been able to setup yet. > >>from i386/kernel/timers/timer_tsc.c. And indeed, I had x 20 performance >>improvements in some cases. > > > Oops, that sounds like a bit too extreme optimisations. Is the original > version varying that much? I didn't observe this. > > Here is my current version, BTW: > > long tsc_scale; > unsigned int tsc_shift = 31; > > static inline long long fast_tsc_to_ns(long long ts) > { > long long ret; > > __asm__ ( > /* HI = HIWORD(ts) * tsc_scale */ > "mov %%eax,%%ebx\n\t" > "mov %%edx,%%eax\n\t" > "imull %2\n\t" > "mov %%eax,%%esi\n\t" > "mov %%edx,%%edi\n\t" > > /* LO = LOWORD(ts) * tsc_scale */ > "mov %%ebx,%%eax\n\t" > "mull %2\n\t" > > /* ret = (HI << 32) + LO */ > "add %%esi,%%edx\n\t" > "adc $0,%%edi\n\t" > > /* ret = ret >> tsc_shift */ > "shrd %%cl,%%edx,%%eax\n\t" > "shrd %%cl,%%edi,%%edx\n\t" > : "=A"(ret) > : "A" (ts), "m" (tsc_scale), "c" (tsc_shift) > : "ebx", "esi", "edi"); > > return ret; > } > > void init_tsc(unsigned long cpu_freq) > { > unsigned long long scale; > > while (1) { > scale = do_div(1000000000LL << tsc_shift, cpu_freq); > if (scale <= 0x7FFFFFFF) > break; > tsc_shift--; > } > tsc_scale = scale; > } > > This version will use 31 (GHz cpu_freq) to 26 (~32 MHz) shifts, i.e. a > bit more than the Linux kernel's 22 bits. > Here is likely why we have different levels of accuracy and performance, firstly my version is bluntly based on the khz freq, secondly it calculates the other way around, i.e. ns2tsc, so that tsc are keep in the inner code, but more efficiently converted from ns counts passed to the outer interface: static unsigned long ns2cyc_scale; #define NS2CYC_SCALE_FACTOR 10 /* 2^10, carefully chosen */ static inline void set_ns2cyc_scale(unsigned long cpu_khz) { ns2cyc_scale = (cpu_khz << NS2CYC_SCALE_FACTOR) / 1000000; } static inline unsigned long long ns_2_cycles(unsigned long long ns) { return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; } >> >>TSC are not the whole nucleus time base, but only the timer management >>one. The motivation to use TSCs in nucleus/timer.c was to pick a unit >>which would not require any conversion beyond the initial one in >>xntimer_start. > > > That helps strictly periodic application timers, not aperiodic ones like > timeouts. > It depends, periodic timers usually exhibit larger delays, so the gain is more significant with oneshot timings incurring smaller delays, hence a higher number of calculations. > >>>Any pitfalls down the road (except introducing regressions)? >> >>Well, pitfalls expected from changing the core idea of time of the timer >>management code... :o> >> > > You mean turning > > rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,RTHAL_CPU_FREQ)); > > into > > rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,1000000000)); > Not really, it was a general remark about changing a code that might have some assumtions on using TSCs. Additionally, only x86 needs to rescale TSC values to the timer frequency, other archs use the same unit on both sides, and such unit might even have nothing to do with any CPU accounting (e.g. blackfin uses a free running timer, ppc uses the internal timebase, etc). This said, it should not have that many assumptions, and in any case, they should be confined to nucleus/timers.c. I think we should give this kind of optimization a try. -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 12:31 ` Philippe Gerum @ 2006-06-13 13:07 ` Gilles Chanteperdrix 2006-06-13 13:28 ` Philippe Gerum 2006-06-13 13:33 ` Jan Kiszka 2006-06-13 16:19 ` Jan Kiszka 2 siblings, 1 reply; 27+ messages in thread From: Gilles Chanteperdrix @ 2006-06-13 13:07 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai Philippe Gerum wrote: > static inline unsigned long long ns_2_cycles(unsigned long long ns) > { > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; This multiplication is 64 bits * 32 bits, the intermediate result may need more than 64 bits, so you should compute it the same way as the beginning of ullimd. Something like: static inline unsigned long long ns_2_cycles(unsigned long long ns) { unsigned nsh, nsl, tlh, tll; unsigned long long th, tl; __rthal_u64tou32(ns, nsh, nsl); tl = rthal_ullmul(nsl, ns2cyc_scale); __rthal_u64tou32(tl, tlh, tll); th = rthal_ullmul(nsh, ns2cyc_scale); th += tlh; tll = (unsigned) th << (32 - NS2CYC_SCALE_FACTOR) | tll >> NS2CYC_SCALE_FACTOR; th >>= NS2CYC_SCALE_FACTOR; return __rthal_u64fromu32(th, tll); } -- Gilles Chanteperdrix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 13:07 ` Gilles Chanteperdrix @ 2006-06-13 13:28 ` Philippe Gerum 2006-06-13 13:34 ` Gilles Chanteperdrix 0 siblings, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 13:28 UTC (permalink / raw) To: Gilles Chanteperdrix; +Cc: xenomai Gilles Chanteperdrix wrote: > Philippe Gerum wrote: > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > > { > > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > > This multiplication is 64 bits * 32 bits, the intermediate result may > need more than 64 bits, so you should compute it the same way as the > beginning of ullimd. Something like: Sure, but the point is that if we were to use such code, we should bound the 64bit operand and would not use it beyond the tolerable loss of accuracy on output (e.g. 2ms). This would require to break longer shots in several smaller ones, relying on the internal timer management logic to redo the shot until it has actually elapsed (which should be a rare case for oneshot timing), a bit like we are currently doing in bounding the values to 2^32-1 right now. Going for ullimd alike implementation somehow impedes the overall effort in reducing the CPU footprint, I guess. This said, I have still no clue if the gain in computation cycles is worth the additional overhead of dealing with possibly early shots - I tend to think it would be better on average though. > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > { > unsigned nsh, nsl, tlh, tll; > unsigned long long th, tl; > > __rthal_u64tou32(ns, nsh, nsl); > tl = rthal_ullmul(nsl, ns2cyc_scale); > __rthal_u64tou32(tl, tlh, tll); > th = rthal_ullmul(nsh, ns2cyc_scale); > th += tlh; > > tll = (unsigned) th << (32 - NS2CYC_SCALE_FACTOR) | tll >> NS2CYC_SCALE_FACTOR; > th >>= NS2CYC_SCALE_FACTOR; > return __rthal_u64fromu32(th, tll); > } > > -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 13:28 ` Philippe Gerum @ 2006-06-13 13:34 ` Gilles Chanteperdrix 2006-06-13 13:45 ` Philippe Gerum 0 siblings, 1 reply; 27+ messages in thread From: Gilles Chanteperdrix @ 2006-06-13 13:34 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai Philippe Gerum wrote: > Gilles Chanteperdrix wrote: > > Philippe Gerum wrote: > > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > > > { > > > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > > > > This multiplication is 64 bits * 32 bits, the intermediate result may > > need more than 64 bits, so you should compute it the same way as the > > beginning of ullimd. Something like: > > Sure, but the point is that if we were to use such code, we should bound > the 64bit operand and would not use it beyond the tolerable loss of > accuracy on output (e.g. 2ms). This would require to break longer shots > in several smaller ones, relying on the internal timer management logic > to redo the shot until it has actually elapsed (which should be a rare > case for oneshot timing), a bit like we are currently doing in bounding > the values to 2^32-1 right now. Going for ullimd alike implementation > somehow impedes the overall effort in reducing the CPU footprint, I > guess. This said, I have still no clue if the gain in computation cycles > is worth the additional overhead of dealing with possibly early shots - > I tend to think it would be better on average though. Ok, we could then write: static inline unsigned long long ns_2_cycles(unsigned ns) { return (unsigned long long) ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; } -- Gilles Chanteperdrix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 13:34 ` Gilles Chanteperdrix @ 2006-06-13 13:45 ` Philippe Gerum 0 siblings, 0 replies; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 13:45 UTC (permalink / raw) To: Gilles Chanteperdrix; +Cc: xenomai Gilles Chanteperdrix wrote: > Philippe Gerum wrote: > > Gilles Chanteperdrix wrote: > > > Philippe Gerum wrote: > > > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > > > > { > > > > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > > > > > > This multiplication is 64 bits * 32 bits, the intermediate result may > > > need more than 64 bits, so you should compute it the same way as the > > > beginning of ullimd. Something like: > > > > Sure, but the point is that if we were to use such code, we should bound > > the 64bit operand and would not use it beyond the tolerable loss of > > accuracy on output (e.g. 2ms). This would require to break longer shots > > in several smaller ones, relying on the internal timer management logic > > to redo the shot until it has actually elapsed (which should be a rare > > case for oneshot timing), a bit like we are currently doing in bounding > > the values to 2^32-1 right now. Going for ullimd alike implementation > > somehow impedes the overall effort in reducing the CPU footprint, I > > guess. This said, I have still no clue if the gain in computation cycles > > is worth the additional overhead of dealing with possibly early shots - > > I tend to think it would be better on average though. > > Ok, we could then write: > > static inline unsigned long long ns_2_cycles(unsigned ns) > { > return (unsigned long long) ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > } > Yep. -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 12:31 ` Philippe Gerum 2006-06-13 13:07 ` Gilles Chanteperdrix @ 2006-06-13 13:33 ` Jan Kiszka 2006-06-13 13:51 ` Philippe Gerum 2006-06-13 16:19 ` Jan Kiszka 2 siblings, 1 reply; 27+ messages in thread From: Jan Kiszka @ 2006-06-13 13:33 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai-core [-- Attachment #1: Type: text/plain, Size: 4549 bytes --] Philippe Gerum wrote: > Jan Kiszka wrote: >> Philippe Gerum wrote: >>> from i386/kernel/timers/timer_tsc.c. And indeed, I had x 20 performance >>> improvements in some cases. >> >> Oops, that sounds like a bit too extreme optimisations. Is the original >> version varying that much? I didn't observe this. >> >> Here is my current version, BTW: >> >> long tsc_scale; >> unsigned int tsc_shift = 31; >> >> static inline long long fast_tsc_to_ns(long long ts) >> { >> long long ret; >> >> __asm__ ( >> /* HI = HIWORD(ts) * tsc_scale */ >> "mov %%eax,%%ebx\n\t" >> "mov %%edx,%%eax\n\t" >> "imull %2\n\t" >> "mov %%eax,%%esi\n\t" >> "mov %%edx,%%edi\n\t" >> >> /* LO = LOWORD(ts) * tsc_scale */ >> "mov %%ebx,%%eax\n\t" >> "mull %2\n\t" >> >> /* ret = (HI << 32) + LO */ >> "add %%esi,%%edx\n\t" >> "adc $0,%%edi\n\t" >> >> /* ret = ret >> tsc_shift */ >> "shrd %%cl,%%edx,%%eax\n\t" >> "shrd %%cl,%%edi,%%edx\n\t" >> : "=A"(ret) >> : "A" (ts), "m" (tsc_scale), "c" (tsc_shift) >> : "ebx", "esi", "edi"); >> >> return ret; >> } >> >> void init_tsc(unsigned long cpu_freq) >> { >> unsigned long long scale; >> >> while (1) { >> scale = do_div(1000000000LL << tsc_shift, cpu_freq); >> if (scale <= 0x7FFFFFFF) >> break; >> tsc_shift--; >> } >> tsc_scale = scale; >> } >> >> This version will use 31 (GHz cpu_freq) to 26 (~32 MHz) shifts, i.e. a >> bit more than the Linux kernel's 22 bits. >> > > Here is likely why we have different levels of accuracy and performance, > firstly my version is bluntly based on the khz freq, secondly it > calculates the other way around, i.e. ns2tsc, so that tsc are keep in > the inner code, but more efficiently converted from ns counts passed to > the outer interface: > > static unsigned long ns2cyc_scale; > #define NS2CYC_SCALE_FACTOR 10 /* 2^10, carefully chosen */ Linux only uses 10 bits for scheduling time calculation, which is tick-based (low-res) anyway. The tsc clock_source uses 22 bits. The latter overflows after an hour or so, because they drop all bits > 64 after the multiplication - insignificantly faster when using optimised code anyway. > > static inline void set_ns2cyc_scale(unsigned long cpu_khz) > { > ns2cyc_scale = (cpu_khz << NS2CYC_SCALE_FACTOR) / 1000000; > } > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > { > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > } > >>> >>> TSC are not the whole nucleus time base, but only the timer management >>> one. The motivation to use TSCs in nucleus/timer.c was to pick a unit >>> which would not require any conversion beyond the initial one in >>> xntimer_start. >> >> >> That helps strictly periodic application timers, not aperiodic ones like >> timeouts. >> > > It depends, periodic timers usually exhibit larger delays, so the gain > is more significant with oneshot timings incurring smaller delays, hence > a higher number of calculations. > >> >>>> Any pitfalls down the road (except introducing regressions)? >>> >>> Well, pitfalls expected from changing the core idea of time of the timer >>> management code... :o> >>> >> >> You mean turning >> >> rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,RTHAL_CPU_FREQ)); >> >> >> into >> >> rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,1000000000)); >> >> > > Not really, it was a general remark about changing a code that might > have some assumtions on using TSCs. Additionally, only x86 needs to > rescale TSC values to the timer frequency, other archs use the same unit > on both sides, and such unit might even have nothing to do with any CPU > accounting (e.g. blackfin uses a free running timer, ppc uses the > internal timebase, etc). Ok, an interesting aspect I already assumed but didn't check in details yet. That makes dealing with TSCs interesting again on != x86. In contrast, on x86, there is the aspect of frequency scaling that Anders brought up and which would speak pro nanos. > > This said, it should not have that many assumptions, and in any case, > they should be confined to nucleus/timers.c. I think we should give this > kind of optimization a try. > Yep, it just needs some more brain cycles how to do this precisely. Jan [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 13:33 ` Jan Kiszka @ 2006-06-13 13:51 ` Philippe Gerum 0 siblings, 0 replies; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 13:51 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core Jan Kiszka wrote: > Philippe Gerum wrote: > >>Jan Kiszka wrote: >> >>>Philippe Gerum wrote: >>> >>>>from i386/kernel/timers/timer_tsc.c. And indeed, I had x 20 performance >>>>improvements in some cases. >>> >>>Oops, that sounds like a bit too extreme optimisations. Is the original >>>version varying that much? I didn't observe this. >>> >>>Here is my current version, BTW: >>> >>>long tsc_scale; >>>unsigned int tsc_shift = 31; >>> >>>static inline long long fast_tsc_to_ns(long long ts) >>>{ >>> long long ret; >>> >>> __asm__ ( >>> /* HI = HIWORD(ts) * tsc_scale */ >>> "mov %%eax,%%ebx\n\t" >>> "mov %%edx,%%eax\n\t" >>> "imull %2\n\t" >>> "mov %%eax,%%esi\n\t" >>> "mov %%edx,%%edi\n\t" >>> >>> /* LO = LOWORD(ts) * tsc_scale */ >>> "mov %%ebx,%%eax\n\t" >>> "mull %2\n\t" >>> >>> /* ret = (HI << 32) + LO */ >>> "add %%esi,%%edx\n\t" >>> "adc $0,%%edi\n\t" >>> >>> /* ret = ret >> tsc_shift */ >>> "shrd %%cl,%%edx,%%eax\n\t" >>> "shrd %%cl,%%edi,%%edx\n\t" >>> : "=A"(ret) >>> : "A" (ts), "m" (tsc_scale), "c" (tsc_shift) >>> : "ebx", "esi", "edi"); >>> >>> return ret; >>>} >>> >>>void init_tsc(unsigned long cpu_freq) >>>{ >>> unsigned long long scale; >>> >>> while (1) { >>> scale = do_div(1000000000LL << tsc_shift, cpu_freq); >>> if (scale <= 0x7FFFFFFF) >>> break; >>> tsc_shift--; >>> } >>> tsc_scale = scale; >>>} >>> >>>This version will use 31 (GHz cpu_freq) to 26 (~32 MHz) shifts, i.e. a >>>bit more than the Linux kernel's 22 bits. >>> >> >>Here is likely why we have different levels of accuracy and performance, >> firstly my version is bluntly based on the khz freq, secondly it >>calculates the other way around, i.e. ns2tsc, so that tsc are keep in >>the inner code, but more efficiently converted from ns counts passed to >>the outer interface: >> >>static unsigned long ns2cyc_scale; >>#define NS2CYC_SCALE_FACTOR 10 /* 2^10, carefully chosen */ > > > Linux only uses 10 bits for scheduling time calculation, which is > tick-based (low-res) anyway. This code is rather used to compute TSC offsets within a tick, so the max operand is short, bounded and known by design. Hence the scale factor, AFAICS. The tsc clock_source uses 22 bits. The > latter overflows after an hour or so, because they drop all bits > 64 > after the multiplication - insignificantly faster when using optimised > code anyway. > This path to optimizing is about computing reasonably short delays this way, so roll-over and precision would not be a key factor. > >>static inline void set_ns2cyc_scale(unsigned long cpu_khz) >>{ >> ns2cyc_scale = (cpu_khz << NS2CYC_SCALE_FACTOR) / 1000000; >>} >> >>static inline unsigned long long ns_2_cycles(unsigned long long ns) >>{ >> return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; >>} >> >> >>>>TSC are not the whole nucleus time base, but only the timer management >>>>one. The motivation to use TSCs in nucleus/timer.c was to pick a unit >>>>which would not require any conversion beyond the initial one in >>>>xntimer_start. >>> >>> >>>That helps strictly periodic application timers, not aperiodic ones like >>>timeouts. >>> >> >>It depends, periodic timers usually exhibit larger delays, so the gain >>is more significant with oneshot timings incurring smaller delays, hence >>a higher number of calculations. >> >> >>>>>Any pitfalls down the road (except introducing regressions)? >>>> >>>>Well, pitfalls expected from changing the core idea of time of the timer >>>>management code... :o> >>>> >>>You mean turning >>> >>>rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,RTHAL_CPU_FREQ)); >>> >>> >>>into >>> >>>rthal_timer_program_shot(rthal_imuldiv(delay,RTHAL_TIMER_FREQ,1000000000)); >>> >>> >> >>Not really, it was a general remark about changing a code that might >>have some assumtions on using TSCs. Additionally, only x86 needs to >>rescale TSC values to the timer frequency, other archs use the same unit >>on both sides, and such unit might even have nothing to do with any CPU >>accounting (e.g. blackfin uses a free running timer, ppc uses the >>internal timebase, etc). > > > Ok, an interesting aspect I already assumed but didn't check in details > yet. That makes dealing with TSCs interesting again on != x86. In > contrast, on x86, there is the aspect of frequency scaling that Anders > brought up and which would speak pro nanos. > > >>This said, it should not have that many assumptions, and in any case, >>they should be confined to nucleus/timers.c. I think we should give this >>kind of optimization a try. >> > > > Yep, it just needs some more brain cycles how to do this precisely. > > Jan > -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 12:31 ` Philippe Gerum 2006-06-13 13:07 ` Gilles Chanteperdrix 2006-06-13 13:33 ` Jan Kiszka @ 2006-06-13 16:19 ` Jan Kiszka 2006-06-13 16:29 ` Gilles Chanteperdrix 2006-06-13 17:04 ` Philippe Gerum 2 siblings, 2 replies; 27+ messages in thread From: Jan Kiszka @ 2006-06-13 16:19 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai-core [-- Attachment #1: Type: text/plain, Size: 1015 bytes --] Philippe Gerum wrote: > Here is likely why we have different levels of accuracy and performance, > firstly my version is bluntly based on the khz freq, secondly it > calculates the other way around, i.e. ns2tsc, so that tsc are keep in > the inner code, but more efficiently converted from ns counts passed to > the outer interface: > > static unsigned long ns2cyc_scale; > #define NS2CYC_SCALE_FACTOR 10 /* 2^10, carefully chosen */ > > static inline void set_ns2cyc_scale(unsigned long cpu_khz) > { > ns2cyc_scale = (cpu_khz << NS2CYC_SCALE_FACTOR) / 1000000; > } > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > { > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > } Your version performs ~50% better than mine (outperforming the original version by factor 7 on a 1 GHz box, vs. 4.8). I think you compared non-optimised code, didn't you? Without -O2, I see 15 times better performance. [Gilles variant yet refuses the get benchmarked.] Jan [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 16:19 ` Jan Kiszka @ 2006-06-13 16:29 ` Gilles Chanteperdrix 2006-06-13 17:04 ` Philippe Gerum 1 sibling, 0 replies; 27+ messages in thread From: Gilles Chanteperdrix @ 2006-06-13 16:29 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai Jan Kiszka wrote: > Philippe Gerum wrote: > > Here is likely why we have different levels of accuracy and performance, > > firstly my version is bluntly based on the khz freq, secondly it > > calculates the other way around, i.e. ns2tsc, so that tsc are keep in > > the inner code, but more efficiently converted from ns counts passed to > > the outer interface: > > > > static unsigned long ns2cyc_scale; > > #define NS2CYC_SCALE_FACTOR 10 /* 2^10, carefully chosen */ > > > > static inline void set_ns2cyc_scale(unsigned long cpu_khz) > > { > > ns2cyc_scale = (cpu_khz << NS2CYC_SCALE_FACTOR) / 1000000; > > } > > > > static inline unsigned long long ns_2_cycles(unsigned long long ns) > > { > > return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; > > } > > Your version performs ~50% better than mine (outperforming the original > version by factor 7 on a 1 GHz box, vs. 4.8). I think you compared > non-optimised code, didn't you? Without -O2, I see 15 times better > performance. > > [Gilles variant yet refuses the get benchmarked.] Since we accept a smaller range, I think you should benchmark nodiv_imuldiv instead of nodiv_ullimd. And it should perform better since it uses 32 bits shifts which are not real shifts. -- Gilles Chanteperdrix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 16:19 ` Jan Kiszka 2006-06-13 16:29 ` Gilles Chanteperdrix @ 2006-06-13 17:04 ` Philippe Gerum 2006-06-13 17:13 ` Gilles Chanteperdrix 1 sibling, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 17:04 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core Jan Kiszka wrote: > Philippe Gerum wrote: > >>Here is likely why we have different levels of accuracy and performance, >> firstly my version is bluntly based on the khz freq, secondly it >>calculates the other way around, i.e. ns2tsc, so that tsc are keep in >>the inner code, but more efficiently converted from ns counts passed to >>the outer interface: >> >>static unsigned long ns2cyc_scale; >>#define NS2CYC_SCALE_FACTOR 10 /* 2^10, carefully chosen */ >> >>static inline void set_ns2cyc_scale(unsigned long cpu_khz) >>{ >> ns2cyc_scale = (cpu_khz << NS2CYC_SCALE_FACTOR) / 1000000; >>} >> >>static inline unsigned long long ns_2_cycles(unsigned long long ns) >>{ >> return ns * ns2cyc_scale >> NS2CYC_SCALE_FACTOR; >>} > > > Your version performs ~50% better than mine (outperforming the original > version by factor 7 on a 1 GHz box, vs. 4.8). I think you compared > non-optimised code, didn't you? Nah, I'm not that drunk! Without -O2, I see 15 times better > performance. Redone the check here on a Centrino 1.6Mhz, and still have roughly x20 improvement (a bit better actually). I'm using Debian/sarge gcc 3.3.5. > > [Gilles variant yet refuses the get benchmarked.] > > Jan > -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 17:04 ` Philippe Gerum @ 2006-06-13 17:13 ` Gilles Chanteperdrix 2006-06-13 17:58 ` Philippe Gerum 2006-07-25 18:26 ` [Xenomai-core] Timer optimisations, continued Jan Kiszka 0 siblings, 2 replies; 27+ messages in thread From: Gilles Chanteperdrix @ 2006-06-13 17:13 UTC (permalink / raw) To: Philippe Gerum; +Cc: Jan Kiszka, xenomai-core Philippe Gerum wrote: > Redone the check here on a Centrino 1.6Mhz, and still have roughly x20 > improvement (a bit better actually). I'm using Debian/sarge gcc 3.3.5. I think I remember that Pentium M has a much shorter mull instruction than other processors of the family. -- Gilles Chanteperdrix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 17:13 ` Gilles Chanteperdrix @ 2006-06-13 17:58 ` Philippe Gerum 2006-06-14 9:25 ` Jim Cromie 2006-07-25 18:26 ` [Xenomai-core] Timer optimisations, continued Jan Kiszka 1 sibling, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-06-13 17:58 UTC (permalink / raw) To: Gilles Chanteperdrix; +Cc: Jan Kiszka, xenomai-core Gilles Chanteperdrix wrote: > Philippe Gerum wrote: > > Redone the check here on a Centrino 1.6Mhz, and still have roughly x20 > > improvement (a bit better actually). I'm using Debian/sarge gcc 3.3.5. > > I think I remember that Pentium M has a much shorter mull instruction > than other processors of the family. > That would explain. Anyway, as John Stulz put it: "math is hard, lets go shopping!" -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 17:58 ` Philippe Gerum @ 2006-06-14 9:25 ` Jim Cromie 2006-06-14 12:29 ` Philippe Gerum 0 siblings, 1 reply; 27+ messages in thread From: Jim Cromie @ 2006-06-14 9:25 UTC (permalink / raw) To: Philippe Gerum; +Cc: Jan Kiszka, xenomai-core Philippe Gerum wrote: > Gilles Chanteperdrix wrote: >> Philippe Gerum wrote: >> > Redone the check here on a Centrino 1.6Mhz, and still have roughly >> x20 > improvement (a bit better actually). I'm using Debian/sarge >> gcc 3.3.5. >> >> I think I remember that Pentium M has a much shorter mull instruction >> than other processors of the family. >> > > That would explain. Anyway, as John Stulz put it: > "math is hard, lets go shopping!" > Heh. Appropriate that his name (Stultz) comes up here, as his generic-time (GTOD) patchset looks headed for 2.6.18, bringing with it a full re-working of linux timers / timeofday. IN this new world, time is kept on free-running counters. Ive been running this patchset on my soekris for some time, since GTOD detects that the TSC counts slowly, calls it insane, and does timing with the PIT. With GTOD, writing a new clocksource driver is easy, enough so I could do it. My clocksource patch uses the 27 mhz timer on the Geode CPU. Once the TSC is de-rated, mine becomes the best clocksource, and GTOD switches to it. All of which is to say .. new mainline code is coming, should this current rework notion wait, given that its will all need revisited again later ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-14 9:25 ` Jim Cromie @ 2006-06-14 12:29 ` Philippe Gerum 2006-06-14 13:07 ` Jan Kiszka 0 siblings, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-06-14 12:29 UTC (permalink / raw) To: Jim Cromie; +Cc: Jan Kiszka, xenomai-core Jim Cromie wrote: > Philippe Gerum wrote: > >> Gilles Chanteperdrix wrote: >> >>> Philippe Gerum wrote: >>> > Redone the check here on a Centrino 1.6Mhz, and still have roughly >>> x20 > improvement (a bit better actually). I'm using Debian/sarge >>> gcc 3.3.5. >>> >>> I think I remember that Pentium M has a much shorter mull instruction >>> than other processors of the family. >>> >> >> That would explain. Anyway, as John Stulz put it: >> "math is hard, lets go shopping!" >> > > Heh. Appropriate that his name (Stultz) comes up here, as his > generic-time (GTOD) > patchset looks headed for 2.6.18, bringing with it a full re-working > of linux timers / timeofday. IN this new world, time is kept on > free-running counters. > > Ive been running this patchset on my soekris for some time, since > GTOD detects that the TSC counts slowly, calls it insane, and does timing > with the PIT. > > With GTOD, writing a new clocksource driver is easy, enough so I could > do it. > My clocksource patch uses the 27 mhz timer on the Geode CPU. > Once the TSC is de-rated, mine becomes the best clocksource, and GTOD > switches to it. > > All of which is to say .. > new mainline code is coming, should this current rework notion wait, > given that its will all need revisited again later > Clearly yes, since this is going to impact Adeos too. GTOD is going to fiddle with the PIT channels in a way Adeos needs to be aware of, in order for the client RTOS to reuse such timer. Added to the flow of other core changes planned for 2.6.18, this is likely going to be funky. "Find wall. Beat head against same." -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-14 12:29 ` Philippe Gerum @ 2006-06-14 13:07 ` Jan Kiszka 2006-06-14 16:04 ` Jan Kiszka 0 siblings, 1 reply; 27+ messages in thread From: Jan Kiszka @ 2006-06-14 13:07 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai-core [-- Attachment #1: Type: text/plain, Size: 2035 bytes --] Philippe Gerum wrote: > Jim Cromie wrote: >> Philippe Gerum wrote: >> >>> Gilles Chanteperdrix wrote: >>> >>>> Philippe Gerum wrote: >>>> > Redone the check here on a Centrino 1.6Mhz, and still have >>>> roughly x20 > improvement (a bit better actually). I'm using >>>> Debian/sarge gcc 3.3.5. >>>> >>>> I think I remember that Pentium M has a much shorter mull instruction >>>> than other processors of the family. >>>> >>> >>> That would explain. Anyway, as John Stulz put it: >>> "math is hard, lets go shopping!" >>> >> >> Heh. Appropriate that his name (Stultz) comes up here, as his >> generic-time (GTOD) >> patchset looks headed for 2.6.18, bringing with it a full re-working >> of linux timers / timeofday. IN this new world, time is kept on >> free-running counters. >> >> Ive been running this patchset on my soekris for some time, since >> GTOD detects that the TSC counts slowly, calls it insane, and does timing >> with the PIT. >> >> With GTOD, writing a new clocksource driver is easy, enough so I could >> do it. >> My clocksource patch uses the 27 mhz timer on the Geode CPU. >> Once the TSC is de-rated, mine becomes the best clocksource, and GTOD >> switches to it. >> >> All of which is to say .. >> new mainline code is coming, should this current rework notion wait, >> given that its will all need revisited again later >> > > Clearly yes, since this is going to impact Adeos too. GTOD is going to > fiddle with the PIT channels in a way Adeos needs to be aware of, in > order for the client RTOS to reuse such timer. Added to the flow of > other core changes planned for 2.6.18, this is likely going to be funky. > > "Find wall. Beat head against same." > May not be required: the GTOD and clocksource abstractions could provide a clean way to register some virtual, Adeos- or RTOS-provided clock with Linux. And that clock may even lose ticks without Linux losing its system time! So far for the theory, practice may still require walls... Jan [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-14 13:07 ` Jan Kiszka @ 2006-06-14 16:04 ` Jan Kiszka 0 siblings, 0 replies; 27+ messages in thread From: Jan Kiszka @ 2006-06-14 16:04 UTC (permalink / raw) To: Philippe Gerum; +Cc: xenomai-core [-- Attachment #1: Type: text/plain, Size: 2432 bytes --] Jan Kiszka wrote: > Philippe Gerum wrote: >> Jim Cromie wrote: >>> Philippe Gerum wrote: >>> >>>> Gilles Chanteperdrix wrote: >>>> >>>>> Philippe Gerum wrote: >>>>> > Redone the check here on a Centrino 1.6Mhz, and still have >>>>> roughly x20 > improvement (a bit better actually). I'm using >>>>> Debian/sarge gcc 3.3.5. >>>>> >>>>> I think I remember that Pentium M has a much shorter mull instruction >>>>> than other processors of the family. >>>>> >>>> That would explain. Anyway, as John Stulz put it: >>>> "math is hard, lets go shopping!" >>>> >>> Heh. Appropriate that his name (Stultz) comes up here, as his >>> generic-time (GTOD) >>> patchset looks headed for 2.6.18, bringing with it a full re-working >>> of linux timers / timeofday. IN this new world, time is kept on >>> free-running counters. >>> >>> Ive been running this patchset on my soekris for some time, since >>> GTOD detects that the TSC counts slowly, calls it insane, and does timing >>> with the PIT. >>> >>> With GTOD, writing a new clocksource driver is easy, enough so I could >>> do it. >>> My clocksource patch uses the 27 mhz timer on the Geode CPU. >>> Once the TSC is de-rated, mine becomes the best clocksource, and GTOD >>> switches to it. >>> >>> All of which is to say .. >>> new mainline code is coming, should this current rework notion wait, >>> given that its will all need revisited again later >>> >> Clearly yes, since this is going to impact Adeos too. GTOD is going to >> fiddle with the PIT channels in a way Adeos needs to be aware of, in >> order for the client RTOS to reuse such timer. Added to the flow of >> other core changes planned for 2.6.18, this is likely going to be funky. >> >> "Find wall. Beat head against same." >> > > May not be required: the GTOD and clocksource abstractions could provide > a clean way to register some virtual, Adeos- or RTOS-provided clock with > Linux. And that clock may even lose ticks without Linux losing its > system time! So far for the theory, practice may still require walls... > Some refinement: clocksource may either remain TSC or become a Xenomai-provided clock if its handling (PIT...) requires synchronisation. The clockevent, the one thing that triggers timer IRQs, could become a virtual device driven by Xenomai. And GTOD should happily make use of them instead of messing up with shared hardware. Jan [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* [Xenomai-core] Timer optimisations, continued 2006-06-13 17:13 ` Gilles Chanteperdrix 2006-06-13 17:58 ` Philippe Gerum @ 2006-07-25 18:26 ` Jan Kiszka 2006-07-27 8:53 ` Philippe Gerum 1 sibling, 1 reply; 27+ messages in thread From: Jan Kiszka @ 2006-07-25 18:26 UTC (permalink / raw) To: xenomai-core [-- Attachment #1: Type: text/plain, Size: 18489 bytes --] Hi all, to continue the discussion about improving the timer subsystem, specifically with respect to unit conversion overhead, I'm posting here a (fairly long) report of my findings and consideration. First of all I did some benchmarking of the various optimised conversion routines that popped up. I stressed them on the different x86-platforms. The numbers are for 1000 iterations (loop overhead compensated), used compiler was gcc-4.1. Just to recall the actors: xnarch_tsc_to_ns - original accurate 64-bit division for converting TSC ticks in nanoseconds (and vice versa) fast_tsc_to_ns - my scaled-math-based assembler variant, suffering from some inaccuracy for large intervals, still requires normal 64-bit muldiv for the ns-to-TSC return path ns_2_cycles - Philippe's similar version, a bit more inaccurate nodiv_ullimd - Gilles' 64-bit conversion routine, only sometimes varying in the last bit from the original result nodiv_imuldiv - Gilles' 32-bit div-less conversion for small intervals (haven't checked, but I assume it's as accurate as the 64-bit variant in the limited domain) And here are the results (ugly test code available on request): VIA C2, 600 MHz: xnarch_tsc_to_ns: 160680 cycles / 267800 ns fast_tsc_to_ns: 119842 cycles / 199736 ns ns_2_cycles: 69376 cycles / 115626 ns nodiv_ullimd: 179042 cycles / 298403 ns nodiv_imuldiv: 41336 cycles / 68893 ns P-III, 1GHz: xnarch_tsc_to_ns: 108475 cycles / 107935 ns fast_tsc_to_ns: 24127 cycles / 24006 ns ns_2_cycles: 21338 cycles / 21231 ns nodiv_ullimd: 67974 cycles / 67635 ns nodiv_imuldiv: 13269 cycles / 13202 ns P-MMX, 266 MHz: xnarch_tsc_to_ns: 131886 cycles / 495812 ns fast_tsc_to_ns: 47697 cycles / 179312 ns ns_2_cycles: 43627 cycles / 164011 ns nodiv_ullimd: 141915 cycles / 533515 ns nodiv_imuldiv: 44761 cycles / 168274 ns P-M, 1,3GHz: xnarch_tsc_to_ns: 113219 cycles / 87091 ns fast_tsc_to_ns: 26718 cycles / 20552 ns ns_2_cycles: 15024 cycles / 11556 ns nodiv_ullimd: 49620 cycles / 38169 ns nodiv_imuldiv: 17036 cycles / 13104 ns Opteron 275 (32-bit mode), 1,8 GHz: xnarch_tsc_to_ns: 112507 cycles / 62503 ns fast_tsc_to_ns: 21857 cycles / 12142 ns ns_2_cycles: 12545 cycles / 6969 ns nodiv_ullimd: 41175 cycles / 22875 ns nodiv_imuldiv: 7261 cycles / 4033 ns For sure, working with only 32-bit is the fastest variant on all platforms. Other variants do not always perform well or have limited accuracy. Unfortunately, 32-bit conversions cannot be applied on all scenarios, we will see this below. After hacking my fast_tsc_to_ns, my original plan was to switch the internal timer base completely to nanoseconds in the hope to reduce the number of conversions in the timer hot-paths. Luckily I decided to analyse the typical scenarios first before starting the develop any patch. I consider the following 5 scenarios for heavy timer usage. Both TSC and nanoseconds as time base are analysed, also a potential timer_start() variant that accepts absolute timeout values. The pseudo code /should/ be self-explaining. If not do not hesitate to ask. 1. Periodic Timers ================== Start once, run continuously => hot-path is the timer IRQ 1.1 TSC-based ------------- task_set_periodic(start, interval) [rarely] delay = start - get_time() get_time(): tsc -> ns [64-bit] timer_start(delay, interval) delay: ns -> tsc [32-bit candidate] date = get_tsc() + delay interval: ns -> tsc [32-bit candidate] program_timer(date) delay = date - get_tsc() set_hw_timer(delay) -or- task_set_periodic(start, interval) [rarely] timer_start_abs(start, interval) date: ns -> tsc [64-bit] interval: ns -> tsc [32-bit candidate] program_timer(date) delay = date - get_tsc() set_hw_timer(delay) timer_irq() [hot-path] date <= get_tsc()? date = get_tsc() + interval program_timer(date) delay = date - get_tsc() set_hw_timer(delay) 1.2 ns-based ------------ task_set_periodic(start, interval) [rarely] delay = start - get_time() get_time(): tsc -> ns [64-bit] timer_start(delay, interval) date = get_time() + delay get_time(): tsc -> ns [64-bit] program_timer(date) date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) -or- task_set_periodic(start, interval) [rarely] timer_start_abs(start, interval) date = start program_timer(date) date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [hot-path] now = get_time() get_time: tsc -> ns [64-bit] date <= now()? date = now + interval program_timer(date) date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) 1.3 Summary of (only!) the hot-path ----------------------------------- | total | tsc->ns | ns->tsc | possible | conversions | | | 32-bit ns->tsc --------------+-------------+---------+---------+---------------- TSC-based | 0 | 0 | 0 | 0 TSC-based+ABS | 0 | 0 | 0 | 0 ns-based | 2 | 1 | 1 | 0 ns-based+ABS | 2 | 1 | 1 | 0 2. Relative Timers ================== (explicit relative delays) Started often, typically time out => hot-path is timer_start() and the timer IRQ 2.1 TSC-based ------------- task_sleep(delay) [hot-path] timer_start(delay, 0) delay: ns -> tsc [32-bit candidate] date = get_tsc() + delay program_timer(date) delay = date - get_tsc() set_hw_timer(delay) timer_irq() [hot-path] date <= get_tsc()? (programming of succeeding timer intentionally not included) 2.2 ns-based ------------- task_sleep(delay) [hot-path] timer_start(delay, 0) date = get_time() + delay get_time: tsc -> ns [64-bit] program_timer(date) date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [hot-path] now = get_time() get_time: tsc -> ns [64-bit] date <= now? (programming of succeeding timer intentionally not included) 2.3 Summary of the hot-path --------------------------- | total | tsc->ns | ns->tsc | possible | conversions | | | 32-bit ns->tsc --------------+-------------+---------+---------+---------------- TSC-based | 1 | 0 | 1 | 1 ns-based | 3 | 2 | 1 | 0 3. Relative Timeouts ==================== (IPC mechanisms, device operations, etc.) Started often, typically do not fire, often comparably large timeout values that do not make it down to program_timer() before cancellation => hot-path is timer_start() and timer_stop() 3.1 TSC-based ------------- mutex_lock(..., delay) [hot-path] timer_start(delay, 0) delay: ns -> tsc [32-bit candidate] date = get_tsc() + delay program_timer(date) [rarely] delay = date - get_tsc() set_hw_timer(delay) block_on_mutex() timer_stop() program_timer(date) [rarely] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [rarely] date <= get_tsc()? 3.2 ns-based ------------ mutex_lock(..., delay) [hot-path] timer_start(delay, 0) date = get_time() + delay get_time: tsc -> ns [64-bit] program_timer(date) [rarely] date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) block_on_mutex() timer_stop() program_timer(date) [rarely] date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [rarely] now = get_time() get_time: tsc -> ns [64-bit] date <= now? 3.3 Summary of the hot-path --------------------------- | total | tsc->ns | ns->tsc | possible | conversions | | | 32-bit ns->tsc --------------+-------------+---------+---------+---------------- TSC-based | 1 | 0 | 1 | 1 ns-based | 1 | 1 | 0 | 0 4. Absolute Timers ================== (e.g. TDMA slot timing in RTnet) Started often, include time-stamp acquisition and conversion, typically fire => hot-path is get_time(), timer_start(), and the timer IRQ 4.1 TSC-based ------------- date = get_time() + delay [hot-path] get_time: tsc -> ns [64-bit] task_sleep_until(date) [hot-path] delay = date - get_time() get_time: tsc -> ns [64-bit] timer_start(delay, 0) delay: ns -> tsc [32-bit candidate] date = get_tsc() + delay program_timer(date) delay = date - get_tsc() set_hw_timer(delay) -or- task_sleep_until(date) [hot-path] timer_start_abs(date, 0) date: ns -> tsc [64-bit] program_timer(date) delay = date - get_tsc() set_hw_timer(delay) timer_irq() [hot-path] test date <= get_tsc()? 4.2 ns-based ------------ date = get_time() + delay [hot-path] get_time: tsc -> ns [64-bit] task_sleep_until(date) [hot-path] delay = date - get_time() get_time: tsc -> ns [64-bit] timer_start(delay, 0) date = get_time() + delay get_time(): tsc -> ns [64-bit] program_timer(date) date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) -or- task_sleep_until(date) [hot-path] timer_start_abs(date, 0) program_timer(date) date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [hot-path] now = get_time() get_time: tsc -> ns [64-bit] date <= now()? 4.3 Summary of the hot-path --------------------------- | total | tsc->ns | ns->tsc | possible | conversions | | | 32-bit ns->tsc --------------+-------------+---------+---------+---------------- TSC-based | 3 | 2 | 1 | 1 TSC-based+ABS | 2 | 1 | 1 | 0 ns-based | 5 | 4 | 1 | 0 ns-based+ABS | 3 | 2 | 1 | 0 5. Absolute Timeouts ==================== (e.g. POSIX IPC mechanisms) Started often, typically do not fire, include time-stamp acquisition, often comparably large timeout values => hot-path is get_time(), timer_start(), and timer_stop() 5.1 TSC-based ------------- date = get_time() + delay [hot-path] get_time: tsc -> ns [64-bit] sem_timeddown(..., date) [hot-path] delay = date - get_time() get_time: tsc -> ns [64-bit] timer_start(delay, 0) delay: ns -> tsc [32-bit candidate] date = get_tsc() + delay program_timer(date) [rarely] delay = date - get_tsc() set_hw_timer(delay) block_on_sem() timer_stop() program_timer(date) [rarely] delay = date - get_tsc() set_hw_timer(delay) -or- sem_timeddown(..., date) [hot-path] timer_start_abs(date, 0) date: ns -> tsc [64-bit] program_timer(date) [rarely] delay = date - get_tsc() set_hw_timer(delay) block_on_sem() timer_stop() program_timer(date) [rarely] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [rarely] date <= get_tsc()? 5.2 ns-based ------------ date = get_time() + delay [hot-path] get_time: tsc -> ns [64-bit] sem_timeddown(..., date) [hot-path] delay = date - get_time() get_time: tsc -> ns [64-bit] timer_start(delay, 0) date = get_time() + delay get_time(): tsc -> ns [64-bit] program_timer(date) [rarely] date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) block_on_sem() timer_stop() program_timer(date) [rarely] date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) -or- sem_timeddown(..., date) [hot-path] timer_start_abs(date, 0) program_timer(date) [rarely] date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) block_on_sem() timer_stop() program_timer(date) [rarely] date: ns -> tsc [64-bit] delay = date - get_tsc() set_hw_timer(delay) timer_irq() [rarely] now = get_time() get_time: tsc -> ns [64-bit] date <= now()? 5.3 Summary of the hot-path --------------------------- | total | tsc->ns | ns->tsc | possible | conversions | | | 32-bit ns->tsc --------------+-------------+---------+---------+---------------- TSC-based | 3 | 2 | 1 | 1 TSC-based+ABS | 2 | 1 | 1 | 0 ns-based | 3 | 3 | 0 | 0 ns-based+ABS | 1 | 1 | 0 | 0 [Please don't take every detail above for granted. Some bugs may sleep even there. Too many conversions...] To summarise these lengthy results: o ns-based xntimers are nice on first sight, but not on second. Most use-cases (except 5) require less conversions when we keep the abstraction as it is. o Performance should be improvable by combining fast_tsc_to_ns for full 64-bit conversions with nodiv_imuldiv for short relative ns-to-tsc. It should be ok to loose some accuracy wrt to long periods given that TSC are AFAIK not very accurate themselves. Nevertheless, to keep precision on 64-bit ns-to-tsc reverse conversions, those should remain implemented as they are: "if (ns <= ULONG_MAX) nodiv_imuldiv else xnarch_ns_to_tsc" o A further improvement should be achievable for scenarios 4 and 5 by introducing absolute xntimers (more precisely: a flag to differentiate between the mode on xntimer_start). I have an outdated patch for this in my repos, needs re-basing. To verify that we actually improve something with each of the changes above, some kind of fine-grained test suite will be required. The timerbench could be extended to support all 5 scenarios. But does someone have any quick idea how to evaluate the overall performances best? The new per-task statistics code is not accurate enough as it accounts IRQs mostly to the preempted task, not the preempting one. Mm, execution time of some long-running number-crunching Linux task in the background? Looking forward to feedback! Jan PS: Finally, after stabilising the xntimers again, we will see a nice rtdm_timer API as well. But those patches need even more re-basing then... [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] Timer optimisations, continued 2006-07-25 18:26 ` [Xenomai-core] Timer optimisations, continued Jan Kiszka @ 2006-07-27 8:53 ` Philippe Gerum 2006-07-27 12:42 ` Gilles Chanteperdrix 0 siblings, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-07-27 8:53 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core On Tue, 2006-07-25 at 20:26 +0200, Jan Kiszka wrote: <massive snippage> > > To summarise these lengthy results: > > o ns-based xntimers are nice on first sight, but not on second. Most > use-cases (except 5) require less conversions when we keep the > abstraction as it is. > The current approach was a deliberate choice to favour accuracy of timers, at the - reasonably small - expense of not optimizing the "timeout" use case. The net result is that the core timing code is TSC-based, so that no time unit conversion occurs after a timer has been started, except in the case where the hw timer has a different time unit than the TSC used (this said, this last conversion before programmin gthe hw timer would be needed regardless of the time unit maintained by the timing core). > o Performance should be improvable by combining fast_tsc_to_ns for full > 64-bit conversions with nodiv_imuldiv for short relative ns-to-tsc. > It should be ok to loose some accuracy wrt to long periods given that > TSC are AFAIK not very accurate themselves. Nevertheless, to keep > precision on 64-bit ns-to-tsc reverse conversions, those should > remain implemented as they are: > "if (ns <= ULONG_MAX) nodiv_imuldiv else xnarch_ns_to_tsc" > I basically agree with that, including the 64/32 optimization on delay ranges. IOW, we could optimize time conversions in the timing core _locally_ (i.e. nucleus/timer.c exclusively) even at the expense of a small loss of accuracy in the dedicated converters. In any case, we are implicitely talking of the oneshot mode here, and as such, it would be acceptable to trigger an early shot once in a while - i.e. due to the loss of accuracy - that would cause the existing code to restart the timer until it eventually elapses past the expected time, given that this would only occur with large delays. But: we must leave the existing converters as they are in the xnarch layer, keeping the most accurate operations provided there, since a lot of code depends on their accuracy. > o A further improvement should be achievable for scenarios 4 and 5 by > introducing absolute xntimers (more precisely: a flag to > differentiate between the mode on xntimer_start). I have an outdated > patch for this in my repos, needs re-basing. > Grmblm... Well, I would have preferred that we don't add that kind of complexity to the nucleus interface, but I must admit that some important use cases are definitely better served by absolute timespecs, so I would surrender to this requirement, provided the implementation is confined to xnpod_suspend_thread() + xntimer_start(). > To verify that we actually improve something with each of the changes > above, some kind of fine-grained test suite will be required. The > timerbench could be extended to support all 5 scenarios. But does > someone have any quick idea how to evaluate the overall performances > best? The new per-task statistics code is not accurate enough as it > accounts IRQs mostly to the preempted task, not the preempting one. Mm, > execution time of some long-running number-crunching Linux task in the > background? Better use a kernel-based low priority RT task running in the background, limiting the sampling period to a duration that Linux could bear with (maybe running multiple subsequent periods with warmup phases, just to let the penguin breath). The effect of TLB misses would be much lower, and no need to block the Linux IRQs using Xenomai's I-shield. > Looking forward to feedback! > > Jan > > > PS: Finally, after stabilising the xntimers again, we will see a nice > rtdm_timer API as well. But those patches need even more re-basing then... > > _______________________________________________ > Xenomai-core mailing list > Xenomai-core@domain.hid > https://mail.gna.org/listinfo/xenomai-core -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] Timer optimisations, continued 2006-07-27 8:53 ` Philippe Gerum @ 2006-07-27 12:42 ` Gilles Chanteperdrix 2006-07-27 13:19 ` Philippe Gerum 0 siblings, 1 reply; 27+ messages in thread From: Gilles Chanteperdrix @ 2006-07-27 12:42 UTC (permalink / raw) To: rpm; +Cc: Jan Kiszka, xenomai-core Philippe Gerum wrote: > > o A further improvement should be achievable for scenarios 4 and 5 by > > introducing absolute xntimers (more precisely: a flag to > > differentiate between the mode on xntimer_start). I have an outdated > > patch for this in my repos, needs re-basing. > > > > Grmblm... Well, I would have preferred that we don't add that kind of > complexity to the nucleus interface, but I must admit that some > important use cases are definitely better served by absolute timespecs, > so I would surrender to this requirement, provided the implementation is > confined to xnpod_suspend_thread() + xntimer_start(). It would be nice if absolute timeouts were also available when using xnsynch_sleep_on. There are a few use cases in the POSIX skin. -- Gilles Chanteperdrix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] Timer optimisations, continued 2006-07-27 12:42 ` Gilles Chanteperdrix @ 2006-07-27 13:19 ` Philippe Gerum 2006-07-27 13:54 ` Jan Kiszka 0 siblings, 1 reply; 27+ messages in thread From: Philippe Gerum @ 2006-07-27 13:19 UTC (permalink / raw) To: Gilles Chanteperdrix; +Cc: Jan Kiszka, xenomai-core On Thu, 2006-07-27 at 14:42 +0200, Gilles Chanteperdrix wrote: > Philippe Gerum wrote: > > > o A further improvement should be achievable for scenarios 4 and 5 by > > > introducing absolute xntimers (more precisely: a flag to > > > differentiate between the mode on xntimer_start). I have an outdated > > > patch for this in my repos, needs re-basing. > > > > > > > Grmblm... Well, I would have preferred that we don't add that kind of > > complexity to the nucleus interface, but I must admit that some > > important use cases are definitely better served by absolute timespecs, > > so I would surrender to this requirement, provided the implementation is > > confined to xnpod_suspend_thread() + xntimer_start(). > > It would be nice if absolute timeouts were also available when using > xnsynch_sleep_on. There are a few use cases in the POSIX skin. Makes sense, since xnpod_suspend_thread() and xnsynch_sleep_on() are tightly integrated interfaces. > -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] Timer optimisations, continued 2006-07-27 13:19 ` Philippe Gerum @ 2006-07-27 13:54 ` Jan Kiszka 2006-07-27 14:10 ` Philippe Gerum 0 siblings, 1 reply; 27+ messages in thread From: Jan Kiszka @ 2006-07-27 13:54 UTC (permalink / raw) To: rpm; +Cc: xenomai-core [-- Attachment #1: Type: text/plain, Size: 1398 bytes --] Philippe Gerum wrote: > On Thu, 2006-07-27 at 14:42 +0200, Gilles Chanteperdrix wrote: >> Philippe Gerum wrote: >> > > o A further improvement should be achievable for scenarios 4 and 5 by >> > > introducing absolute xntimers (more precisely: a flag to >> > > differentiate between the mode on xntimer_start). I have an outdated >> > > patch for this in my repos, needs re-basing. >> > > >> > >> > Grmblm... Well, I would have preferred that we don't add that kind of >> > complexity to the nucleus interface, but I must admit that some >> > important use cases are definitely better served by absolute timespecs, >> > so I would surrender to this requirement, provided the implementation is >> > confined to xnpod_suspend_thread() + xntimer_start(). >> >> It would be nice if absolute timeouts were also available when using >> xnsynch_sleep_on. There are a few use cases in the POSIX skin. > > Makes sense, since xnpod_suspend_thread() and xnsynch_sleep_on() are > tightly integrated interfaces. > Anyone any idea how to extend both function interfaces best to differentiate absolute/relative timeouts? I guess we need an additional argument to the functions, don't we? I had the weird idea of using the sign bit of the timeout value for this. But the potential side effects of halving the absolute time domain this way scares me. Jan [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 250 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] Timer optimisations, continued 2006-07-27 13:54 ` Jan Kiszka @ 2006-07-27 14:10 ` Philippe Gerum 0 siblings, 0 replies; 27+ messages in thread From: Philippe Gerum @ 2006-07-27 14:10 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core On Thu, 2006-07-27 at 15:54 +0200, Jan Kiszka wrote: > Philippe Gerum wrote: > > On Thu, 2006-07-27 at 14:42 +0200, Gilles Chanteperdrix wrote: > >> Philippe Gerum wrote: > >> > > o A further improvement should be achievable for scenarios 4 and 5 by > >> > > introducing absolute xntimers (more precisely: a flag to > >> > > differentiate between the mode on xntimer_start). I have an outdated > >> > > patch for this in my repos, needs re-basing. > >> > > > >> > > >> > Grmblm... Well, I would have preferred that we don't add that kind of > >> > complexity to the nucleus interface, but I must admit that some > >> > important use cases are definitely better served by absolute timespecs, > >> > so I would surrender to this requirement, provided the implementation is > >> > confined to xnpod_suspend_thread() + xntimer_start(). > >> > >> It would be nice if absolute timeouts were also available when using > >> xnsynch_sleep_on. There are a few use cases in the POSIX skin. > > > > Makes sense, since xnpod_suspend_thread() and xnsynch_sleep_on() are > > tightly integrated interfaces. > > > > Anyone any idea how to extend both function interfaces best to > differentiate absolute/relative timeouts? I guess we need an additional > argument to the functions, don't we? Yes, I'm afraid we do. The other approach that would basically make the timeout a non-scalar value in order to store the rel/abs qualifier would be just overkill. > > I had the weird idea of using the sign bit of the timeout value for > this. But the potential side effects of halving the absolute time domain > this way scares me. > Same here, this looks like a very fragile solution to a general issue. -- Philippe. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 10:51 [Xenomai-core] ns vs. tsc as internal timer base Jan Kiszka 2006-06-13 11:16 ` Philippe Gerum @ 2006-06-13 11:59 ` Gilles Chanteperdrix 2006-06-13 12:00 ` Anders Blomdell 2 siblings, 0 replies; 27+ messages in thread From: Gilles Chanteperdrix @ 2006-06-13 11:59 UTC (permalink / raw) To: Jan Kiszka Jan Kiszka wrote: > Hi, > > between some football half-times of the last days ;), I played a bit > with a hand-optimised xnarch_tsc_to_ns() for x86. Using scaled math, I > achieved between 3 (P-I 133 MHz) to 4 times (P-M 1.3 GHz) faster > conversions than with the current variant. While this optimisation only > saves a few ten nanoseconds on high-end, slow processors can gain > several hundreds of nanos per conversion (my P-133: -600 ns). Some time ago, I did also some experiment on avoiding divisions. I came to a solution that precompute fractions using a real division, and that only use additions, multiplication and shifts for imuldiv and ullimd. I thought there would be no loss in accuracy, but well, sometimes the last bit is wrong. Anyway, here is the code if you want to benchmark it, div96by32 and u64(to|from)u32 are defined in asm-i386/hal.h or asm-generic/hal.h: typedef struct { unsigned long long frac; /* Fractionary part. */ unsigned long integ; /* Integer part. */ } u32frac_t; /* m/d == integ + frac / 2^64 */ void precalc(u32frac_t *const f, const unsigned long m, const unsigned long d) { f->integ = m > d ? m / d :0; f->frac = div96by32(u64fromu32(m % d, 0), 0, d, NULL); } inline unsigned long nodiv_imuldiv(unsigned long op, u32frac_t f) { const unsigned long tmp = (ullmul(op, f.frac >> 32)) >> 32; if(f.integ) return tmp + op * f.integ; return tmp; } #define add64and32(h, l, s) do { \ __asm__ ("addl %2, %1\n\t" \ "adcl $0, %0" \ : "+r"(h), "+r"(l) \ : "r"(s)); \ } while(0) #define add96and64(l0, l1, l2, s0, s1) do { \ __asm__ ("addl %4, %2\n\t" \ "adcl %3, %1\n\t" \ "adcl $0, %0\n\t" \ : "+r"(l0), "+r"(l1), "+r"(l2) \ : "r"(s0), "r"(s1)); \ } while(0) inline unsigned long long mul64by64_high(const unsigned long long op, const unsigned long long m) { /* Compute high 64 bits of multiplication 64 bits x 64 bits. */ unsigned long long t1, t2, t3; u_long oph, opl, mh, ml, t0, t1h, t1l, t2h, t2l, t3h, t3l; u64tou32(op, oph, opl); u64tou32(m, mh, ml); t0 = ullmul(opl, ml) >> 32; t1 = ullmul(oph, ml); u64tou32(t1, t1h, t1l); add64and32(t1h, t1l, t0); t2 = ullmul(opl, mh); u64tou32(t2, t2h, t2l); t3 = ullmul(oph, mh); u64tou32(t3, t3h, t3l); add64and32(t3h, t3l, t2h); add96and64(t3h, t3l, t2l, t1h, t1l); return u64fromu32(t3h, t3l); } inline unsigned long long nodiv_ullimd(const unsigned long long op, const u32frac_t f) { const unsigned long long tmp = mul64by64_high(op, f.frac); if(f.integ) return tmp + op * f.integ; return tmp; } -- Gilles Chanteperdrix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Xenomai-core] ns vs. tsc as internal timer base 2006-06-13 10:51 [Xenomai-core] ns vs. tsc as internal timer base Jan Kiszka 2006-06-13 11:16 ` Philippe Gerum 2006-06-13 11:59 ` [Xenomai-core] ns vs. tsc as internal timer base Gilles Chanteperdrix @ 2006-06-13 12:00 ` Anders Blomdell 2 siblings, 0 replies; 27+ messages in thread From: Anders Blomdell @ 2006-06-13 12:00 UTC (permalink / raw) To: Jan Kiszka; +Cc: xenomai-core Jan Kiszka wrote: > Hi, > > To avoid loosing the optimisation again in ns_to_tsc, I thought about > basing the whole internal timer arithmetics on nanoseconds instead of > TSCs as it is now. Good idea, makes it simpler to adopt to laptop frequency scaling and deep ACPI sleep, i.e. sync Xenomai time to the ACPI timer. /Anders -- Anders Blomdell Email: anders.blomdell@domain.hid Department of Automatic Control Lund University Phone: +46 46 222 4625 P.O. Box 118 Fax: +46 46 138118 SE-221 00 Lund, Sweden ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2006-07-27 14:10 UTC | newest] Thread overview: 27+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-06-13 10:51 [Xenomai-core] ns vs. tsc as internal timer base Jan Kiszka 2006-06-13 11:16 ` Philippe Gerum 2006-06-13 11:56 ` Jan Kiszka 2006-06-13 12:31 ` Philippe Gerum 2006-06-13 13:07 ` Gilles Chanteperdrix 2006-06-13 13:28 ` Philippe Gerum 2006-06-13 13:34 ` Gilles Chanteperdrix 2006-06-13 13:45 ` Philippe Gerum 2006-06-13 13:33 ` Jan Kiszka 2006-06-13 13:51 ` Philippe Gerum 2006-06-13 16:19 ` Jan Kiszka 2006-06-13 16:29 ` Gilles Chanteperdrix 2006-06-13 17:04 ` Philippe Gerum 2006-06-13 17:13 ` Gilles Chanteperdrix 2006-06-13 17:58 ` Philippe Gerum 2006-06-14 9:25 ` Jim Cromie 2006-06-14 12:29 ` Philippe Gerum 2006-06-14 13:07 ` Jan Kiszka 2006-06-14 16:04 ` Jan Kiszka 2006-07-25 18:26 ` [Xenomai-core] Timer optimisations, continued Jan Kiszka 2006-07-27 8:53 ` Philippe Gerum 2006-07-27 12:42 ` Gilles Chanteperdrix 2006-07-27 13:19 ` Philippe Gerum 2006-07-27 13:54 ` Jan Kiszka 2006-07-27 14:10 ` Philippe Gerum 2006-06-13 11:59 ` [Xenomai-core] ns vs. tsc as internal timer base Gilles Chanteperdrix 2006-06-13 12:00 ` Anders Blomdell
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.