Even More Optimal!

A new player by the name of constrat reported some increased lag with Rev 1.4/1.5 on steam. We got talking and it turns out he has quite a special case. He has over 200 land turrets!

Now, this is a pretty good stress test case, and I’d been meaning to explore an avenue of potential performance increase.

One of the speed-ups I mentioned in earlier posts was to use x^0.5 instead of math.sqrt(x). One of the reasons that math.sqrt(x) is slightly slower partly because it involves a call out of lua into the native math library in C. The extra function call, and boxing/unboxing of the values adds some overhead.

Looking at CC2, the lua scripting makes heavy use of vehicle objects. These are all implemented in C/C++, calls from lua to the various methods on these objects reach down into the native code. This is generally pretty fast, but what if we could cache these?

In my previous post I got a significant speedup by using my new get_vehicles_table() function. Returning only one copy of each unit in a fast-to-iterate table.

get_vehicles_table() turns out to be a pretty good spot to try something clever!

I have created a proxy class for vehicles that I call VProxy. get_vehicles_table() now returns instances of this class.

In here, I can cache a lot of stuff right away. I can store things like the unit type (definition_index), it’s location, waypoint counts etc. I can store these in my lua object, and add methods for all the various real vehicle functions.

552 lines of lua later and we have it working!

Using my perftest map and call timer. With the original vehicle objects (plus some minor speedups) I get:

start timer	3	1752189005	10748
done timer	1752189025
calls	8607
calls/sec	430.35

Using my new proxy objects instead, and using the same map/timings I now get:

start timer	3	1752189090	12589
done timer	1752189110
calls	13522
calls/sec	676.1

Holy rusty metal Batman! a 57% speed increase!

It’s not simply caching calls into the native layer that got this speed up. Having a lua object means I can cache a lot more of the revolution extra computation onto each object.

Previously, to find out if a unit had a RADAR fitted, I would look at the unit’s attachment points each time. With the proxy object I can now do this once and cache the result for the rest of the tick. This is especially a benefit as things like “is this seen by a radar?” checks are all over the place. I can now cache all of these in the proxy object.

There were a few other things that are slow-ish in lua that I mentioned before. Use of the local keyword can speed things up. Partly this is due to local things being on the stack, but also partly that it is faster to lookup stack variables than it is to lookup globals.

It is also pretty slow to use the “index” accessor of a table.

Previously I had some caches that were global tables indexed by vehicle ID. I would access them like so:

function _get_is_seen_by_friendly_modded_radar(vehicle)
    if vehicle and vehicle:get() then
        local vid = vehicle:get_id()
        local exists = g_seen_by_friendly_radars[vid]
        if exists ~= nil then
            return true
        end
    end
    return false
end

The g_seen_by_friendly_radars line is actually quite slow :/

But with my new proxy object I can cache all this in one place!

function _get_is_seen_by_friendly_modded_radar(vehicle)
    if vehicle and vehicle:get() then
        if vehicle.extended then
            return vehicle:get_is_seen_by_friendly_modded_radar()
        end

        local vid = vehicle:get_id()
        local exists = g_seen_by_friendly_radars[vid]
        if exists ~= nil then
            return true
        end
    end
    return false

Here, if I am handed one of my new objects (test for vehicle.extended being non nil) I can just call a method and get a cached value after the first call.

For now this is in my experimental branch as there are at least 260 calls to vehicle objects in the vehicle control screen alone. I need to be sure I’ve proxied and cached them correctly in all cases before this goes live.

Fly safe!

By:


2 responses to “Even More Optimal!”

Leave a comment