POV-Ray : Newsgroups : povray.unofficial.patches : [announce] JITC: Really fast POVRay FPU Server Time
8 Oct 2026 23:23:34 EDT (-0400)
  [announce] JITC: Really fast POVRay FPU (Message 1 to 23 of 23)  
From: Wolfgang Wieser
Subject: [announce] JITC: Really fast POVRay FPU
Date: 3 Aug 2004 18:11:15
Message: <41100d82@news.povray.org>
Hello all...

the last two days, I wrote a patch for UNIX POVRay-3.6. to speed 
up user-functions as used e.g. in isosurfaces. 

Instead of interpreting the functions as done by the POV VM, this 
patch does just-in-time compilation of the function using the system 
compiler -- all that on-the-fly completely transparent for the user. 

Result: Some scenes trace 4 times as fast!

Details: 
http://www.cip.physik.uni-muenchen.de/~wwieser/render/povray/patches/jitc-patch/

Disclaimer: 
- The patch is Linux-specific. Probably Minor efford porting to other UNICes 
  or MaxOS X. Major efford necessary for Windows. 
- The patch is _highly_experimental_. It works fine for me but I expect that 
  there are functions for which it fails. In this case, please tell me. 
- The patch is not cleanly designed in several points. Unfortunately, during 
  coding some problems showed up which I had not thought of before. 

Any comments welcome. 
Wolfgang


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 3 Aug 2004 18:14:47
Message: <41100e57@news.povray.org>
In article <41100d82@news.povray.org> , Wolfgang Wieser 
<wwi### [at] nospamgmxde>  wrote:

> - The patch is Linux-specific. Probably Minor efford porting to other UNICes
>   or MaxOS X. Major efford necessary for Windows. 

You are aware that the official POV-Ray for Mac OS does include a
just-in-time compiler, aren't you?

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Nicolas Calimet
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 3 Aug 2004 18:27:35
Message: <41101157$1@news.povray.org>
> You are aware that the official POV-Ray for Mac OS does include a
> just-in-time compiler, aren't you?

	It's very likely Wolfgang never tried the Mac OS version  ;-)

	Sounds like a cool patch anyway !

	- NC


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 3 Aug 2004 18:39:20
Message: <41101418@news.povray.org>
In article <41101157$1@news.povray.org> , Nicolas Calimet 
<pov### [at] freefr>  wrote:

>> You are aware that the official POV-Ray for Mac OS does include a
>> just-in-time compiler, aren't you?
>
>  It's very likely Wolfgang never tried the Mac OS version  ;-)

That is true, but using the core code SYS_FUNCTIONS macro family would have
made integration of a JIT compiler possible without hacking fnpovfpu.cpp.
In particular because they are documented to exist exactly for that purpose.
Would at least have made the whole implementation easier...

>  Sounds like a cool patch anyway !

Certainly!  On the other hand, calling gcc is overkill to make JIT
compilation possible :-)

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Eli
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 3 Aug 2004 19:12:52
Message: <41101bf4$1@news.povray.org>
haven't tried it myself, but........ wow!


Post a reply to this message

From: Eli
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 3 Aug 2004 19:14:53
Message: <41101c6d@news.povray.org>
otherwise encorporate the whole gcc thing in pov-ray. probably impossible
because of licensing issues.


Post a reply to this message

From: Christoph Hormann
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 01:40:01
Message: <cepsnj$260$1@chho.imagico.de>
Wolfgang Wieser wrote:
> Hello all...
> 
> the last two days, I wrote a patch for UNIX POVRay-3.6. to speed 
> up user-functions as used e.g. in isosurfaces. 
> 
> Instead of interpreting the functions as done by the POV VM, this 
> patch does just-in-time compilation of the function using the system 
> compiler -- all that on-the-fly completely transparent for the user. 
> 

I think the work probably would have been better invested in 
implementing an internal JIT compiler using the existing hooks as 
Thorsten explained.  This would work on all x86 systems (and for Mac an 
implementation already exists).

