CALL or SPAWN, this is here the question :)

fred41

Member
SPAWN and CALL, two different ways to start the execution of script code.

CALL: The fast, resource saving, serial way.
If we use CALL to execute a piece of code, we ensure that the script is running as fast as currently possible. This is the prefered way to execute our code with less resource consumption at all.


SPAWN: The slow, parallel way.
When we are forced to use SPAWN instead of CALL?
There are only two reasons to prefer SPAWN.
1. If we can't avoid the use of SLEEP or WAITUNTIL to ensure a specific timing.
2. If the calling code cant wait for termination of the called code, because the called code contains very large loops (>10000) or the called code produce other large delays by waiting for external returns (>100ms).

If we cant avoid the use of SPAWN, we have to ensure that we never risk a situation, where our SPAWNed scripts are ACCUMULATED to much.
Accumulation occurs, if the execution time of our script is larger then the calling period.
For example we have a script which is SPAWNed every second, but the execution time of this script on a loaded server is 3 seconds (execution times depends on load and can be many minutes). This means the number of concurrently running scripts will increase permanently. And the secondary effect is, that the execution time of the same script increases too (our timing will be not as expected).
And we have to realize, that all other SPAWNed scripts currently running are slowed down significantly (timing broken), if such accumulation occurs.

CONCLUSION:
Generally, the periodical and/or frequently use of SPAWN is critical (especially on servers), we should prefer using CALL where ever possible!!!

Thats all, thanks for your attention :)
 
Tell it to Rocket lol. There are a lot of spawn calls from fsm scripts that execute twice a sec as I understand?

True, it seems rocket did'nt used this both in an optimal way,
and i remember there was a good example for wrong use of SPAWN:

... millions of people, sitting millions of hours on a black screen ... :D

I think we should not wait to check and to purify the current code from this missfortune.
 
So let me understand this.... as a 'call' can be precompiled, you reduce the thread count which leans up resources? So the slow load time is from all of players running asynchronous spawn calls?
 
So let me understand this.... as a 'call' can be precompiled, you reduce the thread count which leans up resources? So the slow load time is from all of players running asynchronous spawn calls?

1. Aspect:
Precompiling is an other thing.
Precompiled code can be executed much faster at all, because the engine doesn't have to recompile for each execution.
So precompiling is highly recommended for ALL code executed more then ONCE (99.9% of all code).

2. Aspect:
Correct.
The old way to execute phase 1 of player login process (just for example):
Code:
"dayzLogin" addPublicVariableEventHandler {(_this select 1) SPAWN server_playerLogin};
creates a pseudo thread (each per event), which runs in the low priority (scheduled) environment and execution time depends much on server load (number of SPAWNed scripts already running concurrently).

The faster way:
Code:
"dayzLogin" addPublicVariableEventHandler {(_this select 1) CALL server_playerLogin};
DOESN'T create a pseudo thread and runs in the non scheduled environment with the currently fastest speed, script code can run.

***SPAWNed EH code will always run slower, as CALLed EH code will.***
***If there are many already running SPAWNed scripts (Accumulation), our SPAWNed code will run very much slower.***

On a heavy loaded test server, i observed the following (with the help of my profiler):
A specific test script, which is running a few minutes executed per SPAWN, needs only 0.1 ms when it is executed per CALL!!!


(Just to avoid misunderstandings; we are talking here mainly about code executed on server and orginating in Eventhandlers. Even if the same rules are valid on clients, so are clients normally not that critical.)

hope it was understandable, even if my english is not the best :rolleyes:
 
Code:
_somefunc = {
  private ["_counter","_timer"];
  _timer = diag_tickTime;
  _counter = 0;
  for "_i" from 1 to 1000 do {
    _counter = _counter+1;
  };
diag_log format["DEBUG: loop - %1 [%2]",_counter, diag_tickTime-_timer];
};
 
_timer = diag_tickTime;
call _somefunc;
diag_log ("DEBUG:  call - " + str(diag_tickTime-_timer));
 
