Module speed

I have a somewhat open question regarding module speed. Once units get fairly complex with lots of traits, things start slowing down pretty bad (taking a few seconds to simply move a piece, etc). The easy answer to this is of course…simplify things (and believe me, I’ve tried).

However, when you have a decent amount of logic in a unit, something as simple as an If…Then statement requires 5-7 traits (one to trigger via menu, two to represent separate conditions, two more to represent actions, plus two more if you want it to report the actions taken in the log, requiring a minimum of 3 triggers). Having things like movement through varied terrain (which have multiple if…then statements) bloat things greatly. A simple, select A or B and perform related actions (such as send to VP stack) takes 6 actions (one to trigger, dynamic to store value, then see above for if statement for a minimum of 4 triggers). Something as crazy as a switch statement has even more, which with sequential if statements, the number of triggers gets insane.

What actually impacts game speed? Is it number of traits (regardless of type)? Number of triggers (so markers and calcs have little effect)?

More specifically:

  1. Do calculated variables slow things down? Of course they need a bit of processing time, but does the engine have to go through them which hunting for triggers or such?

  2. Is it better to have several DPs with simple triggers, or one DP with more complex triggers? An example would be 4 on-off variables. You could use 4 DPs with 2 triggers each, or 1 DP with 8 complex triggers (using binary logic). Same number of triggers and actions, but which would be faster?

  3. For just storing fixed values (such as base Defense or base Attack values for each unit) are Markers more efficient than DPs (without triggers)? Would storing things in global variables be even efficient since it would reduce number of traits (though it’d be a nightmare to work with when you have many unit types)?

  4. If triggers (and hunting for traits they change) are the slow point, might it be possible to use variable / calculated triggers? Similar to the way you can use an expression to choose the global property in a “Set Global Property” trait? Then you could have one complicated Calculated Property to use as many inputs as you want in nested if statements to call a resulting trigger (rather than needing 3 traits for every nested if…then).

Thus spake dsdhornet:

What actually impacts game speed? Is it number of traits (regardless of
type)? Number of triggers (so markers and calcs have little effect)?

Depth of traits matters quite a lot. Specifically, putting traits which
are accessed a lot near the top of the trait stack if you can will speed
things up.

As for the other things, they’re relatively new and haven’t been
profiled much, if at all. So my advice would be to try them and find
out.


J.

Calculated properties do slow down the module significantly. I had, like 5 per counter, 12-15 counters, yields ~70 calculated properties. Module would run very slowly; if I, however, triggered the change of a calculated property, module would then run with “normal” speed.

When you say “triggered the change of a calculated property”, what do you mean? You mean using a dynamic and placing the calculation in the “set value” field? (so it only changes when triggered?). If the calculated property has lots of variables (say maybe 5, and needs to be updated when any of them change), would it be more efficient to use a calculated property, or trigger a dynamic change when each variable changes (i.e. add a trigger action with dozens of triggers)?

Calculated Properties do not work this way. They have no way of knowing the value of the properties referenced in them except by recalculating the whole expression. They are not recalculated when one of their variables changes, they are recalculated each and every time their value is queried.

So if you have a lot of pieces with many Calculated Properties and those CP’s are referenced in the Property Match Expression of a Global Key Command, then each and every one of those CP’s in every counter is going to be re-calculated whenever you send a Global Key Command.

The primary thing that slows down modules is the average number of traits per counter. Traits are stored like a stack of pancakes and whenever there is a request to evaluate a property, Vassal starts at the top and searched down through the stack of pancakes until it finds a trait that ‘knows’ how to provide a value for that property. If no pancake knows about that property, then after the stack has been searched, Vassal checks for internal and system properties. So number 1 guideline is fewer properties are better.

What you don’t see is that there are many calls to Vassal system properties that you don’t see, that have to search down through the same stack of pancakes, even though they will never be found in the stack. It’s a flaw in the design that I am looking at providing a workaround for shortly.

Global Key Commands of any sort are also very inefficient as they have to search every single counter in the current game to evaluate the Property Match Expression on each counter to see if the counter matches. So guideline 2 is go easy on Global Key Commands, try not have the generated often.

Calculated Properties themselves are coded to be as efficient as possible, however, there is certainly an overhead in evaluating complex formulae. This is no problem if they are called now and then. But if your module is generating lots of Global Key Commands automatically that reference Calculated Properties in pieces, you are going to have trouble. The CP overhead is pretty much independent of the complexity of the formula, so 1 complicated CP is better than multiple simple CP’s.

There is no difference in efficiency between Markers and Dynamic Properties. Except that you can store multiple property names and values in a marker (seperate by ;) so guideline 1 says that recording 5 stats in a single marker will be much better than storing them in separate markers.

Hope this helps,
Brent.

My goal was to display leader attributes – the attributes would be displayed if global property display==1. Each leader has three attributes – thus I created three calculated properties for each leader: if(display==1,COMMAND,"") (can’t recall if it requires $$ or not – bear with me). Each leader would have specific COMMAND defines as a Marker. The same refers to ASSAULT and LEVEL.

On start, display was set to 0 – attributes were hidden but also module would run very slowly. If I changed the value of display – with a button which changes a specific GP – module would display attributes and would gain on speed – it would not run very smoothly but noticeably faster and would keep on this speed irrespectively of value of display.

EDIT: I should have added that each COMMAND, ASSAULT and LEVEL are displayed by a Text Label trait.