Jump to content
Sign in to follow this  
zorrobyte

Condition optimization request

Recommended Posts

Hello! I'm investigating CPS drop in my addon ZBE_Caching and require assistance in optimizing a condition.

The code is:

!({_x distance player < 1000} count (switchableUnits + playableUnits) isEqualTo 0)

["!({_x distance player < 1000} count (switchableUnits + playableUnits) isEqualTo 0);"] call BIS_fnc_codePerformance;

0.0121948ms 1 player 5 playableUnits

This is important as when running on 144 groups:

1.7712144ms : 144 groups 1 player 5 playableunits - this is where CPS begins to drop assuming 60FPS as I have a sleep of 1 second between checks.

Share this post


Link to post
Share on other sites

I don't actually understand the syntax you're using there but I'll assume it's legal in whatever context you're using it.

What I would say is you probably want to avoid concatenating the switchableUnits and playableUnits arrays just to count them, better to count them separately and add the results.

Though I wouldn't have thought 1.7ms was an issue, did you mean 1.7s?

Share this post


Link to post
Share on other sites

I'm a little lost on the wording, but from what I think I understand: a single group of 6 entities takes ~0.012ms, but doing 144 groups of 6 enitities each takes ~1.77ms, but there is a suspension of one second between evaluation?

Edited by JShock

Share this post


Link to post
Share on other sites

!({_x distance unit1 < 1000} count (switchableUnits + playableUnits) isEqualTo 0)

is a condition in a FSM that runs on each group that is checked every second. This condition takes 0.0121948ms to process, with 144 groups (144 FSMs) the combined total to check this condition is 1.7712144 seconds. As 1.7 seconds is longer than 1 second, other scripts begin to lag (my logic may be flawed here).

Simply put, I'm looking for any way to check if a player is near a unit in a faster way.

What I would say is you probably want to avoid concatenating the switchableUnits and playableUnits arrays just to count them, better to count them separately and add the results.

I'll start here, I can build the "playable" units array in my main SQF loop that runs every 15 seconds instead of the FSMs that run every second x 144 times.

Edited by zorrobyte

Share this post


Link to post
Share on other sites

take a step back and explain first what you want to achieve

Share this post


Link to post
Share on other sites

When doing frequent distance checks against a fixed value, it's better to use distanceSqr. That way the game doesn't have to pull the square root of the value every time.

https://community.bistudio.com/wiki/distanceSqr

I guess this is as good as it gets:

!( { if (_x distanceSqr player < 1000000) exitWith {true}; } count (switchableUnits + playableUnits) isEqualTo 0 )

Also, switchableUnits are only relevant when you want that mission to work in SP. Which is rather pointless for most MP missions.

Share this post


Link to post
Share on other sites
This condition takes 0.0121948ms to process, with 144 groups (144 FSMs) the combined total to check this condition is 1.7712144 seconds

Your conversion is off there Zoro. Ignoring the sleep for a moment...

0.0121948ms * 144groups = 1.7560512ms or 0.001756seconds

60fps == 1 / 60 = so 1frame is 0.016seconds or 16ms

0.016 / 0.001756 = 9.11

So your FSM would actually runs 9 times a frame, well potentially speaking, ignoring your sleep, other code and any engine overhead.

Simply put, I'm looking for any way to check if a player is near a unit in a faster way.

Im with .kju here, take a step back and explain what your overall goal is and how your currently doing it. No need to paste loads of code, just give us pseudo code of how things operate.

Edited by Larrow

Share this post


Link to post
Share on other sites
When doing frequent distance checks against a fixed value, it's better to use distanceSqr. That way the game doesn't have to pull the square root of the value every time.

Thank you! I'm adding and testing now!

Your conversion is off there Zoro. Ignoring the sleep for a moment...

0.0121948ms * 144groups = 1.7560512ms or 0.001756seconds

