[Speex-dev] Resampler experimental speedups

Thorvald Natvig thorvald at natvig.com
Fri Apr 4 04:48:18 PDT 2008


>
> Using just '-O2':
> Original: Direct 4548 k, Interpolate 9657k
> This version: Direct 2992k, Interpolate 9003k
> Unless anyone can spot any glaring mistakes I've made, the plan is to 
> fix the double versions, correct the int->float (and vice versa) 
> conversions and make sure the magic bytes work. Then it's time for 
> some unrolling and _USE_SSE improvements ;)
Or I can do SSE improvements first. With -O2, direct is 1043k, 
interpolate is 5166k. With full optimization, direct is 931k, 
interpolate is 5034k. I'll try to scrounge up a core2 machine I can use 
for performance testing to check wallclock time as well.
The interpolate is hurt a LOT by the 'broadcast curr_in to all 4 
elements of register'. Since there is no 'load single to all' 
instruction, we have to copy low-word to high-word and then shuffle. We 
could probably shave 20% of the instruction count if we duplicate the 
input array to have 4 copies of each value, but I think that might be 
overkill ;) ... Or maybe it isn't? For the 320 sample case (speex 
wideband), that would be only 6kB of stack, but would require massive 
rewrites (the buffer would need this copying inside resample.c, meaning 
we move arch-specific stuff into the main file). Opinions wanted.

There's a small observation here. The other SSE optimizations in speex 
have the SSE function in a header, and unless override_blah is defined, 
will define a similar function. For the non-SSE case, GCC does 
suboptimal optimization of this case with '-O2'; it is unable to merge 
the loop index and array indexes which wastes quite a few instructions. 
I therefore implemented it as follows:

...
#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
      float sum1, sum2;
      sum1 = sum2 = 0.0f;

      for(j=0;j<N;j+=2) {
        sum1 += sinc[j]*iptr[j];
        sum2 += sinc[j+1]*iptr[j+1];
      }
      sum = sum1 + sum2;
#else
      sum = inner_product_single(sinc, iptr, N);
#endif
...

This gives optimal results with -O2 for the non-SSE case.

Note that the interpolated SSE case suffers a bit from the same 
problems, and we can shave 5% or so of the instruction count if we move 
it inside the function with #ifdef'ing. The function is declared as 
'static inline' and has no side-effects, so I have no idea why GCC 
doesn't produce the same code :(
How bad would it be to move the SSE code directly into the functions, 
suitably #ifdef'd?



More information about the Speex-dev mailing list