The Water Demo Performance
From PyWiki
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