60fps == 1 / 60 = so 1frame is 0.016seconds or 16ms

0.016 / 0.001756 = 9.11

So your FSM would actually runs 9 times a frame, well potentially speaking, ignoring your sleep, other code and any engine overhead.

Derp, I shouldn't stay up all night and code while sick. Thanks!

;2832903']take a step back and explain first what you want to achieve

Hello kju!

I'm trying to solve CPS drop (script lag) in my caching module GIT REPO

I'm currently seeking to optimize for uncache/cache event if players are near (the isNull is for AI<->AI cache/uncache check):

zbe_cacheEvent = {
({_x distance _leader < _distance} count zbe_players > 0) || !isNull (_leader findNearestEnemy _leader)
};

C2pWdCx.png

The other conditions are in the functions sqf (some are scattered in the FSMs until I can migrate them):

zbe_func

The faster I can make my conditions' date=' the less load my caching module has on the VM.

My overall goal is to make CooP playable again with decent performance as AI kill servers. ZBE_Cache is CC-BY-SA and is one of the few caching modules compatible with just about any addon/script as I enablesimulation and hideobject all but leader instead of create/deletevehicle. As a bonus, ZBE_Cache allows thousands of empty vehicles spawned on the map as without, FPS massively drops for clients.

I'll accept and credit any help provided up to and including GIT access.

---------- Post added at 06:40 PM ---------- Previous post was at 06:34 PM ----------

Hell, just posting the SS of my FSM helped, I see a error for reSync leader as uncache is linked to it for condition check and that I can remove my grpNull check for cache&uncache state as allDead should remove null groups :eek:

Edited by zorrobyte

Share this post


Link to post
Share on other sites

I think you are still to narrow with the description of your "problem".

So let me put you a specific question to start with - why do you need to check that every more than every second?

The condition can and still should be optimized, yet its important to look at the areas that matter most first.

Share this post


Link to post
Share on other sites

The condition is not checked more than every second. It is checked every 3 or so "time frames" of te Arma engine.

But the condition is checked by every AI group. Thus the need and questions to optimize it as much as possible.

As in his example, 144 AI mean 144 checks every 3 secs.

Share this post


Link to post
Share on other sites

I think a question to ask is, how often is it NECESSARY for the server to perform these evaluations? Every frame? Every 3 frames (as now)? Every 60 frames? Every 1-2 seconds? Every 10 seconds?

Seems like such a performance-costly schedule is the problem, and something that definitely isn't going to improve much by trying to optimize the evaluation in question.

It's still being performed many hundreds of times each second.

Share this post


Link to post
Share on other sites

Dunno if wrong, but sleep 3 is a wait of 3 secs, isn't it? Not 3 frames.

Share this post


Link to post
Share on other sites
Dunno if wrong, but sleep 3 is a wait of 3 secs, isn't it? Not 3 frames.

Sleep does not work in FSM, and he's got 144 parallel FSMs running, one for each group. Many many thousands of evaluations per second. Not just evaluations, but world evaluations (distance checks). Optimization? You know what they say about lipstick and pigs? :)

Optimizing an evaluation that happens thousands of times a second by using naval gazing optimizations that are measured in 3-5 decimal places (ie faster commands, lazy evaluations, and other stuff that produces barely-measurable and virtually unnoticeable effects)... Or structural optimization to go from thousands of evaluations a second, down to just a handful a second?

As it is, there is not enough information provided to approach structural optimization, so IMO we are back to looking at a pig and deciding what color lipstick looks best :)

No offense to you OP, just speaking my mind, and one way or the other your problems will be solved and all will be well in the end.

EDIT:

To be constructive:

Since that FSM isn't a perpetual loop and it looks like there is great similarity from one FSM to the next (of the 144), I am of the mind that the best optimization would be to get rid of all the loops in the FSM (simplify it so it doesn't hang anywhere waiting for something), and then build a scheduler SQF and then feed the groups into the FSM one at at time in a loop. So instead of 144 FSMs running in separate threads, only one runs at a time. That would make the code almost 144x more performance-efficient.

