Skip to content

13702 Optimize sum and count expressions#14547

Open
rlament wants to merge 1 commit into
vassalengine:release-3.7from
rlament:13702-countzone
Open

13702 Optimize sum and count expressions#14547
rlament wants to merge 1 commit into
vassalengine:release-3.7from
rlament:13702-countzone

Conversation

@rlament

@rlament rlament commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Wondering if these changes to the sum/count functions make any noticeable impact on modules. Doing some very basic profiling with System.nanoTime shows an improvement depending on game piece design and filtering (match expression) options.

The existing code relies on updateTotal() for computing both sums and counts. These actions are similar yet different enough to warrant separate functions. They do handle properties differently. Since these functions are invoked from within loops, any reduction in conditional testing and branching can have an impact.

The updateTotal() function applies the match expression (if defined) to all pieces first, whether or not those pieces have the property of interest. The BeanShell processing is computationally expensive and it is best to avoid it when possible. The new updateCount() and updateSum() functions compute the match expression as a matter of last resort. Take the sum function, if the property is non-existent or is not a number or is zero, then checking the match expression is unnecessary and thus never invoked.

The greatest benefit would be in modules that subset properties. With differing units having different properties, summing on something like alliedPower or axisPower could eliminate half the counters from a calculation before applying any match expressions. In cases where there are common properties with a reliance on match expressions, this code change likely won't make much of a difference.

Profiling with unit tests shows a marked improvement. Whether this translates to more responsive modules is to be seen. The matching expression is too powerful not to use, but at least it won't be invoked on pieces unrelated to the property in question.

Closes #13702

@rlament rlament changed the base branch from master to release-3.7 March 9, 2026 23:37
@riverwanderer riverwanderer added this to the 3.7.21 milestone Mar 12, 2026
@riverwanderer

Copy link
Copy Markdown
Collaborator

Tested briefly with the C&C Napoleonics module, which uses Count() family functions extensively. The game mechanics worked as expected and maybe some were a little faster.

@uckelman uckelman removed this from the 3.7.21 milestone Apr 9, 2026
@uckelman

uckelman commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

If you really want this to be faster, the way to do it is to hoist the null and emptiness checks for propertyName and the null check for filter out of the loops, which you can do because they are loop invariant.

@uckelman

Copy link
Copy Markdown
Contributor

For updateSum and updateCount, pass in an iterable rather than have the loop on the outside. Then you can hoist the null and emptiness checks outside of the loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimise CountZone() evaluation order

3 participants