Jump to content
Leopard20

Using "sleep" - How to account for low FPS?

Recommended Posts

Hi.

 

Currently I have a problem with one of my scripts. It uses "sleep" in lots of places (mostly short duration ones, from 0.01 to 0.1). The problem is that when I run a script-heavy mission and my FPS falls below 30, the sleep times do not work very well (e.g I'm using sleep 0.01 but it's too long when FPS is low, so it's like the "actual" sleep time is 0.1 or something)

How can I account for this engine behavior?

 

I'm personally thinking of something like this but I'm wondering if it's effective?

sleep 0.01*(diag_fps/60 min 1)

What I mean is that I want the sleep time to be shortened when FPS is lower than 60 otherwise remain the same.

Share this post


Link to post
Share on other sites

Update: OK I tested it myself and it doesn't work. Any suggestions?

Share this post


Link to post
Share on other sites

Nevermind. Found a way! Using uiSleep accounts for lag as well.

Share this post


Link to post
Share on other sites
8 hours ago, Leopard20 said:

Hi.

 

Currently I have a problem with one of my scripts. It uses "sleep" in lots of places (mostly short duration ones, from 0.01 to 0.1). The problem is that when I run a script-heavy mission and my FPS falls below 30, the sleep times do not work very well (e.g I'm using sleep 0.01 but it's too long when FPS is low, so it's like the "actual" sleep time is 0.1 or something)

How can I account for this engine behavior?

 

I'm personally thinking of something like this but I'm wondering if it's effective?


sleep 0.01*(diag_fps/60 min 1)

What I mean is that I want the sleep time to be shortened when FPS is lower than 60 otherwise remain the same.

 

How about tackling the scripts that are causing that fps drop in the first place?

 

Cheers

  • Like 1

Share this post


Link to post
Share on other sites
26 minutes ago, Grumpy Old Man said:

 

How about tackling the scripts that are causing that fps drop in the first place?

 

Cheers

I was talking about a pre-made mission not my own! ;)

I'm using said script in my mod. It's not at all problematic either! Thanks for the tip anyway.

Share this post


Link to post
Share on other sites

if you are using short sleeps consider using call for unscheduled work

Share this post


Link to post
Share on other sites
39 minutes ago, Leopard20 said:

I was talking about a pre-made mission not my own! ;)

I'm using said script in my mod. It's not at all problematic either! Thanks for the tip anyway.

time to rewrite it then lol

  • Haha 2

Share this post


Link to post
Share on other sites
13 minutes ago, fycj said:

if you are using short sleeps consider using call for unscheduled work

The script is a bit long and in a while loop. If used without sleep it would cause massive CPU usage. Trust me I've tried! My laptop fan goes extremely loud when I do that! ;) 

Share this post


Link to post
Share on other sites
20 minutes ago, gokitty1199 said:

time to rewrite it then lol

It's actually a famous mission: OPEX (Opérations Extérieures) Plus the author is still working on it. So I'll just give him a feedback! It'll save me some time! LOL

Share this post


Link to post
Share on other sites
48 minutes ago, atmo said:

Things like the engine will try to do a {} forEach section in one frame

Where did you read that? It's wrong and it's not on that wiki page.

 

On 12.8.2018 at 10:31 AM, Leopard20 said:

How can I account for this engine behavior?

You can't actually.

 

On 12.8.2018 at 10:31 AM, Leopard20 said:

I'm using sleep 0.01 but it's too long when FPS is low, so it's like the "actual" sleep time is 0.1 or something

0.01 are 10 mill.seconds. at 30fps one single frame is 33,3 milliseconds. Scheduled scripts only execute once per frame. So you cannot do anything to run scheduled scripts faster.

With unscheduled you could run scripts in EachFrame and Draw eventhandlers. The EachFrame is near the front of the frame and the Draw EH is near the end.

  • Like 2

Share this post


Link to post
Share on other sites
2 hours ago, Dedmen said:

Where did you read that? It's wrong and it's not on that wiki page.

 

You can't actually.

 

0.01 are 10 mill.seconds. at 30fps one single frame is 33,3 milliseconds. Scheduled scripts only execute once per frame. So you cannot do anything to run scheduled scripts faster.

With unscheduled you could run scripts in EachFrame and Draw eventhandlers. The EachFrame is near the front of the frame and the Draw EH is near the end.

Wow. Thanks! It's really helpful!

Share this post


Link to post
Share on other sites
6 hours ago, Dedmen said:
7 hours ago, atmo said:

Things like the engine will try to do a {} forEach section in one frame

Where did you read that? It's wrong and it's not on that wiki page.

 

Well, you've called me out on it. I am sure I read this buried somewhere and it surprised me so much, as I knew waitUnitl {} did so, but not {} forEach. I may have erroneously remembered it, but I really can't find it right now. I will drop the claim, until I find the quote. 

Share this post


Link to post
Share on other sites
3 hours ago, dave_beastttt said:

sleep uses diag tick time, uiSleep uses realtime

Wrong ;)
diag_tickTime is realtime (in reference to game start time).

