Need help optimizing module speed and logfile size.

Here’s the situation:

116 cards, a “market” of 12 cards dealt from a deck into 2 rows of 6 columns (U0 to U5 in the top row and L0 to L5 in the bottom). Players can take a maximum of 2 cards in a turn, adding “money” tokens to the market when they do. U0 and L0 might be discarded on cleanup.

Then, the refresh button shifts all cards and money on cards towards 0 as far as they will go, and deals new cards into empty spaces (U0 L0 U1 L1 etc).

At first this refresh was very very slow, but I found a way to speed it up. The problem is that doing so seems to have made saving games and writing logfiles really slow (like, 60 seconds slow).

So, I’ll describe how I did it, and hopefully someone can point me to a way to resolve both problems - slow refresh AND slow logfile writing.

Mk 1 (slow refresh, OK logfiles)
Global properties U0 to L5.
Reset all to 0
GKC to cards in market to set matching GP to 1
GKC to cards&money in market to “move”
Triggers on cards&money to move only if adjacent GP is 0.
Repeat 4 more times.
Reset GPs to 0
GKC to cards in market to set matching GP to 1
Add new cards.

MK2 (fast enough refresh, slow logfiles)
Global properties U0 to L5.
Reset all to 0
GKC to cards in market to set matching GP to 1
GKC to cards&money in market to “move”
90 Triggers on cards&money to move based on all possible GP 0/1 combinations.
Reset GPs to 0
GKC to cards in market to set matching GP to 1
Add new cards.

MK3?
Maybe shift all move triggers off cards and money to an invisible control piece, have it send out two sets of up to 10 conditional targeted move GKCs to cards & money?

I’m finding this frustrating because I have little idea what will be fast or slow, and even less idea what impacts logfile write times, and each rewrite is very time-consuming.

Can anyone point me in the right direction?

In case I’m completely off the mark as to what is causing the logfile write times and someone is willing to look it over, here’s the current-ish state of the module:
drive.google.com/open?id=1UATAn … Pb9Euym7gP

FWIW, consolidating the 90 move triggers into 10 for cards (1 for each possible destination) and 3 for money (1 for each possible move distance) seems to have sped things up a bit.

drive.google.com/open?id=1kG1hp … zmquDEtw6y

I don’t want to try rewriting everything to work off a control piece unless I know it will speed things up significantly.

90 triggers is a fairly astonishing number–I don’t have the reference on hand, but I swear I’ve read somewhere a long time ago in this forums that triggers specifically have a performance impact. I’m just hazy on why that was.

It might have been in relation to the Space Empires 4X module…

I’ve run into this problem and it’s mainly the reason I’ve put off my lifetime goal of creating an online version of my game of To Be King until Vassal 4. In my case, the combat computer I was creating basically brought the module to a stand still after only a few battles.

The problem, as I understand it, is when you have a large amount of automation, triggers, etc., this all gets recorded in internal memory so that the “undo” functions will work properly. The information collected is enormous and if you open your Task Manager (if you’re using Windows) and watch the memory usage for Vassal, it frighteningly impressive. Basically, you’re draining your memory resources every time you run the process. It only takes a few times and there’s nothing left.

Thank you for the replies.

I don’t think the problem is insurmountable in my module. I would just like to know how to minimize delays - which architecture will run fastest?

I know the 90 triggers per card breaks things badly, while cutting that down to 10 “or or or” triggers per card speeds things up. Likewise, 3 very simple triggers on the cards and one very complex control piece with a lot (I haven’t counted) of triggers and GKCs seems to speed things up again.

So is it a simple sum of all traits on the board? Triggers on all pieces on the board, regardless of whether or not they are identical from one prototype? Some other easy to use rule of thumb?

I just want to optimize speed as much as possible.

I think thinning out a lot of very messy trait lists on widely-used prototype traits has already done wonders for the module.

drive.google.com/open?id=1j_BWL … m0JFW-Sm37

Joel, I don’t know if you are the Joel who made modules like Fire in the Lake, but if you are, thanks! The use of things from your modules like $DestX$ $CurrentX$ $OldBitLocation$ Global Properties and the like has made some really nifty things possible in my own modules.

Nope, not me.

You might take a look at Pax Renaissance and Bios Megafauna mods, which have similar markets.

Sorry for being a bit late to chime in.

Each and every trait you add to a counter adds a processing overhead to that counter whenever it is on the screen. It’s not so much the Undo information, it’s that the visible state of all the counters is being continuously checked and refreshed many times per second. Each time this happens, Vassal essentially runs through every trait in every counter on the board to see if something has changed.

The amount of overhead varies depending on what the trait is, but every trait has at least some overhead. Any trait referencing Dynamic Properties or using inline {} beanshell expressions tend to be the heaviest, also Layers following properties. Marker traits would be the lightest.

There is also an additional overhead per trait per counter when saving/loading games and in save game file size. This is the undo information issue you referred to.

So the limiting factor tends to be the total number number of traits (not counters) on the board at once. This means your solution of simplifying the majority of the pieces and concentrating the ‘intelligence’ in a few control pieces was a particularly good one.

Regards,
Brent.

Thanks Brent!

One more question:

I have 10 pieces each with property-dependant 5 layers, and currently I’m using a different calculated property for each piece with a really long if-then-otherwise chain based on the same 6 global properties to determine the correct layer to use for each piece in a given game.

However, the global properties, the layer, and the calculated property will only change once in a game, when a setup button is pressed by a player.