BTW your page does not say which optimizations you used for compiling 
the patched version.  To me it seems quite unlikely that you always get 
a speedup, there is also some overhead introduced by calling an external 
library.

None the less an interesting idea of course.

Christoph

-- 
POV-Ray tutorials, include files, Sim-POV,
HCR-Edit and more: http://www.tu-bs.de/~y0013390/
Last updated 06 Jul. 2004 _____./\/^>_*_<^\/\.______


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 05:29:29
Message: <4110ac78@news.povray.org>
Christoph Hormann wrote:
> I think the work probably would have been better invested in
> implementing an internal JIT compiler using the existing hooks as
> Thorsten explained.  This would work on all x86 systems (and for Mac an
> implementation already exists).
> 
Sounded interesting. I'll have a look at that. 
Why didn't anybody put that on a publically available todo list? ;) 

> BTW your page does not say which optimizations you used for compiling
> the patched version. 
>
Well, this actually does not matter much. As pointed out on my home page, 
I used the same compiler flags for the patched and the unpatched version 
to make sure that the timings can be compared. And of course, I used the 
best ones I know. 
-O2 -ffast-math -march=athlon-xp -Wno-multichar -finline-functions 
-funit-at-a-time -fno-rtti -mfpmath=387

> To me it seems quite unlikely that you always get 
> a speedup, there is also some overhead introduced by calling an external
> library.
> 
This is correct. An external no-op function called via a pointer takes 
about 10 times as long as an internal no-op function. 
No-op function means: 
  int foo(int x)  {  return(x);  }

But we should not forget that the huge swith-case construct in the main VM 
takes some time, too. And this switch is effectively eliminated by JITC. 

Wolfgang


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 05:33:53
Message: <4110ad81@news.povray.org>
Thorsten Froehlich wrote:

> In article <41100d82@news.povray.org> , Wolfgang Wieser
> <wwi### [at] nospamgmxde>  wrote:
> 
>> - The patch is Linux-specific. Probably Minor efford porting to other
>> UNICes or MaxOS X. Major efford necessary for Windows.
> 
> You are aware that the official POV-Ray for Mac OS does include a
> just-in-time compiler, aren't you?
> 
Actually, I was not aware of that! I'll have a look. 
Thanks for the hint. 

Wolfgang


Post a reply to this message

From: ABX
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 05:41:49
Message: <7lb1h0pgvjkebk6e6ofo9a8hvdt5b07nt1@4ax.com>
On Wed, 04 Aug 2004 11:28:22 +0200, Wolfgang Wieser <wwi### [at] nospamgmxde>
wrote:
> Christoph Hormann wrote:
> > I think the work probably would have been better invested in
> > implementing an internal JIT compiler using the existing hooks as
> > Thorsten explained.  This would work on all x86 systems (and for Mac an
> > implementation already exists).
> 
> Sounded interesting. I'll have a look at that. 
> Why didn't anybody put that on a publically available todo list? ;) 

I have considered this task for the future versions of MegaPOV thought I would
be veeeeery happy if you could be faster :-)

ABX


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 05:48:20
Message: <4110b0e3@news.povray.org>
Thorsten Froehlich wrote:

> In article <41101157$1@news.povray.org> , Nicolas Calimet
> <pov### [at] freefr>  wrote:
> 
>>> You are aware that the official POV-Ray for Mac OS does include a
>>> just-in-time compiler, aren't you?
>>
>>  It's very likely Wolfgang never tried the Mac OS version  ;-)
> 
> That is true, but using the core code SYS_FUNCTIONS macro family would
> have made integration of a JIT compiler possible without hacking
> fnpovfpu.cpp. In particular because they are documented to exist exactly
> for that purpose. 
>
Well, "they are documented to..." is little exaggeration. 
All I have found in the sources about these macros were a couple 
of lines which described just what I already knew from reading the 
code and one "cryptic" allusion that it can be used somehow to allow 
JIT compilation. And that sounded to me like "we could some time 
use that for JIT if we finally find the time to do so"...