sleep uses simulation time. Aka "time" script command. Which gets paused when the mission is paused.
uiSleep also isn't realtime. It uses uiTime. Which is also simulated (incremented by deltaT every frame)

  • Like 4

Share this post


Link to post
Share on other sites

BTW, I just discovered that "waitUntil" performs only one computations per frame (if used without sleep), but "while" can make several computations on each frame. However, I think waitUntil is of lower priority than Draw and OnEachFrame, so it might miss a few frames if the engine is busy.

 

Hope it's useful to others!

Share this post


Link to post
Share on other sites

Need some conditions checked faster than onEachFrame? (depending on FPS), or even a looped code?

 

Test: this addAction ["",{},[],1.5,true,true,"","hint str diag_tickTime;true"];

 

working like an "onEachFrame" EH but not limited to one check per frame.

Here, there is no action on menu and the condition field works like the looped code. Must end by a true boolean.

  • Like 2

Share this post


Link to post
Share on other sites
14 hours ago, Leopard20 said:

However, I think waitUntil is of lower priority than Draw and OnEachFrame, so it might miss a few frames if the engine is busy.

scheduled vs unscheduled. There is no "priority" here. Draw3D and OnEachFrame execute every frame.

scheduled scripts execute for 3ms every frame, if your script doesn't get executed it get's pushed to the next frame, where it also might not be executed.

There is no guarantee about when a scheduled script executes next time. Might be as low as a single frame. Might also be as high as a couple hours (theoretically).

More about that -> http://sqf.ovh/ite/2018/01/21/ITE-the-scheduler.html

 

6 hours ago, pierremgi said:

working like an "onEachFrame" EH but not limited to one check per frame.

Where does it check that condition then? There is only a single simulation cycle per frame.

  • Like 1

Share this post


Link to post
Share on other sites
4 hours ago, Dedmen said:

scheduled vs unscheduled. There is no "priority" here. Draw3D and OnEachFrame execute every frame.

scheduled scripts execute for 3ms every frame, if your script doesn't get executed it get's pushed to the next frame, where it also might not be executed.

There is no guarantee about when a scheduled script executes next time. Might be as low as a single frame. Might also be as high as a couple hours (theoretically).

More about that -> http://sqf.ovh/ite/2018/01/21/ITE-the-scheduler.html

 

Where does it check that condition then? There is only a single simulation cycle per frame.

 

If I'm right, perhaps i missed something, the  scheduler is mandatory for all processes, scheduled or not, main or parallel. BUT the 3ms slot is the same limitation for all scheduled (every frame). The scheduler will just ignore this limitation (and any sleep) for non-scheduled one. On the other hand, any loop will be limited up to 10,000 iterations.

Anyway, that doesn't mean you can't repeat a quick code several time inside a frame (scheduled or not). If you loop (with no delay or 0.01 sec) a condition and a tiny code, you will run it several times a frame.

I guess the addAction condition code is checked as a fast loop, no matter the frame.

 

With that idea, i wrote with success, a code to add an action for any gunner (player of course) in any vehicle with turret (Hellcat, Hunter HMG...), which allows a search light controlled by the weapon direction.


 

Spoiler

 

0 = [] spawn {
//////////////////   the interesting part here. This "_check" is inside the addAction (normal condition to make the addAction visible + the update of the spotlight position)

  _check = "
    if (local (_target turretUnit [0])) then {
      private _ins = lineIntersectsSurfaces [AGLToASL positionCameraToWorld [0,0,5],AGLToASL positionCameraToWorld [0,0,300],_target,objNull,true,1,'FIRE','NONE'];
      if (count _ins > 0) then {
        _target setVariable ['SLpos',(_ins select 0 select 0),true];
      } else {
        _target setVariable ['SLpos',AGLToASL positionCameraToWorld [0,0,300],true]
      };
    };
    (missionNamespace getVariable 'SL'+str(_target)) setPosASL (_target getVariable ['SLpos',[0,0,300]]);
    (_this == _target turretUnit [0]) && local _this
  ";

///////////////////////////////////

  while {true} do {
    {
      _x setVariable ["spotted",true];
      _x addAction ["<t color='#11ff11'>S.L. On</t>", {
        params ["_veh","_gunner","_id","_check"];
        private _SLMenu = (_veh actionParams _id) select 0;
        private _SL = "SL"+str(_veh);
        if (_SLMenu isEqualTo "<t color='#11ff11'>S.L. On</t>") then {
          _SLMenu = "<t color='#ff1111'>S.L. Off</t>";
          _gunner action ["SearchlightOn",_veh];
          missionNamespace setVariable [_SL,"#lightpoint" createVehicle [0,0,0],true];
          [_SL,{(missionNamespace getVariable _this) setLightBrightness 0.9;
          (missionNamespace getVariable _this) setLightAmbient [2.3, 2.3, 2.55];
          (missionNamespace getVariable _this) setLightColor [230, 230, 255];
          (missionNamespace getVariable _this) setLightUseFlare  true;
          (missionNamespace getVariable _this) setLightAttenuation [3,50,80,50,0,50];
          (missionNamespace getVariable _this) setLightFlareSize 50}] remoteExec ["call",0,_veh];
        } else {
          _SLMenu = "<t color='#11ff11'>S.L. On</t>";
          _gunner action ["SearchlightOff", _veh];
          deleteVehicle (missionNamespace getVariable _SL);
        };
        _veh setUserActionText [_id,_SLMenu];
      },_check,0.8,false,true,"",_check];
    } forEach (vehicles select {!(_x getVariable ["spotted",false]) && {["Turret",[0,1]] in (_x call BIS_fnc_vehicleRoles) or ["Turret",[0]] in (_x call BIS_fnc_vehicleRoles)}});

    {
      if (!alive _x) then {_x setVariable ["spotted",false]; removeAllActions _x};
      if (!isNil {missionNamespace getVariable 'SL'+str(_x)} && !alive _x) then {
        deleteVehicle (missionNamespace getVariable 'SL'+str(_x));
        missionNamespace setVariable ['SL'+str(_x),nil,true];
      }
    } forEach (vehicles  select {_x getVariable ["spotted",false]});

    sleep 3;
  }
};

 

 

