www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Runtime version statement

reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
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
next sibling parent Manu <turkeyman gmail.com> writes:
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
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On 8 January 2012 00:31, Manu <turkeyman gmail.com> wrote:

 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)
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.
Jan 07 2012
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
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
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
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 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);
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.
Jan 10 2012
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
 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
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
On 7 January 2012 22:31, Manu <turkeyman gmail.com> wrote:
 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()
 {
 =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=
e
 calling main(). Then it modifies the function code to make it execute on=
ly
 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.cp=
uid.
 Code modification mechanism is up to implementation. One that come to my
 mind is inserting unconditional jumps by the compiler then and fixing th=
em
 up before calling main().

 Additional advantage is possibility to generate executables for particul=
ar
 environments. This may help reduce execucutable size when targeting spec=
ific
 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=
y.
 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
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
On 10 January 2012 09:42, Martin Nowak <dawg dawgfoto.de> wrote:
 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.
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';
Jan 10 2012
prev sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
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