> Would at least have made the whole implementation 
> easier...
> 
Okay... could somebody please make the POVRay-for-MacOS 
source code available in a file format which I can read?

Or, alternatively, point me to a _working_ .sit unpacker for Linux. 

The last time I was using the stuffit expander, I sweared to ban it from 
my HD: First, I unpacked the archive which took quite long for just 
some hundret kb. The binaries were okay but I saw that it messed up 
the newlines in the text. So, I un-packed it again with changed flags 
which really took _ages_ now and finally the text files were okay but 
the binaries were corrupt. Oh dear...

> Certainly!  On the other hand, calling gcc is overkill to make JIT
> compilation possible :-)
> 
I wonder how the Mac version does it...

Wolfgang


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 05:59:25
Message: <4110b37c@news.povray.org>
ABX wrote:

> On Wed, 04 Aug 2004 11:28:22 +0200, Wolfgang Wieser
> <wwi### [at] nospamgmxde> wrote:
>> Christoph Hormann wrote:
>> > I think the work probably would have been better invested in
>> > implementing an internal JIT compiler using the existing hooks as
>> > Thorsten explained.  This would work on all x86 systems (and for Mac an
>> > implementation already exists).
>> 
>> Sounded interesting. I'll have a look at that.
>> Why didn't anybody put that on a publically available todo list? ;)
> 
> I have considered this task for the future versions of MegaPOV thought I
> would be veeeeery happy if you could be faster :-)
> 
IMO, in the present stage, this patch is not suitable for inclusion into 
MegaPOV. Need to get rid of some unclean "hacks" first. 

Or, maybe better, use the existing SYS_ macros if I manage to figure out 
how to use them. 

BTW, will the features from MLPov be included in the next MegaPOV version?

Wolfgang


Post a reply to this message

From: ABX
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 06:04:07
Message: <pqc1h0h2j6naajeiafc1btvvck2vfpl9pc@4ax.com>
On Wed, 04 Aug 2004 11:58:19 +0200, Wolfgang Wieser <wwi### [at] nospamgmxde>
wrote:
> BTW, will the features from MLPov be included in the next MegaPOV version?

Well... we try to be trendy ;-)

ABX


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 06:26:41
Message: <4110b9e1@news.povray.org>
In article <4110b0e3@news.povray.org> , Wolfgang Wieser 
<wwi### [at] nospamgmxde>  wrote:

> Or, alternatively, point me to a _working_ .sit unpacker for Linux.

<http://www.stuffit.com/cgi-bin/stuffit_loginpage.cgi?stuffitunix>

> The last time I was using the stuffit expander, I sweared to ban it from
> my HD: First, I unpacked the archive which took quite long for just
> some hundret kb. The binaries were okay but I saw that it messed up
> the newlines in the text. So, I un-packed it again with changed flags
> which really took _ages_ now and finally the text files were okay but
> the binaries were corrupt. Oh dear...

Yes, the Windows version used to come with a Mac configuration as default.
Not very useful to get Mac line endings on Windows...

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 14:27:53
Message: <41112aa8@news.povray.org>
Christoph Hormann wrote:
> I think the work probably would have been better invested in
> implementing an internal JIT compiler using the existing hooks as
> Thorsten explained.  This would work on all x86 systems (and for Mac an
> implementation already exists).
> 
Well, I had a look at the PPC JIT Compiler in the Mac version. If I 
understand it correctly, then it is actually assembling the binary code for 
the PPC in memory and then executing it by jumping into that created 
code. 

After thinking about it, I found 2 reasons which can keep me from 
doing something like that for i386 architecture: 

