CPU Optimization



  • This is a really general question and I don't know what kind of answer I'm expecting, but does anyone have any tips for CPU optimization? I'm finding myself not wanting to expand just because my CPU is almost maxed out as is.



  • There are some known functions that cause big slowdowns, these are mostly (but not all) functions related to pathfinding and calculating distances. You can use Game.getUsedCpu to measure strategically the slowdowns. And by this work out how to avoid the bottlenecks.

    But to be honest, staying out of the cpu bottleneck problem can be a huge challenge, but that keeps us challenged in the game as well I hope 😉



  • Just out of curiosity - how much CPU are you running on?

    I did those things to improve my CPU usage:

    • cache all paths
    • cache find results
    • where possible replace several creeps for the same task with fewer creeps with more bodyparts.

    With my far from intelligent caching i'm currently running my 5 rooms @ ~55 CPU and 1MB of memory. Still I get ~4 CPU timeouts per hour.



  • I've got 7 rooms and am usually at about 244 but it spikes frequently past 300. When you say you cached the paths and find results, what do you mean?



  • By caching the paths he means storing the most often used paths in memory. For instance, the path between sources and your room controller, spawn and extensions will probably be used a lot. Instead of calculating the path for each creep over and over again, you store the path in memory and let each creep find a path to the beginning of the cached path(which shouldn't be more than 2 or 3 tiles ideally) and then let it use the stored path.

    This will save tremendous amounts of time because most path calculations will then be short-range for which A* is pretty fast and takes few cycles.

    For find results the same can be done: whenever you do a room.find(type) keep the results in memory in case any other creep needs to do the same. I usually just store them in the room instance and not Memory because search results are usually only valid for the duration of the tick.

    To save cycles I kept my creeps relatively simple: they just execute a bunch of simple orders(move, mine, load, unload, attack, build, repair, upgrade) and when their current job is complete they report their idleness back to a controller object. This one knows of the overall state of a room(where there is available energy, tasks to be completed, etc.) and hand out new orders. Distance calculations can be cached on an on-the fly basis. If you have a creep at (10, 10) that needs to know how far it is to (29,36) you could calculate the distance and then save it the next time a creep ever needs it again. Alternatively you could create a spatial map that would make the results a bit less accurate but require less memory.



  • While I haven't tried it myself, I think that using a flowfield would be beneficial.

    The principal is as follows: You have many units wishing to find the shortest path to a particular point (or area), for example, your spawn. For every cell in the grid (a room, in this case), you calculate the direction in which a creep should move to get the the goal. After creating the flowfield, each creep can simply look at the flowfield and follow the direction. If there's something in the way, you could take the second-best direction, and so on.

    While the initial setup of the flowfield could be slow, using it is very fast. However, it does have the drawback that it doesn't consider other units, so I'd avoid using it in situations where there are many creeps in a small space, or where the environment could potentially change.



  • It seems to me that a flowfield would be more beneficial during attacks with larger groups of units. If you have a few units it probably wouldn't be worth the CPU but as your attack formations become larger I think a flowfield would be more beneficial over multiple path calculations.

    I'm currently switching most of my expensive CPU calls into a message based system: whenever a creep needs a new path, it posts a message to the back of the command queue. When I'm done with all work and still have CPU left I'll calculate a new path for the creep. The creep won't post a 'requestPath' command whenever there's one in the cache it can use.