Benchmarking time spent in beat functions, 'avatar update' is very expensive

I've been looking into benchmarking the performance cost of different ui mods, and made a minimal ui mod for this purpose.
('OnBeatTimings', uploaded to the mod vault.)

This tells you how long is being spent in UI 'beat functions', on average. (Not the total performance cost of UI mods, in all situations, but something which I think is significant, and which can be measured quite easily.)

To use this, run FAF windowed, open the log viewer and console, set up a benchmark situation, leave it to run for a bit (10 seconds or so) and then enter the following in the console:

UI_Lua import("/lua/ui/game/gamemain.lua").AverageOnBeatTime()

This tells you the average time spent in beat functions which are not flagged as 'throttled', per update.
You can also get the average time spent in 'throttled' beat functions, with:

UI_Lua import("/lua/ui/game/gamemain.lua").AverageOnBeatTime(true)

Note that these timings include time spent in built-in beat functions, as well as beat functions in mods you have enabled, but you can disabled and enable mods and see how this affects the timings.

To quickly set up a benchmark situation, I suggest enabling cheats and then using the copy and paste units thing. (So set up a situation with a load of units placed one time. Select the units. Hit ctrl-shift-C to copy placement script for these units. Paste that into a text editor. To place the units back into game for future benchmarking copy the buffer out of your text editor and then ctrl-shift-V in game.)

When looking into the timings coming out of this I found that one built-in beat function in particular, for 'avatar update', was taking a disproportionate amount of the time spent in situations I was benchmarking.

'Avatar update' is for the ui elements normally towards the top right of the screen that show things like ACU health and shield, number of idle engineers, and so on.

I made another 'micro mod', then, to simply remove this update function. ('DisableAvatarUpdate', also uploaded to the vault.) With this mod installed and enabled, the avatars no longer get updated, so no longer work correctly, but this enables us to quickly check the cost of this beat function, and also enables you to reduce your total UI beat function overhead quite significantly, if you are so inclined.

If anyone is interested:

  • Have a go and see if you can repeat my findings (e.g. benchmarking beat function times with and without DisableAvatarUpdate enabled)
  • Check the beat function cost of other ui mods you have installed (if there are significant performance costs for running popular UI mods then it would be good for people to know this)

When you test the beats from the Ui did you remove the UI beat throttling system from FAF ?
https://github.com/FAForever/fa/blob/deploy/fafdevelop/lua/ui/game/gamemain.lua#L650

This function is removed (destructive hook) in my AI mod.
This is fixing the issue with odd numbers (0 income) inside the mini economic window:
https://github.com/Uveso/AI-Uveso/blob/master/hook/lua/ui/game/gamemain.lua#L21

So if player test this with my AI then there is no throttle flag/function.
In case you get issues/bug reports.

Ok @uveso, thanks for the heads up!

OnBeatTimings measures separate times for throttled and non-throttled beat functions, which also requires, as you say, destructive hooking of the OnBeat() function in gamemain.lua. This then means that there's effectively a conflict between the hooking in the OnBeatTimings and AI-Uveso mods.

(If these mods are both enabled, then I guess that, depending on the order in which hooks are applied, either the timings will all be shown as zero, or timings will be shown but the issue you were seeing with odd numbers in the mini economic window will come back.)

It's pretty straightforward to do the same kind of timings without destructive hooking, however. This could be done by replacing the OnBeat() implementation in OnBeatTimings mod with the following:

local originalOnBeat = OnBeat 
function OnBeat()
    local time = CurrentTime()
    originalOnBeat()
    onBeatTimes[nextOnBeatTime] = CurrentTime() - time
    if nextOnBeatTime == table.getn(onBeatTimes) then
        nextOnBeatTime = 1
    else
        nextOnBeatTime = nextOnBeatTime + 1
    end
end

When the throttling thing is enabled, however, measuring throttled and non-throttled beat functions together makes it much harder to get a clear signal out of this kind of benchmarking, I find, since there is a kind of feedback effect where stuff taking time changes the frequency with which throttled functions are executed, which then also affects the timings...

What does the throttling even a thing?

I’m a shitty 1k Global. Any balance or gameplay suggestions should be understood or taken as such.

Project Head and current Owner/Manager of SCTA Project

Is disabling the avatar updates in anyway noticeable in terms of reduced UI lag or otherwise improved performance?

@crispweed

yes if my mods loads after yours then my mod will overwrite and delete your hook.
In this case your mod simply don't work.

On the other side if your mod is loading last, then everything is fine.
The hook in my mod is only used to fix the econemy_mini window and is not needed for the functionality of my AI-mod.

So we don't need to change the hook, just be sure that both mods are not active while testing beat functions.

Just for info, these are the lines who did not work if the function is not called every beat:
https://github.com/FAForever/fa/blob/deploy/fafdevelop/lua/ui/game/economy.lua#L402
Income per second (incomeSec) is calculated on the base of simFrequency.
In case this function is not called every beat it will produce negative numbers for income.
Those numbers are floored to 0 (zero), thats why you see 0 for income in the eco window as user.

@uveso

If it's just about wanting to prevent your beat function from being skipped, maybe you could just change the following line:

GameMain.AddBeatFunction(_BeatFunction, true)

to

GameMain.AddBeatFunction(_BeatFunction)

The point is that the second parameter to GameMain.AddBeatFunction() says whether the beat function you are adding should be throttled, as I understand.

And then maybe you wouldn't need to destructively hook OnBeat().

(I haven't read all the code involved though, and I could definitely be misunderstanding the situation.)

@giebmasse said in Benchmarking time spent in beat functions, 'avatar update' is very expensive:

Is disabling the avatar updates in anyway noticeable in terms of reduced UI lag or otherwise improved performance?

So I've had issues with lag in the past that seemed to me to be related to beat functions taking too long. This includes an issue with the UI refusing to accept my commands, in certain situations, as well as more general problems with UI responsiveness. I'm pretty sure that reducing time in beat functions has helped a lot with this problem, for me.

It's going to depend on the machine you are playing on, and stuff like that, I guess. And just avatar updates by itself may not be an issue, whereas the time spent in this plus time spent in other UI mods may become an issue, depending on what kind of mods you are using..

@crispweed

i am hooking the beatfunction destructive because i test the function for a gamepatch.
I plan to remove the beat throttling completely from the game. ( i can't see any speedimprovements here on my PC)

In case you have a better solution, then we can patch your code to the game.

Just be sure you don't throttle the eco stuff.

@uveso said in Benchmarking time spent in beat functions, 'avatar update' is very expensive:

@crispweed

i am hooking the beatfunction destructive because i test the function for a gamepatch.
I plan to remove the beat throttling completely from the game. ( i can't see any speedimprovements here on my PC)

OK.

Got to say I did wonder how useful this throttling actually is.

I mean, with the way this is setup, it seems like, as more units get created, and the game slows down, the 'throttled' functions are actually going to be run in more game ticks..

This post is deleted!