(1) When I saw the POV VM instruction set it immediately reminded me 
  somehow on the PPC instruction set or a similar RISC instruction set 
  with a number of general-purpose registers etc. (I do not know the PPC 
  instructions in detail but this opinion was based on the feeling I had 
  of it from reading the computer magazines and from my experiences with 
  other RISCs.) 
  So, compiling this code into PPC code turns out to be pretty
  straight-forward. In contrast, the i387 does not seem to have  
  these general purpose registers but instead it uses a register stack with 
  IMO 8 registers and there is a top-of-stack pointer and so on. 
  Furthermore, I am by far no expert in i386/7 assembly and I do not want 
  to hack tons of error-prone code to perform correct translation of 
  POV-VM-ASM into i387-ASM. [r0 should be top of stack...]

(2) GCC does a decent work in optimizing. The POV VM compiler produces 
  assembly which IMO has plenty of (seemingly?) pointless register moves. 
  (Don't understand me wrong, Thorsten: Good register allocation is a really 
  tough job.) Take for example this part of the paramflower on my homepage. 
------------------------
        r0 = sqrt(r0);
        r5 = r5 * r0;
        r0 = r5;
        r5 = r6;  <-- completely useless
        r5 = r0;  <-- useless as well
        r0 = r2;
        r0 = sqrt(r0);
        r5 = r5 + r0;
        r6 = r5;
        r0 = POVFPU_Consts[k];
        r5 = r0;  <-- (skip)
        r7 = r5;  <-- why not r7=r0
        r0 = r2;  <-- (skip)
        r5 = r0;  <-- why not r5=r2
        r0 = r5;  <-- hmm?!
        r5 = r5 * r0;
        r5 = r5 * r0;
        r0 = r5;
        r5 = r7;
------------------------
  Compiling this assembly directly into i387 code would probably not give 
  as good runtime performance as asking GCC would. 
  And I do not want to implement an optimizer especially since there is 
  really little chance to get better than GCC if we're only 1 or 2 people...

Maybe it would be easier to translate the POV-VM-ASM into SSE2 instructions. 
But 2 reasons suggest against that: 
(1) Not yet widely available. 
(2) My box only has SSE1 and hence I could not test it. 

Wolfgang


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 4 Aug 2004 16:28:45
Message: <411146fd@news.povray.org>
In article <41112aa8@news.povray.org> , Wolfgang Wieser 
<wwi### [at] nospamgmxde>  wrote:

> Well, I had a look at the PPC JIT Compiler in the Mac version. If I
> understand it correctly, then it is actually assembling the binary code for
> the PPC in memory and then executing it by jumping into that created
> code.

Yes, that is what it does.

> After thinking about it, I found 2 reasons which can keep me from
> doing something like that for i386 architecture:
>
> (1) When I saw the POV VM instruction set it immediately reminded me
>   somehow on the PPC instruction set or a similar RISC instruction set
>   with a number of general-purpose registers etc. (I do not know the PPC
>   instructions in detail but this opinion was based on the feeling I had
>   of it from reading the computer magazines and from my experiences with
>   other RISCs.)
>   So, compiling this code into PPC code turns out to be pretty
>   straight-forward. In contrast, the i387 does not seem to have
>   these general purpose registers but instead it uses a register stack with
>   IMO 8 registers and there is a top-of-stack pointer and so on.
>   Furthermore, I am by far no expert in i386/7 assembly and I do not want
>   to hack tons of error-prone code to perform correct translation of
>   POV-VM-ASM into i387-ASM. [r0 should be top of stack...]

Well, it would fit into the eight available stack places.  It is not as
trivial as doing it with (at least) eight real registers.

> (2) GCC does a decent work in optimizing. The POV VM compiler produces
>   assembly which IMO has plenty of (seemingly?) pointless register moves.

Yes, it does generate plenty of them, which is an artifact of the the direct
compiling from an expression tree into the final instruction set without
intermediate code.

The good thing is that most of these redundant moves can be removed without
too much work using peephole optimisation.  However, it turns out that this
produces hardly any performance gain (for neither VM nor JIT code) but does
make the compiling/assembling much more complicated.  What you get is below
the measurement error - about two percent raw function performance, which
translates into at most 0.5% (18 seconds per hour) speed improvement in a
heavy isosurface-using scene.

