Improving python performance.

Hello everyone.
In my long path of making scripts I often try to optimize my current python lines of code,but I am not sure what needs to be fixed…so I am asking you for some tips maybe.
I know logic briks are faster but very dirty too,so I always try to replace them with scripts.

So,any tips?

Thanks!

Well, you could always profile your scripts to attempt to find bottlenecks: https://blip.tv/pycon-us-videos-2009-2010-2011/introduction-to-python-profiling-1966784

Better improve the design of the logic rather then replacing well designed logic bricks with own “inventions” ;).
The Python controller is a logic brick too. This means it has all the benefits and drawbacks of the logic bricks.

I suggest to review the connected sensors especially the pulse modes.
See sensors - a word on pulses

try to avoid the IF , you cannot ever , but some time…

example:


this is SLOW
if x >= y and r < (x+y) or t != 2:
    x=1
else:
    x=-1

THIS IS FAST:
x=(v*t)/((r-s)*6.1654665464)


float number is more fast than integer…


this is SLOW:
x=1+1

this is (more) FAST
x= 1.0 + 1.0

EDIT: IF is not SLOW!
maybe was true time ago!?
i read this thig many time , but (at least now, with python 3.x) is FALSE

Thank you all for tips, and Marco , is that for real?

yes is all true
I can not “quantify” (not now) the difference, but on average it is so

i know many other tips :smiley:

assignament of variable cost…

SLOW:
a=15
b=51
c=44
d=a+b+c

FAST
d=15+51+44

SLOW:
import bge
logic=bge.logic
cont=logic.getCurrentController()
own=cont.owner
own[“energy”]+=1

FAST:
import bge
bge.logic.getCurrentController().owner[“energy”] += 1

PS: warning which this tips can make the script DIRTY , more exposed to line redundant or usenless… so the “absolute velocity” can not mean nothing… :wink:

Check out some general Python optimisations: http://wiki.python.org/moin/PythonSpeed/PerformanceTips

Python has many lesser used features that are faster than the more common solutions (have a look at map(), filter() and using generators).

Something I commonly do in my scripts is avoid this:


...
if not own.get('init'):
    #do initialisation stuff
    own['init'] = 1
...
# carry on script

That if statement will be checked every logic tic, and after the first tic will always give the same result. It’s better to use a state for managing the initialisation stuff and once complete go to a state for the main logic. Then you’re not unnecessarily checking a variable.

Also, localise global variables (a very contrived example!):


if bge.myGlobalValue < 2:
    myActuator.someAttribute = bge.myGlobalValue

x = 4 + bge.myGlobalValue*bge.myGlobalValue

This script has to lookup myGlobalValue through the BGE module each time it’s called, which is slow. This is faster:


var = bge.myGlobalValue
if var < 2:
    myActuator.someAttribute = var

x = 4 + var*var

Here only one lookup needs to be performed instead of 4. Obviously, this only works if you don’t plan to modify the global variable (though you could always reassign the global variable at the end of the script: bge.myGlobalValue = var). And it’s pointless if you only access the variable once or twice.

battery,

probably you here right .
if the value is used many time is better create a “local variable”

is also much too clean

I always create local values. I define lots of things to make code cleaner and with less lines of code.

Great video on profiling!

How could I use cProfile from within a game loop?

I’m using something like this:


cProfile.runctx( 'game.update()',globals(), locals(), 'output.txt')

but it only gives a report for a single logic tick, which results in a report with 0.000 for all time recordings:
http://www.pasteall.org/30553

I imagine if I wasn’t using the BGE i would call it on my main function with a while True loop and be able to get a report for the entire duration.

Any ideas?

Off topic a bit, how do I load and apply values from an external text file to specific properties? Please help me with a blend file.

@jplur: I’ve always had issues getting any profiler to work nicely with the BGE. I think the best thing to do is just to import time and time scripts, or sections of them. It doesn’t give you much information though. You might want to have a look at the timeit module.

@BlendingBGE: I don’t have time to do a .blend, but here’s a quick and dirty script:


try:
	f = open('SomeFile.txt', 'r')
        own['someProp'] = int(f.readline())
        own['someOtherProp'] = float(f.readline())
        f.close()
except IOError:
        #Somethings gone wrong! set defaults instead
        own['someProp'] = 12
        own['someOtherProp'] = 2.45

By default the value read in will be a string, so in order to use it as a value you’ll need to cast it with either int() or float(). Also, the the values are stored in a text file is important as readline() reads consecutive lines. So someProp will be line 1 and someOtherProp will be line 2. This means that if you’re saving the values at any point you also need to save them in the same order that they are loaded in. With this method it’s kinda hard to specify what variable you’re after, unless you know what line it’s on. Also, the file needs to live in the .blend directory, unless you specify a path to it: f = open(path/to/file/file.txt, ‘r’).

You also might want to look at the configparser and pickle modules.

Sounds like a flaw in your development process.

You should test your code after every significant modification, and then, if the performance is bad enough to visibly affect gameplay, you know that you need to fix something in that recently modified/created area. In that case, the problem is usually obvious, and relatively easy to remedy.

You don’t just slug along on a whole bunch of code, only to run it a few days later, and realize: “Oh, wow, this is running so slow - I must be doing something wrong.”. Then it’s much more difficult to narrow it down to one, or maybe a few lines.

All that said: Premature optimization is the root of all evil. You should try to make your algorithms as elegant, and as straightforward as possible, and worry about performance only when it becomes an actual problem.

Same here.

Although, I profile very rarely, because for real time simulations, you’re either hitting 60 fps, or you’re not, and if you’re not, it’s because of what you just changed.

When I do profile, it’s usually for more complex cases, but even then, it’s only to confirm my initial suspicions, rather than to “find the bottleneck” in the first place.

For text files there is either the method stated above. (use it as a text document) But this gets messy when you are trying to build a list, say for a high-scores system, or a dictionary for a key-mapper.

What I do then is create an external module (in the same folder as the blend file, just rename it from “.txt” to “.py”). Then you can import that using:

from myModule import scoreDict

or

from config import keyMap

Text in that text document will have to be structured properly though, as though it was typed into the script in the first place, with proper indentation and such.

Have a look at my movement demo (attached) for an example. Be aware that the script also does quite a bit of other stuff.

Attachments

movement demo.zip (66 KB)

so who can be?

by chance you use some LOD with replaceMesh??
this result as work for logic.

and is is very heavy.

or something as particle system

thats is the only thing which know which can due a hard work to the logic.

not think which can be

if not “init” in own:
:smiley:

agree, thats make run fast a script really :slight_smile:

Only optimise your code when your code begins to slow your game down. Your biggest bottleneck will most likely be the rasteriser.

I say to keep 2 versions, 1 Dev (elegant), 1 Prod (for packing).

You can remove all comments on Python to speed up a little bit.

Thank you all!Andrew, that’s true ,the rasterizer migh be a big problem and it is indeed ,but I want to optimize my code because my game needs to handle some zombies (no big scripts for them though) and a networking script which would ‘eat’ frames. Anyway,atm my logic % goes up to 12% with many zombies,but even so I must extra optimize everything.

Sdfgeoff: Thanks for the blend, I will try it when I will reach my pc.
Goran: Can’t say I do lots of script and line without checking the impact on logic% and framerate,but the problem is that I am using simple basic methods to make them and in some cases I must repeat some lines of code.Anyway,it was my fault because I haven’t specified that I am not advanced in py scripting.