No flickering.

Share this post


Link to post
Share on other sites
2 hours ago, pierremgi said:

the  scheduler is mandatory for all processes, scheduled or not, main or parallel

No. Unscheduled scripts don't run in the scheduler. That's why they are called unscheduled.

 

2 hours ago, pierremgi said:

 

No flickering.

No flickering means it's executed atleast once per frame. OnEachFrame and Draw3D do that. But I never hear of addAction executing multiple times, and it also wouldn't make any sense for it to do that.

  • Like 1

Share this post


Link to post
Share on other sites
51 minutes ago, Dedmen said:

But I never hear of addAction executing multiple times, and it also wouldn't make any sense for it to do that.

 

addAction condition is evaluated once each frame, easy test:

player addAction ["",{},[],0,false,false,"","diag_log diag_frameno;true"]; 

//prints the following inside the .rpt:
21:19:17 6061
21:19:17 6062
21:19:17 6063
21:19:17 6064
21:19:17 6065
21:19:17 6066
21:19:17 6067
21:19:17 6068
21:19:17 6069
21:19:17 6070
21:19:17 6071
21:19:17 6072
21:19:17 6073
21:19:17 6074
21:19:17 6075
21:19:17 6076
21:19:17 6077
21:19:17 6078
21:19:17 6079
21:19:17 6080
21:19:17 6081
21:19:17 6082
21:19:17 6083
21:19:17 6084
21:19:17 6085
21:19:17 6086
21:19:17 6087
21:19:17 6088
21:19:17 6089
21:19:17 6090
21:19:17 6091
21:19:18 6092

Cheers

  • Like 1
  • Thanks 2

Share this post


Link to post
Share on other sites
2 hours ago, Dedmen said:

No. Unscheduled scripts don't run in the scheduler. That's why they are called unscheduled.

 

 

Never mind. I thought it was a little bit more complicated if I understood some tips about that. Scheduler is the core of the engine. Unscheduled just means not limited by a 3 ms slot. You can't have a scheduler for scheduled code (all sqf...) and an independent core engine for unscheduled ones (some sqs, call,...). Of course there is a global "management" for all codes and that's the scheduler, even if there is no slot time limitation (specific treatment) for unscheduled.

But, this terminology, if I'm right, doesn't change the life. Just interesting topic, imho, and it's hard to read something very precise, even in BIKI about that. Let's say there will be more debate about what to do with or without scheduled/waiting scripting. At least two schools, pros/cons the scheduling. Not sure the ACE3 approach is "friendly" for any case. It seems to me it gives "priority" to ACE3 codes, then, never mind the other ones.

 

Share this post


Link to post
Share on other sites
7 hours ago, pierremgi said:

It seems to me it gives "priority" to ACE3 codes

As I said no priority. Every unscheduled script is executed. What you could mean by "priority" here is that if ACE's scripts are slow, they lower your FPS instead of just "scheduling" till the next frame. But to prevent that we make extensive use of my Profiler.

And it's also intended like this. No one wants to wait a minute after a button press for something to happen.

Which.. Is actually exactly what the top post here was about:

On 12.8.2018 at 10:31 AM, Leopard20 said:

e.g I'm using sleep 0.01 but it's too long when FPS is low, so it's like the "actual" sleep time is 0.1 or something

 

Here is a little writeup about what the scheduler does on the technical side and what it's problems are: http://sqf.ovh/ite/2018/01/21/ITE-the-scheduler.html

  • Like 2

Share this post


Link to post
Share on other sites

@Dedmen

Thank you very much for your help!

 

I rewrote my mod codes and ditched all while and waitUntil for stacked "onEachFrame" event handlers. Now the code runs fluently, even at extremely low FPS! What's really strange is that I don't notice much difference in CPU consumption! Why didn't I do this before?! ;)

 

Just one thing: I assume it's OK to remove and add stacked EHs multiple times, right? (Based on our previous discussion:

)

BTW, if I add a new stacked EH having the same ID as the previous one, does the old one get replaced with the new one? (right now I'm assuming yes!)

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

×