>   Compiling this assembly directly into i387 code would probably not give
>   as good runtime performance as asking GCC would.
>   And I do not want to implement an optimizer especially since there is
>   really little chance to get better than GCC if we're only 1 or 2 people...

The trick is that having the code inline reduces call overhead, which
accounts for about 10% to 15% for the average isosurface function.  Thus,
while you perhaps gain 10% function speed by using gcc (thus 2.5% for the
scene), the call overhead has to be really low to make a difference.  To
reach this with dynamic linking is not as easy as with truly inline compiled
code.  So most likely to total difference is close to zero.

The main reason for this is that unlike integer instructions, changing
floating-point operation order tends to also change precision, which in turn
will quickly result in the compiled representation not being equivalent.  As
the basic principle of compiler construction is to generate equivalent code,
compilers either perform very few optimisations at all, or, like newer
compilers do, allow disabling the strict equivalency requirement for
floating-point operations.

The neat thing is that with isosurfaces precision in the range compilers
have to preserve is only of secondary importance.  Thus, the function
compiler does already perform many of the possible optimisations, and thus
when compiling all that is left are relatively few storage instructions that
can be optimized away.  As I already pointed out, measuring (on Macs with VM
and JIT compiler) revealed that those hardly reduce performance.

> Maybe it would be easier to translate the POV-VM-ASM into SSE2 instructions.

Yes, that would be much easier than targeting a i387-style FPU.

> But 2 reasons suggest against that:
> (1) Not yet widely available.

Well, every processor sold at Aldi today offers it, doesn't it? ;-)

> (2) My box only has SSE1 and hence I could not test it.

I can see how this would be a problem...

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 6 Aug 2004 12:34:33
Message: <4113b318@news.povray.org>
Thorsten Froehlich wrote:
> Well, it would fit into the eight available stack places.  It is not as
> trivial as doing it with (at least) eight real registers.
> 
Yes. Especially since there are also some restrictions -- e.g. several 
functions can only be performed on the top-of-stack element. 
It's like the POV VM e.g calling maths functions only on r0 (IIRC). 

> The good thing is that most of these redundant moves can be removed
> without too much work using peephole optimisation.  
>
Correct. After having sent the last posting, I played with the idea 
of actually implementing a peephole optimization step...

> However, it turns out that 
> this produces hardly any performance gain (for neither VM nor JIT code)
>
...but I see that you already tied. 
(Good that I did yet not begin with it.)

> but does
> make the compiling/assembling much more complicated.  What you get is
> below the measurement error - about two percent raw function performance,
> which translates into at most 0.5% (18 seconds per hour) speed improvement
> in a heavy isosurface-using scene.
> 
Which clearly is not worth the efford. 

> The trick is that having the code inline reduces call overhead, which
> accounts for about 10% to 15% for the average isosurface function.  
>
This is correct. Actually, it seems the dynamically linked function call 
overhead is the only disadvantage of my approach concerning performance. 
I actually don't know exactly what the CPU cycles get spent on: 

  (*int_func)(bar);   // <-- internal function
  (*ext_func)(bar);  // <-- external function (dynamically linked)

In C code it looks completely identical but the second one has 
at least 10 times more call overhead. 

> Thus, 
> while you perhaps gain 10% function speed by using gcc (thus 2.5% for the
> scene), the call overhead has to be really low to make a difference.  To
> reach this with dynamic linking is not as easy as with truly inline
> compiled
> code.  So most likely to total difference is close to zero.
> 
Well, probably it's more like that: The more complex a single function, 
the more you gain. For trivial functions, the "gain" may be negative 
(i.e. loss). 