Would I be better off using, for each piece, a dynamic property instead of a calculated property, with 5 different triggers each having a shorter if-then-otherwise chain condition? Or is having one complex calculated property better than a dynamic property and 5 complex triggers? Or is it all a wash?

Or (I just thought of this), would I be better off using 10 different pieces (5 layers, 2 types) in a palette, and using even more triggers to send the correct piece (instead of calculating the correct layer) to the 10 (fixed) locations based on the 6 global properties?

Hi Benkyo,

Property dependent layers are not so bad if the property they depend on
is cheap to check the value of. You do not want to have property
dependent layers based on a Calculated property as these are the most
expensive to read as Vassal has to re-calculate the property value each
time it is referenced, which will be many times per second if it is
associated with any trait that can potentially change the image of the
counter.

Much better to use a Dynamic Property that is set to the value of the
Calculated property at the time the setup button is pressed. Dynamic
properties are cheap to read.

Are these properties shared between counters (Like all ‘red’ pieces will
have the same value and all ‘blue’ pieces get another value)? If so,
consider using Map or Module level Global properties to hold the values
you need, set to the appropriate values at setup time. That will
considerably simplify you counters and be the best solution of all.
Global properties are also very cheap to read.

Regards,
Brent.

On 5/08/2019 10:27 am, Benkyo wrote:

Thanks Brent!

One more question:

I have 10 pieces each with property-dependant 5 layers, and currently
I’m using a different calculated property for each piece with a really
long if-then-otherwise chain based on the same 6 global properties to
determine the correct layer to use for each piece in a given game.

However, the global properties, the layer, and the calculated property
will only change once in a game, when a setup button is pressed by a
player.

Would I be better off using, for each piece, a dynamic property instead
of a calculated property, with 5 different triggers each having a
shorter if-then-otherwise chain condition? Or is having one complex
calculated property better than a dynamic property and 5 complex
triggers? Or is it all a wash?

Or (I just thought of this), would I be better off using 10 different
pieces (5 layers, 2 types) in a palette, and using even more triggers to
send the correct piece (instead of calculating the correct layer) to the
10 (fixed) locations based on the 6 global properties?


Read this topic online here:
https://forum.vassalengine.org/t/need-help-optimizing-module-speed-and-logfile-size/9943/11


messages mailing list
messages@vassalengine.org
vassalengine.org/mailman/listinfo/messages


Brent Easton
Analyst/Programmer
Western Sydney University
Email: b.easton@exemail.com.au


This email has been checked for viruses by Avast antivirus software.
avast.com/antivirus

Thanks again!

The setup is a 2-5 player game. Player adjacency is important for one type of piece movement, and can be imagined as a simple circular track passing through all player windows. I had a request that each player window have a left and right indicator displaying which player is to the left and which to the right, as this is random each game.

To start a game, someone has to click on a setup button, for 2, 3, 4, or 5 players. This does a lot of shuffling and sorting and takes a while to grind through anyway. I recently added a system that a) sets a “shape” global property (indicating facing, triangle, square, or pentagon), b) based on the shape, deals player pieces from a shuffled deck to a circular icon track on the main map, and c) triggers each player piece to set a “position” GP from 1 to 5 based on the XY coordinates it is sent to (indicating where each player piece randomly ends up on corners of the shape).

Each indicator on each player window, if it isn’t deleted, checks the “shape” GP, it’s associated position GP, and which player is associated with an adjacent position GP, in order to pick the appropriate layer (i.e., indicate which player is to the left/right).

It all works fine based on 10 tailored very long calculated properties, but if dynamic properties based on a series of triggers would reduce the processor load, I might re-work it. I don’t think any really simple solution would achieve the same result though.

The module already has some complex necessary calculated properties going on for other systems, and a whole lot else besides, so I need to trim where I can.

This is the Calculated Property for one indicator. I was quite proud I got it all to work, and I was just trying to keep the number of traits as low as possible, but I should have realised CalcProps would be a resource hog.

{If(shape==5,If(positionr==1,If(positionb==2,2,If(positionk==2,3,If(positiont==2,4,5))),If(positionr==2,If(positionb==3,2,If(positionk==3,3,If(positiont==3,4,5))),If(positionr==3,If(positionb==4,2,If(positionk==4,3,If(positiont==4,4,5))),If(positionr==4,If(positionb==5,2,If(positionk==5,3,If(positiont==5,4,5))),If(positionb==1,2,If(positionk==1,3,If(positiont==1,4,5))))))),If(shape==4,If(positionr==1,If(positionb==2,2,If(positionk==2,3,If(positiont==2,4,5))),If(positionr==2,If(positionb==3,2,If(positionk==3,3,If(positiont==3,4,5))),If(positionr==3,If(positionb==4,2,If(positionk==4,3,If(positiont==4,4,5))),If(positionb==1,2,If(positionk==1,3,If(positiont==1,4,5)))))),If(shape==3,If(positionr==1,If(positionb==2,2,If(positionk==2,3,If(positiont==2,4,5))),If(positionr==2,If(positionb==3,2,If(positionk==3,3,If(positiont==3,4,5))),If(positionb==1,2,If(positionk==1,3,If(positiont==1,4,5))))),If(positionr==1,If(positionb==2,2,If(positionk==2,3,If(positiont==2,4,5))),If(positionb==1,2,If(positionk==1,3,If(positiont==1,4,5)))))))}