[Mono-dev] Weird performance problems possibly due to floats and precision issues?

noisecrime noise at noisecrime.com
Wed Sep 21 02:31:58 EDT 2011


Hi,

So I've come across this very odd situation, which I believe I may know the
cause, but don't understand the result. I'm hoping someone can provide some
insight on the matter.

It would appear when float values get very small in a simple single line
arithmetic equation that performance suddenly drops of a cliff. Now I know
how that sounds, but i'm struggling to find any other cause and so wonder if
there is a logical explanation for it?

I'd converted Jos Stam C demo for 'Real-Time Fluid Dynamics for Games' into
C# (actually Mono 2.6 in Unity), but noticed when using certain values for
viscosity one function would suddenly take an order of magnitude many times
longer to complete than normal! 

Profiling pinpointed the problem to a specific function, the kicker being
that there is no reason I can see why this function shouldn't always
complete in constant time (excluding differences due to system interruptions
etc). In fact as long as the grid size remains constant (its a fluid solver
based on a 2D grid) I don't think there is any function in the code that
shouldn't complete in constant time between frames.

Essentially the function has three nested loops, all of which iterate the
same number of times every call. The inner loop is a single line of simple
arithmetic instructions akin to  x[i] = y[i] + (a * ( y[s] + y[t] + y[u] +
y[v]) )/c. It normally completes in a few milliseconds, but when passing in
the troublesome viscosity value it slows down quickly to taking half a
second!

Interesting the profiler showed that the execution time followed a bell
curve when the slow down occurred, suggesting that perhaps an error in the
inner loop was propagating out (through the grid) and then dissipating away,
returning to normal. However no exceptions or errors are raised on the code,
I even tried wrapping the 'checked' directive around the inner loop to no
affect.

My gut-feeling then based on observation (debugging is possible but awkward
due to the sheer number of operations happening per frame), is that it comes
down to some type of floating point precision or perhaps underflow issue (
most grid cell values have become similar to 2.802597E-44 or 1.401298E-45
during the slow down). 

This is somewhat backed up by the fact that when switching to doubles the
issue goes away for my test value, but eventually returns when I raise it
higher. However since no exceptions are raised and I don't notice any
difference in the results I can't fathom why it slow downs. It feels like
its something deep within within Mono or perhaps the hardware itself which
is trying to be helpful and not produce an error but results in unacceptable
slowdown?

So I'd welcome any input into why a single line of code, that just adds and
multiplies a few floats can suddenly take 100's of times longer to execute
than normal?


The function is

N is the dimension of the grid/array (i.e. N*N = total cells in grid)
b is a flag for use in the set_bnd() call
x is a an array of the current float values
x0 is an array of the previous float values
a = dt*viscosity *N*N (where dt is a constant 0.15)
c = 1+4*a


int IX(int i, int j)  
{    
return ( (i)+(N+2)*(j) );
}


void lin_solve ( int N, int b, ref float[] x, ref float[] x0, float a, float
c )
    {
        int i, j, k;

        for ( k=0 ; k<20 ; k++ )
        {
            for ( i=1 ; i<=N ; i++ )
            {
                for ( j=1 ; j<=N ; j++ )
                {
                    x[IX(i,j)] = (x0[IX(i,j)] + a*(x[IX(i-1,j)] +
x[IX(i+1,j)] + x[IX(i,j-1)] + x[IX(i,j+1)]))/c;
                }
            }
           
            set_bnd ( N, b, ref x );
        }
    }


Some additional notes.

Specific values i'm testing with
N = 128
viscosity = 0.09
dt = 0.15

In profiling whilst set_Bnd() did take slightly longer than normal the vast
amount of time was in lin_solve().
Calling IX() for converting the grid(i,j) into a single index is obviously
non-optimal and i've optimised that in my actual code. However the original
code shown here still exhibits the slowdown issue and is easier to read.



--
View this message in context: http://mono.1490590.n4.nabble.com/Weird-performance-problems-possibly-due-to-floats-and-precision-issues-tp3829087p3829087.html
Sent from the Mono - Dev mailing list archive at Nabble.com.


More information about the Mono-devel-list mailing list