Just a side note ... This is the exact issue why AI are such a performance drag in ArmA. Each AI group/unit runs its own behaviour FSM thread, measuring distance to cover, enemies, near objects, waypoint calcs, terrain, rocks, targets, shots fired near, etc etc etc ...So OP, don't feel bad. This is how BIS does it too :)

EDIT 2:

More constructive ... This represents a structural optimization rather than IMO petty evaluation optimizations ...

// FSM scheduler
// Rough template, use for ideas
// :)

private ["_grpIndex","_grp","_fsmHandle"];

//========================== CONFIGURE YOUR GROUPS HERE

ai_cacheGroups = [];            // your managed groups
{
if (_x getVariable "ai_caching_group") then {           // dreadedentity will chime in about alternative syntax here, go with what he suggests
	0 = ai_cacheGroups pushBack _x;               // find groups with your variable attached to them, to register them for management
};
} count allGroups;

// Any more groups data required for the FSM? Define it here
// Stuff here is not checked again so consider it constants unless you redefine them at some point

//========================== LOOP

ai_caching = TRUE;
while {ai_caching} do {

// Can re-define stuff here if necessary, for use by each group
       // access changing variables/information here, IE player count may change, weather, time, FPS, etc. 

{	
	_grpIndex = ai_cacheGroups find _x;
	_grp = ai_cacheGroup select _grpIndex;
	_fsmHandle = format ["fsm_%1",_grpIndex];
	_fsmHandle = [_grp, /* any more data or variables you want to send to the FSM? */] execFSM "fsm\ai_caching.fsm";
	waitUntil {sleep 0.1; (completedFSM _fsmHandle)};			// Wait for one FSM to complete before running the next
} count ai_cacheGroups;
};

Edited by MDCCLXXVI

Share this post


Link to post
Share on other sites

Sorry, my bad. posting comments on phone wiithout thinking.

We are doing this for delay:

(time - _t) > 3;

So basically, checks if the time minus the checked time in a previous FSM state is greater in 3 secs, to continue.

But, your idea could be valid too. will give a try in this week.

Edited by Zriel

Share this post


Link to post
Share on other sites

That is one hell of a way to do it! I'm also on phone now and cannot reply in length as I wish but will try it out!

Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites

Is this assumption correct that your addon/system should be very generic not just specific to your mission/game mode?

If so, it needs to account for dynamically added and removed units, as well as groups. You probably do this already,

but MDCCLXXVI concept did not - being just a concept no problem there.

Next thing is if you only want to check distance to the leader of the group, or to each individual unit.

Like the units can be very much apart while the distance check is done.

Also the question is on the player group/target group side - just account for the leader or each unit.

Next thing is how you want to restore the position of the units once you uncache them - with their

original setup/layout/offset, or just some generic one. Also keep in mind again spread out groups.

Also is the distance check for uncaching done just on the leaders position, or do you take also the offset

into consideration for the hidden units - also same story as above for the target leader and its units.

Instead of running a FSM per group, you probably should add them all to an array and have this one array

do the checks. Aka not multiple concurrent loops/checks, but one central system.

Now you can also play how often the whole set of groups should be checked and if and what delay you want

to add between checking each group.

Overall a cycle refersh rate of a second or even slower should be OK - you could also regulate the frequency

per unit type and the usual or actual travel speed (infantry = slow, vehicles = medium, air units = fast),

as well as the caching distance (for longer distances a slower frequency doesnt matter much, while for close

distance you may get the units to dis-/appear within sight or combat distance.

Share this post


Link to post
Share on other sites

One thing to check with your original condition is whether the count approach, or a standard loop combined with exitWith

on first unit within distance is faster.

Another approach could be nearestObject - however I am doubtful that its faster.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×