> The main reason for this is that unlike integer instructions, changing
> floating-point operation order tends to also change precision, which in
> turn
> will quickly result in the compiled representation not being equivalent. 
>
Well, since the i386 internally has 80bit FP registers, the accuracy 
of the compiled version can be expected to be at least as good as 
that of the interpreted version. But of course that does not guarantee 
equivalent images. OTOH, all that numerics is more or less a 
trade-off between accuracy and runtime. And scenes should not 
depend on the last couple of bits anyways because they then would 
look completely differently when different compilers or different 
architectures are used. - You already mentioned sth similar further down. 

> As the basic principle of compiler construction is to generate equivalent
> code, compilers either perform very few optimisations at all, or, like
> newer compilers do, allow disabling the strict equivalency requirement for
> floating-point operations.
> 
I'm not sure what GCC really does. I'm compiling with -ffast-math which 
allows some IEEE violations but I'm not sure if it does lots of "dangerous" 
things. But at least I verified that the register moves are optimized 
away. 

>> But 2 reasons suggest against that [SSE2]:
>> (1) Not yet widely available.
> 
> Well, every processor sold at Aldi today offers it, doesn't it? ;-)
> 
IMHO it depends on if they are currently selling AthlonXP or PentiumIV 
CPUs... [At least my AthlonXP-1.47GHz does not have SSE2.]

Wolfgang


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 7 Aug 2004 06:18:49
Message: <4114ac88@news.povray.org>
Wolfgang Wieser wrote:
>> The trick is that having the code inline reduces call overhead, which
>> accounts for about 10% to 15% for the average isosurface function.
>>
> This is correct. Actually, it seems the dynamically linked function call
> overhead is the only disadvantage of my approach concerning performance.
> I actually don't know exactly what the CPU cycles get spent on:
> 
>   (*int_func)(bar);   // <-- internal function
>   (*ext_func)(bar);  // <-- external function (dynamically linked)
> 
> In C code it looks completely identical but the second one has
> at least 10 times more call overhead.
> 
This is wrong. I tricked myself: In the above program, the int_func was 
not a pointer to a function but the function itself. 

More measurements show that the overhead is NOT due to 
external shared object "linkage" but due to the function being called via 
a function pointer - not depending on whether the function is in the 
primary code or in a shared object. 

Wolfgang


Post a reply to this message

From: Nicolas Calimet
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 8 Aug 2004 10:57:00
Message: <41163f3c$1@news.povray.org>
> More measurements show that the overhead is NOT due to 
> external shared object "linkage" but due to the function being called via 
> a function pointer - not depending on whether the function is in the 
> primary code or in a shared object. 

	Interesting.  But also surprising (to me).
	Could you explain why it takes an order of magnitude longer to
jump to a function via a pointer as compared to a direct reference ?
(note: I'm not very knowledgeable in low-level programming, just a
tiny idea of some assembly instructions).

	- NC


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 8 Aug 2004 11:13:09
Message: <41164305@news.povray.org>
In article <41163f3c$1@news.povray.org> , Nicolas Calimet 
<pov### [at] freefr>  wrote:

>  Interesting.  But also surprising (to me).
>  Could you explain why it takes an order of magnitude longer to
> jump to a function via a pointer as compared to a direct reference ?
> (note: I'm not very knowledgeable in low-level programming, just a
> tiny idea of some assembly instructions).

It should not at all.

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 8 Aug 2004 13:51:21
Message: <41166817@news.povray.org>
Thorsten Froehlich wrote:
> In article <41163f3c$1@news.povray.org> , Nicolas Calimet
> <pov### [at] freefr>  wrote:
>>  Interesting.  But also surprising (to me).
>>  Could you explain why it takes an order of magnitude longer to
>> jump to a function via a pointer as compared to a direct reference ?
>> (note: I'm not very knowledgeable in low-level programming, just a
>> tiny idea of some assembly instructions).
> 
> It should not at all.
> 
Hmm... After this question, I looked furter into the issue. 

First of all, quoting the GCC info: 
---------------------------------------------------------------------
Note that you will still be paying the penalty for the call through a
function pointer; on most modern architectures, such a call defeats the
branch prediction features of the CPU.  This is also true of normal
virtual function calls.
---------------------------------------------------------------------

