View mode: basic / threaded / horizontal-split · Log in · Help
January 07, 2012
Runtime version statement
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 :)
January 07, 2012
Re: Runtime version statement
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)
January 07, 2012
Re: Runtime version statement
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.
January 10, 2012
Re: Runtime version statement
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);
January 10, 2012
Re: Runtime version statement
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.
January 10, 2012
Re: Runtime version statement
> 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.
January 10, 2012
Re: Runtime version statement
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()
>> {
>>    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)

This.

If you want CPU detection at runtime, you need to write your own
assembly or use core.cpuid.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
January 10, 2012
Re: Runtime version statement
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';
January 11, 2012
Re: Runtime version statement
You could make use of shared library filters where
you link against a native implementation. During installation
you can then provide specialized implementations.
Top | Discussion index | About this forum | D home