_timer = diag_tickTime;
_id = [] spawn _somefunc;
waitUntil {scriptDone _id};
diag_log ("DEBUG: spawn - " + str(diag_tickTime-_timer));
results from 5 run:
Code:
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG:  call - 0.00201416"
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG: spawn - 0.0310059"
"==="
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG:  call - 0.00201416"
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG: spawn - 0.0319824"
"==="
"DEBUG: loop - 1000 [0.00299072]"
"DEBUG:  call - 0.00299072"
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG: spawn - 0.0310059"
"==="
"DEBUG: loop - 1000 [0.00305176]"
"DEBUG:  call - 0.00305176"
"DEBUG: loop - 1000 [0.00195313]"
"DEBUG: spawn - 0.0289917"
"==="
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG:  call - 0.00201416"
"DEBUG: loop - 1000 [0.00201416]"
"DEBUG: spawn - 0.0319824"
how to decide, what is faster? (waitUntil ended with little delay)
 
f0rt, i guess you got this results on an empty test server ...

To get real results, we have to realize, that our spawned scripts are running in a scheduled environment,
concurrently with many other scripts.
Let me expand your code so that you understand what i mean (not ready to run):

Code:
_somefunc = {
  private ["_counter","_timer"];
  _timer = diag_tickTime;
  _counter = 0;
  for "_i" from 1 to 5000 do {
    _counter = _counter+1;
  };
diag_log format["DEBUG: loop - %1 [%2]",_counter, diag_tickTime-_timer];
};
 
// ###### just temporarily load begin
_someSpawnedBackGroundLoad = {
  private ["_counter","_timer"];
  _counter = 0;
  for "_i" from 1 to 5000 do {
    _counter = _counter+1;
  };
};
for "_i" from 1 to 5000 do {
  id =  spawn _someSpawnedBackGroundLoad ; // load the sheduler
};
// ###### just temporarily load end
 
// this must be called as Eventhandler, triggered per publicVariableServer from client, for example
CallTestEH = {
_timer = diag_tickTime;
call _somefunc;
diag_log ("DEBUG:  call - " + str(diag_tickTime-_timer));
};
 
// this must be called as Eventhandler, triggered per publicVariableServer from client, for example
SpawnTestEH = {
_timer = diag_tickTime;
_id = [] spawn _somefunc;
waitUntil {scriptDone _id};
diag_log ("DEBUG: spawn - " + str(diag_tickTime-_timer));
};

... try this and let me know your results :)

I wrote a simple "load simulator" (client/server), to stress my test server while testing some code.
So i can check how my code would run on full servers, before i test it on full real live servers.
If you are interested, i can give you the current code lines.
You will find my profiler here: https://github.com/fred41/armaperflib
Not perfect, but working.

Thanks for your reply :)
 
i think i saw it in fsm files
... yep, in server_cleanup.fsm is an example for wrong use of spawn (update_objects) ...

Code:
diag_log format["DEBUG: needUpdate_objects=%1",needUpdate_objects];
{
//    _x setVariable ["needUpdate",false,true];
    needUpdate_objects = needUpdate_objects - [_x];
    [_x,"all"] spawn server_updateObject;  // this should be CALLed
 
} forEach needUpdate_objects;

On a client such a construct is not a problem, on heavy loaded server it is really bad !!!!
 
....
I wrote a simple "load simulator" (client/server), to stress my test server while testing some code.
So i can check how my code would run on full servers, before i test it on full real live servers.
If you are interested, i can give you the current code lines.
You will find my profiler here: https://github.com/fred41/armaperflib
Not up to date, but working.

Thanks for your reply :)

This is great, there must be a sticky with all the utils like this, pbo viewer, textures editor, etc.
 
f0rt, i guess you got this results on an empty test server ...
yes, you right.
... try this and let me know your results :)
this code is not work. i rewrite it:
Code:
somefunc = {
  private ["_counter","_timer"];
  _timer = diag_tickTime;
  _counter = 0;
  for "_i" from 1 to 1000 do {
    _counter = _counter+1;
  };
diag_log format["DEBUG: %1 - %2 [%3]",_this,_counter, diag_tickTime-_timer];
};
 
BackGroundLoad = {
  private ["_counter","_timer"];
  diag_log ("Scheduler started - " + str(_this));
  _counter = 0;
  for "_i" from 1 to 5000 do {
    _counter = _counter+1;
  };
  diag_log ("Scheduler ended - " + str(_this));
};
 
Load = {
diag_log "scheduler load begin";
for "_i" from 1 to 5000 do {
_id = _i spawn BackGroundLoad; // load the sheduler
};
diag_log "scheduler load finished";
};
CallTest = {
private ["_timer"];
_timer = diag_tickTime;
"call" call somefunc;
diag_log ("DEBUG:  call - " + str(diag_tickTime-_timer));
};
SpawnTest = {
private ["_timer","_id"];
_timer = diag_tickTime;
_id = "spawn" spawn somefunc;
waitUntil {scriptDone _id};
diag_log ("DEBUG: spawn - " + str(diag_tickTime-_timer));
};
 