But this cannot account for the huge difference I measured. 
And actually, my second posting on the issue must be considered partly wrong 
as well. Because it turns out that GCC will now also inline functions which 
are declared extern _and_ appear further down in the code than the 
calling location -- even when marked with __attribute__((noinline)) !!
[GCC 3.4.2 20040724 (prerelease); Seems I need to file a bug report...]

And since I did not verify that all these 3 precautions would successfully 
prevent the compiler from inlining the code, I actually measured the 
time difference between an extern and an inline call which clearly yields 
to a difference in speed. 

Okay, so let's do some really clean benchmarks this time - finally. 

Oh dear. Maybe could anybody do some independent tests concerning that 
issue? Because I will now tell you that calling an external function in 
an external library is actually _faster_ than calling it directly in the 
code when certain compiler flags are used. 
I attached my test code for review. 

So here are the timings: 

Function call      | OPT1  | OPT2
-------------------+-------+-------
int_foo(44.0);     | 3.95s | 3.58s
(*int_fooP)(44.0); | 3.57s | 3.46s
(*ext_fooP)(44.0); | 3.57s | 4.13s
-none-             | 0.37s | 0.37s

OPT1 = -ffast-math -O2 -fno-rtti
OPT2 = -ffast-math -O2 -fno-rtti -march=athlon-xp

All these values have been repeatedly measured up to +-1 in the last 
digit specified - the differences are significant. 

Hence, I think we can conclude, that there is no overhead for an 
dynamically-linked external library function call. 
[At least until somebody proves that something went wrong... :| ]

I also verified the case where the external library is calling back 
into the main code: There is no real difference again. 

Wolfgang

Here are the generated assembler instructions in all measured 
cases: 

----------<OPT1>------------<*ext_fooP>---------<OPT2>----------------
.L7:                             |  .L7:
    movl    $0, (%esp)           |      movl    $0, (%esp)
    movl    $1078329344, %eax    |      movl    $1078329344, 4(%esp)
    movl    %eax, 4(%esp)        |      call    *%esi
    call    *%esi                |      ffreep  %st(0)
    fstp    %st(0)               |      decl    %ebx
    decl    %ebx                 |      jns .L7
    jns .L7                      |
----------------------------<*int_fooP>-------------------------------
.L7:                             |  .L7:
    movl    $0, (%esp)           |      movl    $0, (%esp)
    movl    $1078329344, %eax    |      movl    $1078329344, 4(%esp)
    movl    %eax, 4(%esp)        |      call    *%esi
    call    *%esi                |      ffreep  %st(0)
    fstp    %st(0)               |      decl    %ebx
    decl    %ebx                 |      jns .L7
    jns .L7                      |
----------------------------<int_foo()>-------------------------------
.L7:                             |  .L7:
    movl    $0, (%esp)           |      movl    $0, (%esp)
    movl    $1078329344, %eax    |      movl    $1078329344, 4(%esp)
    movl    %eax, 4(%esp)        |      call    int_foo
    call    int_foo              |      ffreep  %st(0)
    fstp    %st(0)               |      decl    %ebx
    decl    %ebx                 |      jns .L7
    jns .L7                      |
-----------------------------<-none->---------------------------------
.L7:                             |  .L7:
    decl    %eax                 |      decl    %eax
    jns .L7                      |      jns .L7
---------------------------------^------------------------------------

Here are the test programs: 

---<Makefile>---------------------------------------------------------
MAINFLAGS = -ffast-math -O2 -fno-rtti
LIBFLAGS = -ffast-math -O2 -fno-rtti
#MAINFLAGS = -ffast-math -O2 -fno-rtti -march=athlon-xp
#LIBFLAGS = -ffast-math -O2 -fno-rtti -march=athlon-xp

