The Water Demo Performance

From PyWiki

Jump to: navigation, search

Contents

Optimising Python-Ogre Performance

OverView

Upon completing the water demo (doing a straight conversion from the C++ code to Python) I discovered that the frame rate was terrible when comparing the Python-Ogre version with the original C++ one. As this is NOT the normal case I decided to spend some time investigating and hopefully fixing the issue.

As a base line on my Lenovo X61 laptop I get about 175fps for the C++ demo (and this is limited by the graphic card and setting 'fake normal's doesn't improve the performance) and only 2-3 fps for the Python-Ogre version.

Step 1 - Use Pysco !!

Before doing anything it is always a good idea to enable the pysco module just to see what it can do for us. So add the following to Demo_Water.py and WaterMesh.py

try:
   import psyco
   psyco.full()
except ImportError:
   sys.exit()

This improved the frame rate to a wopping 4 fps -- a 30-50% improvement -- however clearly more work needed :)

Step 2 - Identify Problem Areas

So we need to find out where the delays are happening -- and while we can simply start with the frame listeners and do comment out code and retest the 'right' way is to use the Python profiler. So change Demo_Smoke.py to look something like this:

if __name__ == '__main__':
    import cProfile
    import pstats
    application = WaterApplication()
    cProfile.run('application.go()', 'profile.out')
    p = pstats.Stats('profile.out').strip_dirs()
    p.sort_stats('time','cumulative').print_stats(15)

Let it run for 30 seconds or so and press ESC to exit at which point you'll get a print out:

  ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     411   38.812    0.094   46.437    0.113 WaterMesh.py:330(calculateNormals)
     411    9.938    0.024   56.893    0.138 WaterMesh.py:392(updateMesh)
 2525184    7.534    0.000    7.534    0.000 WaterMesh.py:66(__getitem__)
       1    1.927    1.927    1.927    1.927 sf_OIS.py:188(_loadResources)
       1    1.911    1.911    3.333    3.333 Demo_Water.py:51(prepareCircleMaterial)
  274123    1.047    0.000    1.047    0.000 {method 'append' of 'array.array' objects}
       1    0.714    0.714    0.714    0.714 sf_OIS.py:193(_configure)
  207180    0.596    0.000    0.596    0.000 {range}
       1    0.474    0.474    7.027    7.027 sf_OIS.py:124(_setUp)
       1    0.462    0.462   64.902   64.902 sf_OIS.py:103(go)
   65536    0.248    0.000    0.248    0.000 {math.fabs}
   67180    0.167    0.000    0.167    0.000 {math.sqrt}
       1    0.129    0.129    0.129    0.129 Demo_Water.py:189(updateMaterial)
       1    0.114    0.114    0.184    0.184 WaterMesh.py:97(__init__)
       1    0.111    0.111    0.111    0.111 sf_OIS.py:156(_setUpResources)
       1    0.088    0.088    3.605    3.605 Demo_Water.py:331(_createScene)
     412    0.065    0.000   57.325    0.139 Demo_Water.py:256(frameRenderingQueued)

Look for functions that get called each frame and have the greatest tottime -- so we need to look at caclulateNormals and possibly updateMesh

In looking through the updateMesh code we see that it calls calculateNormals hence it's likely to be the issue. So as a test lets comment out the code and see what happens

#        if (self.useFakeNormals):
#            self.calculateFakeNormals() 
#        else :
#            self.calculateNormals()

After testing our frame rates go to 64 fps !!! So clearly we should focus on the calculateNormals function. Also we can see that the loops in calculateNormals relate to the variable 'COMPLEXITY' which is set to 64 (by default) -- hence lets set it to 32 to confirm it effects the frame rate

COMPLEXITY = 32     ## watch out - number of polys is 2*ACCURACY*ACCURACY !

This gives us a frame rate of 11 fps a significant improvement so we need to now look at how to fix the calculateNormals

Step 3 -- Improve the Python Code

The Water Demo Performance -- Part 2 -- Tweak the Python Code

Personal tools