Page MenuHomeFeedback Tracker

Eventhandlers are compiled before every execution
Reviewed, NormalPublic

Description

Not a bug but rather an enhancement.
Arma eventhandlers (ctrlAddEventhandler,addMissionEventHandler,onEachFrame,onMapSingleClick,...) Are stored as Strings in the engine and are compiled before every execution.
This causes

addMissionEventHandler ["EachFrame", addon_fnc_onEachFrame];

To recompile the whole addon_fnc_onEachFrame each frame. Which may be a potentially big function which takes long to compile.
If you instead do this:

addMissionEventHandler ["EachFrame", {call addon_fnc_onEachFrame}];

It looks like it would be slower because you have an additional call. But actually this is about 16x or more faster because it only has to compile that small code segment instead of a big file.

Details

Severity
Tweak
Resolution
Open
Reproducibility
Always
Operating System
Windows 7
Category
Scripting
Steps To Reproduce

Function designed to stress compiler

TestingFunction = {
    if (true) exitWith {};
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
    {call { call {call{}}}} forEach variableStuff;
    missionNamespace getVariable ["",{call{call { call {call{}}}} forEach variableStuff;}];
};

execute

removeAllMissionEventHandlers "EachFrame";
for [{_i=0}, {_i<1000}, {_i=_i+1}] do {addMissionEventHandler ["EachFrame", {call TestingFunction}];};

check Framerate. It's not good ofcause because you have 1k EachFrame Eventhandlers.
Now try this

removeAllMissionEventHandlers "EachFrame";
for [{_i=0}, {_i<1000}, {_i=_i+1}] do {addMissionEventHandler ["EachFrame", TestingFunction];};

You still have the same amount of EachFrame Eventhandlers. But check your FPS now.

using diag_captureFrame i got these results

for [{_i=0}, {_i<1000}, {_i=_i+1}] do {addMissionEventHandler ["EachFrame", TestingFunction];}; //~760ms per frame
for [{_i=0}, {_i<1000}, {_i=_i+1}] do {addMissionEventHandler ["EachFrame", {call TestingFunction}];}; // ~47ms per frame

Event Timeline

dedmen created this task.Feb 14 2017, 5:51 AM
dedmen edited Steps To Reproduce. (Show Details)Feb 14 2017, 6:00 AM
Lex added a subscriber: Lex.Feb 14 2017, 2:17 PM
Alwin changed the task status from New to Reviewed.Feb 14 2017, 3:25 PM
bux578 added a subscriber: bux578.Feb 14 2017, 4:43 PM

thanks, we will take look into this

Dscha also checked if the BIS functions were influenced by that and he only found

if (isNil "bis_revive_iconEH") then {bis_revive_iconEH = addMissionEventHandler ["Draw3D",bis_revive_draw];};

Meaning there is atleast this one BIS function that gets a performance penalty because of this.

GBee added a subscriber: GBee.Feb 15 2017, 12:01 PM

Is this for all events (object,display,control) or just stackable mission events?

PiepMGI added a subscriber: PiepMGI.Mar 3 2017, 7:59 PM

Please could you precise how do you pass arguments in such EH as handleDamage, hit or teamSwitch?
for example, I had workable :
player addEventHandler ["HandleDamage",{

_unit = _this select 0;
if (vehicle _unit isKindOf "plane") then {_dam = 0} else {_dam = _this select 2};
_dam

}];
so, i can't find a solution like:
fn_plane = {

_unit = _this select 0;
if (vehicle _unit isKindOf "plane") then {_dam = 0} else {_dam = _this select 2};
_dam

};
player addEventHandler ["HandleDamage", _this call fn_plane];
or
player addEventHandler ["HandleDamage", {_this call fn_plane}];
or anything else.
I miss something but what?
Thanks

dedmen added a comment.Mar 5 2017, 9:13 PM

@PiepMGI Your code is too small to be noticably affected by this issue.

What you want is this

fn_plane = {
params ["_unit","_dam"];
if (vehicle _unit isKindOf "plane") then {_dam = 0};
_dam
};

player addEventHandler ["HandleDamage", {call fn_plane}];

But as I said your code is too small to matter.

Thank you. This topic is very interesting. I have some heavier codes than this one. It was just to understand how are working parameters code inside the EH.

Lex removed a subscriber: Lex.Mar 17 2017, 12:26 PM

Update due to latest changes BIS_fnc_addStackedEventHandler is now also suffering from this on dev-branch. That change looks to be intended like that.
Besides that change also breaks any non-string and non-number argument passed to the StackedEH because someone apparently doesn't understand how format works.
But that's just KK being KK again.

Maybe that get's fixed again before that change is pushed. Probably not though.

BIS_fnc_KK added a subscriber: BIS_fnc_KK.EditedJul 13 2017, 10:44 PM

Make BIS_fnc_addStackedEventHandler great again!

But that's just KK being KK again

Not my fault it is broken ;)

@BIS_fnc_KK Who wrote this then compile format ["%1 call %2", _arguments, _code] ?
You already broke a bit of stuff lately so sorry for defaulting to blame you. I don't see anybody else doing bigger reworks on SQF stuff.

Can confirm that this is broken. This is not the proper way to pass arguments to a function!

PhILoX added a subscriber: PhILoX.Nov 24 2017, 2:15 PM

No updates on this?

oukej added a subscriber: oukej.Jan 29 2019, 4:16 PM

Real needs to be done as suggested, I think.