all:
    g++ $(MAINFLAGS) -DMODULE=0 -DMAIN -c dl.cc -o dl.o
    g++ $(MAINFLAGS) -DMODULE=0 -DFOO -c dl.cc -o foo.o
    g++ $(MAINFLAGS) -o test dl.o foo.o -rdynamic -ldl -lm
    g++ $(LIBFLAGS) -nostartfiles -shared -DMODULE=1 dl.cc -o foo.so
    time ./test

asm:
    gcc $(MAINFLAGS) -fno-exceptions -DMODULE=0 -DMAIN -S dl.cc -o dl.S
    gcc $(MAINFLAGS) -fno-exceptions -DMODULE=0 -DFOO -S dl.cc -o foo.S
------------------------------------------------------------------------

---<dl.cc>--------------------------------------------------------------
// dl.cc - Written by Wolfgang Wieser. 

#if MODULE==0
//------------------
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>

extern "C" double int_foo(double x) __attribute__((noinline));

#ifdef FOO
double int_foo(double x)
{
    //fprintf(stderr,"int_foo\n");
    return(x);
}
#endif  // FOO

#ifdef MAIN
int main()
{
    void *hdl=dlopen("./foo.so",RTLD_NOW | RTLD_LOCAL);
    if(!hdl)
    {  fprintf(stderr,"dlopen: %s\n",dlerror());  exit(1);  }
    
    dlerror();
    void *sym=dlsym(hdl,"ext_foo");
    const char *err;
    if((err=dlerror()))
    {  fprintf(stderr,"dlsym: %s\n",err);  exit(1);  }
    double (*ext_fooP)(double)=(double (*)(double))sym;
    
    double (*int_fooP)(double)=&int_foo;
    
    // These make the assembler easier to compare because it prevents 
    // function pointers from getting optimized away as "unneeded 
    // variables". 
    int_foo(23.0);
    (*ext_fooP)(23.0);
    (*int_fooP)(23.0);
    
    for(int i=0; i<0xfffffff; i++)
    {
        //int_foo(44.0);
        //(*int_fooP)(44.0);
        (*ext_fooP)(44.0);
    }
    
    return(0);
}
#endif  // MAIN

#else  // MODULE!=0
//------------------
#include <stdio.h>

extern "C" double ext_foo(double x)
{
    //fprintf(stderr,"ext_foo\n");
    return(x);
}
#endif
------------------------------------------------------------------------


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 8 Aug 2004 14:15:43
Message: <41166dcf@news.povray.org>
In article <41166817@news.povray.org> , Wolfgang Wieser 
<wwi### [at] nospamgmxde>  wrote:

> First of all, quoting the GCC info:
> ---------------------------------------------------------------------
> Note that you will still be paying the penalty for the call through a
> function pointer; on most modern architectures, such a call defeats the
> branch prediction features of the CPU.  This is also true of normal
> virtual function calls.

That is completely outdated information and wrong on anything available in
the past decade.  It infers a completely static branch prediction.

The abstraction penalty is commonly measured with the so-called Stepanov
benchmark.  Google will probably find the source code as well as current
measures on current compilers and systems for it.

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Wolfgang Wieser
Subject: Re: [announce] JITC: Really fast POVRay FPU
Date: 8 Aug 2004 15:09:56
Message: <41167a83@news.povray.org>
Thorsten Froehlich wrote:

> In article <41166817@news.povray.org> , Wolfgang Wieser
> <wwi### [at] nospamgmxde>  wrote:
> 
>> First of all, quoting the GCC info:
>> ---------------------------------------------------------------------
>> Note that you will still be paying the penalty for the call through a
>> function pointer; on most modern architectures, such a call defeats the
>> branch prediction features of the CPU.  This is also true of normal
>> virtual function calls.
> 
> That is completely outdated information and wrong on anything available in
> the past decade.  It infers a completely static branch prediction.
> 
Well, actually my measurements in the last posting already showed that 
the branch prediction of my AthlonXP seems to have no major problems 
with it...

But the rest of the results is far more interesting. 
It seems that there actually is no overhead in calling functions inside 
a dynamically linked object.

Wolfgang


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.