"LoadScheduler"addPublicVariableEventHandler { (_this select 1) spawn Load; };
"CallTestEH"addPublicVariableEventHandler { (_this select 1) call CallTest; };
"SpawnTestEH"addPublicVariableEventHandler { (_this select 1) spawn SpawnTest; };
results is very interesting.

1. on my server (virtualBox 4.2.4) arma2 can run ~740 "spawn" - rapidly, after that wait when running thread ended and spawn ~240 for nexts.
2. from "Scheduler started - #" to same "Scheduler ended - #" - about 5-8 mins.
3. on empty server "spawn Load" from start to last end - took about 18 mins.
4. when Load running - relogon delayed:
Code:
2012/11/23,  9:49:18 "DISCONNECT: f0rt (18109702) Object: B 1-1-B:1 (f0rt) REMOTE, _characterID: 20494"
...
2012/11/23,  9:50:14 "STARTING LOGIN: ["18109702",B 1-1-A:1 (f0rt) REMOTE]"
5. when Load running - SpawnTest run:
Code:
2012/11/23,  9:36:55 "DEBUG: spawn - 1000 [43.254]"
2012/11/23,  9:36:55 "DEBUG: spawn - 58.691"
...
2012/11/23,  9:45:45 "DEBUG: spawn - 1000 [102.39]"
2012/11/23,  9:45:45 "DEBUG: spawn - 150.51"
and with 3-4 min delay.
6. call results with running "scheduler"
Code:
2012/11/23, 10:00:00 "DEBUG: call - 1000 [0.000976563]"
2012/11/23, 10:00:00 "DEBUG:  call - 0.000976563"
results without runing "scheduler"
Code:
2012/11/23,  9:32:21 "DEBUG: call - 1000 [0.000999451]"
2012/11/23,  9:32:21 "DEBUG:  call - 0.000999451"
2012/11/23,  9:32:21 "DEBUG: spawn - 1000 [0.0410004]"
2012/11/23,  9:32:21 "DEBUG: spawn - 0.0760002"
2012/11/23,  9:32:24 "DEBUG: call - 1000 [0.000999451]"
2012/11/23,  9:32:24 "DEBUG:  call - 0.000999451"
2012/11/23,  9:32:24 "DEBUG: spawn - 1000 [0.0219994]"
2012/11/23,  9:32:24 "DEBUG: spawn - 0.0579987"
2012/11/23,  9:32:25 "DEBUG: call - 1000 [0.000999451]"
2012/11/23,  9:32:25 "DEBUG:  call - 0.000999451"
2012/11/23,  9:32:25 "DEBUG: spawn - 1000 [0.0420036]"
2012/11/23,  9:32:25 "DEBUG: spawn - 0.0789986"
2012/11/23,  9:32:27 "DEBUG: call - 1000 [0.000999451]"
2012/11/23,  9:32:27 "DEBUG:  call - 0.000999451"
2012/11/23,  9:32:27 "DEBUG: spawn - 1000 [0.0410004]"
2012/11/23,  9:32:27 "DEBUG: spawn - 0.0780029"
2012/11/23,  9:32:28 "DEBUG: call - 1000 [0.000999451]"
2012/11/23,  9:32:28 "DEBUG:  call - 0.000999451"
2012/11/23,  9:32:28 "DEBUG: spawn - 1000 [0.0229988]"
2012/11/23,  9:32:28 "DEBUG: spawn - 0.0590019"

conclusion:
you DAMN right.
 
conclusion:
you DAMN right.

... good work, now we are at least 3 people here, gotcha that stuff ... ;)

you could load your scheduler much harder with this:
Code:
"LoadScheduler" addPublicVariableEventHandler { (_this select 1) CALL Load; };
If you SPAWN here, the scheduler is still "relaxed", because he is loaded much slower/less.
Try it out you will get more considerably results.

BTW: I think, many "heavy load issues" in current dayz are related to this "spawn/execVM on servers eventhandlers" stuff and i am confident, that we will find and replace the code responsible for that issues soon.
 
Looking at RPT after 4 hours of 25 people getting contantly killed loging in out the server starts queuing messages spawn takes ages. I have few scripts that rely on spawn and they just don't get executed in time. What is going to happen with 50 people?
 
Back
Top