digitalmars.D - Runtime version statement
- Piotr Szturmaj (42/42) Jan 07 2012 The idea is to make versions of code that are environment dependent and
- Manu (5/46) Jan 07 2012 ... you could just use if() ?
- Manu (7/63) Jan 07 2012 Sorry, I only half read your post >_<
- Martin Nowak (41/83) Jan 09 2012 Because it could only fix non-inlined code you
- Manu (4/96) Jan 10 2012 Function pointers are super-slow on some architectures. I don't think it...
- Martin Nowak (4/8) Jan 10 2012 If you're working on very specific platforms you can likely determine
- Iain Buclaw (15/71) Jan 10 2012 ly
- Iain Buclaw (11/18) Jan 10 2012 I did have GDC hooked up to the C pre-processor macros, which defined
- Martin Nowak (3/3) Jan 11 2012 You could make use of shared library filters where
The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies. Examples of such versions may be: * supported SIMD CPU extensions MMX, SSE, SSE2, etc. * AMD vs Intel CPU, to use instructions that are not available on both * different OS versions (XP/Vista/7, Linux kernel versions) Why that instead of current if statement? * some additional speed, avoids multiple checks in frequent operations * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time Code example: void main() { version(rt_SSE4) { ... } else version(rt_SSE2) { ... } else { // portable code } } In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match. Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid. Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main(). Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided. Just thinking loud :)
Jan 07 2012
On 7 January 2012 22:44, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies. Examples of such versions may be: * supported SIMD CPU extensions MMX, SSE, SSE2, etc. * AMD vs Intel CPU, to use instructions that are not available on both * different OS versions (XP/Vista/7, Linux kernel versions) Why that instead of current if statement? * some additional speed, avoids multiple checks in frequent operations * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time Code example: void main() { version(rt_SSE4) { ... } else version(rt_SSE2) { ... } else { // portable code } } In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match. Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid. Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main(). Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided. Just thinking loud :)... you could just use if() ? Perhaps detection of these features could be added to the standard library. But I have a feeling it already IS actually (core.cpuid, something I am extremely cynical of)
Jan 07 2012
On 8 January 2012 00:31, Manu <turkeyman gmail.com> wrote:On 7 January 2012 22:44, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Sorry, I only half read your post >_< Many(/most?) systems won't let you write to code memory, so using self modifying code in this way this may be a problem... Additionally, many modern systems use encrypted code memory, so self modifying code is impossible on these systems. But it's an interesting idea, which I have thought about myself too on occasion.The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies. Examples of such versions may be: * supported SIMD CPU extensions MMX, SSE, SSE2, etc. * AMD vs Intel CPU, to use instructions that are not available on both * different OS versions (XP/Vista/7, Linux kernel versions) Why that instead of current if statement? * some additional speed, avoids multiple checks in frequent operations * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time Code example: void main() { version(rt_SSE4) { ... } else version(rt_SSE2) { ... } else { // portable code } } In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match. Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid. Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main(). Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided. Just thinking loud :)... you could just use if() ? Perhaps detection of these features could be added to the standard library. But I have a feeling it already IS actually (core.cpuid, something I am extremely cynical of)
Jan 07 2012
Am 07.01.2012, 21:44 Uhr, schrieb Piotr Szturmaj <bncrbme jadamspam.pl>:The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies. Examples of such versions may be: * supported SIMD CPU extensions MMX, SSE, SSE2, etc. * AMD vs Intel CPU, to use instructions that are not available on both * different OS versions (XP/Vista/7, Linux kernel versions) Why that instead of current if statement? * some additional speed, avoids multiple checks in frequent operations * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time Code example: void main() { version(rt_SSE4) { ... } else version(rt_SSE2) { ... } else { // portable code } } In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match. Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid. Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main(). Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided. Just thinking loud :)Because it could only fix non-inlined code you can as well use lazy binding using thunks. // use static to make it re-entrant safe __gshared R function(Args) doSomething = &setThunk; R setThunk(Args args) { if (sse4) { doSomeThing = &sse4Impl; } else if (sse2) { doSomeThing = &sse2Impl; } else { doSomeThing = &nativeImpl; } return doSomeThing(args); } Much simpler, thread safe and more efficient. __gshared SSE2 = tuple("foo", &sse2Foo, "bar", &sse2Bar); __gshared SSE4 = tuple("foo", &sse4Foo, "bar", &sse4Bar); __gshared typeof(SSE2)* _impl; shared static this() { if (sse4) { _impl = &SSE4; } else if (sse2) { _impl = &SSE2; } else { _impl = &Native; } } _impl.foo(args);
Jan 09 2012
On 10 January 2012 08:09, Martin Nowak <dawg dawgfoto.de> wrote:Am 07.01.2012, 21:44 Uhr, schrieb Piotr Szturmaj <bncrbme jadamspam.pl>: The idea is to make versions of code that are environment dependent andFunction pointers are super-slow on some architectures. I don't think it's a particularly good solution unless the functions you're calling do a lot of work.never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies. Examples of such versions may be: * supported SIMD CPU extensions MMX, SSE, SSE2, etc. * AMD vs Intel CPU, to use instructions that are not available on both * different OS versions (XP/Vista/7, Linux kernel versions) Why that instead of current if statement? * some additional speed, avoids multiple checks in frequent operations * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time Code example: void main() { version(rt_SSE4) { ... } else version(rt_SSE2) { ... } else { // portable code } } In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match. Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid. Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main(). Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided. Just thinking loud :)Because it could only fix non-inlined code you can as well use lazy binding using thunks. // use static to make it re-entrant safe __gshared R function(Args) doSomething = &setThunk; R setThunk(Args args) { if (sse4) { doSomeThing = &sse4Impl; } else if (sse2) { doSomeThing = &sse2Impl; } else { doSomeThing = &nativeImpl; } return doSomeThing(args); } Much simpler, thread safe and more efficient. __gshared SSE2 = tuple("foo", &sse2Foo, "bar", &sse2Bar); __gshared SSE4 = tuple("foo", &sse4Foo, "bar", &sse4Bar); __gshared typeof(SSE2)* _impl; shared static this() { if (sse4) { _impl = &SSE4; } else if (sse2) { _impl = &SSE2; } else { _impl = &Native; } } _impl.foo(args);
Jan 10 2012
Function pointers are super-slow on some architectures. I don't think it's a particularly good solution unless the functions you're calling do a lot of work.If you're working on very specific platforms you can likely determine such things at compile time. Alternative approaches are distributing multiple executables or using template parameterization of whole engines.
Jan 10 2012
On 7 January 2012 22:31, Manu <turkeyman gmail.com> wrote:On 7 January 2012 22:44, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:eThe idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies. Examples of such versions may be: * supported SIMD CPU extensions MMX, SSE, SSE2, etc. * AMD vs Intel CPU, to use instructions that are not available on both * different OS versions (XP/Vista/7, Linux kernel versions) Why that instead of current if statement? * some additional speed, avoids multiple checks in frequent operations * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time Code example: void main() { =A0 =A0version(rt_SSE4) =A0 =A0{ =A0 =A0 =A0 =A0... =A0 =A0} =A0 =A0else version(rt_SSE2) =A0 =A0{ =A0 =A0 =A0 =A0... =A0 =A0} =A0 =A0else =A0 =A0{ =A0 =A0 =A0 =A0// portable code =A0 =A0} } In this example program checks the supported extensions only once, befor=lycalling main(). Then it modifies the function code to make it execute on=.versions that match. Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them)=uid.SIMD extensions would preferably be set by druntime with help of core.cp=emCode modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing th=arup before calling main(). Additional advantage is possibility to generate executables for particul=ificenvironments. This may help reduce execucutable size when targeting spec=y.CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided. Just thinking loud :)... you could just use if() ? Perhaps detection of these features could be added to the standard librar=But I have a feeling it already IS actually (core.cpuid, something I am extremely cynical of)This. If you want CPU detection at runtime, you need to write your own assembly or use core.cpuid. --=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0';
Jan 10 2012
On 10 January 2012 09:42, Martin Nowak <dawg dawgfoto.de> wrote:I did have GDC hooked up to the C pre-processor macros, which defined a lot of target-specific identifiers (GNU_SSE, GNU_SSE2, etc) depending on the default target flags, and what extra target flags you passed to the compiler - but was dropped because of growing number of stub dependencies it incurred, and the fact that most macros were about as useful as marmite sundae. I would be certainly up for addressing this in a pragmatic way though. -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';Function pointers are super-slow on some architectures. I don't think it's a particularly good solution unless the functions you're calling do a lot of work.If you're working on very specific platforms you can likely determine such things at compile time. Alternative approaches are distributing multiple executables or using template parameterization of whole engines.
Jan 10 2012
You could make use of shared library filters where you link against a native implementation. During installation you can then provide specialized implementations.
Jan 11 2012