LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to achieve consistent 60fps in GUI?

I set the loop time of my GUI to 16 ms, which should equal 60 fps if you do the math (1000 ms/60 = 16,67). However, I can't get stable 16 ms. It's jumping between 16 and 18 ms, causing all charts to stutter. Is there anything I could do to mitigate this?

 

Running on PC, not using property nodes.

 

Not60FPS.PNG

 

0 Kudos
Message 1 of 5
(290 Views)

Windows (assumed you using this OS) is not Real-Time Operating System, so you always will have time deviations in loops iterations, this is normal by design. Please show your "benchmark" code, may be there are some point where it can be improved, but you will never ever get absolutely "stable" timing like in pure Real-Time environment (PLC or LabVIEW RealTime/FPGA). In additional, Wiat (ms) as well as GetTickCount related to Windows Timer, which have resolution 1 ms (LabVIEW will set it for you, by default it is 15,625 ms because 1000 ms divided by 64). In theory you can get more or less stable 60 FPS using IMAQ Wind Draw with IMAQ WindNoTearing VI, in this case GUI refresh will be synchronized with VSync signal from monitor, therefore you will get stable (more or less) 60 Hz but this is very specific case.

0 Kudos
Message 2 of 5
(278 Views)

@UL-00 wrote:

I set the loop time of my GUI to 16 ms, which should equal 60 fps if you do the math (1000 ms/60 = 16,67). However, I can't get stable 16 ms. It's jumping between 16 and 18 ms, causing all charts to stutter. Is there anything I could do to mitigate this?


First of all, a 16ms loop runs at 62.5Hz, not 60Hz.

 

A chart that is updating between 16 and 18ms will not "stutter", whatever you mean by that. The UI is updated asynchronously in the UI thread, so if you have greedy loops and unreasonable amounts of data on the front panel, the UI thread might get starved. You cannot tell the FP update rate from the loop rate of your toplevel loop. That depends on UI thread scheduling, which can be different. Are you using a plain loop with a wait or a timed loop? If the loop rate is more important the FP update, it should maybe not contain a chart.

 

If you want the chart to update with the loop rate, set it to "synchronous", but you'll get a serious performance hit. Don't do it! Did you change any priority settings? If you increase priority, the UI thread will get even less predictable, so please leave it at the default!

 

How big is your chart history? How many traces? What update mode? What style? Single lines or thick lines with fancy points? Autoscaling axes or not?

What else is this loop doing?

What problem are you trying to solve?

Even movies have only a frame rate of 24fps.

What is the refresh rate of your monitor?

 

It almost seems like you want to micromanage details that are not really important. Windows is not a realtime OS. (Assuming windows, because you have not mentioned the OS. A realtime OS most often does not have an UI)

 

Why is exact timing so important? Are you doing single point software-timed data acquisition instead of using hardware timing? What hardware are you using?

0 Kudos
Message 3 of 5
(220 Views)

Thanks for your two responses. I think you're right that I'm trying to overengineer a minor issue. I'll leave it the way it is.

 

Just for the sake of completeness:

- My method for measuring the loop time is attached

- Using Windows 

- Thanks for suggesting IMAQ Wind. As you say, it's probably overkill to implement this.

- My chart histories are between 10000 and 100000 entries (I know it's a lot) but this had no impact. The stutter also occurs at very low histories (1024 etc.)

 

0 Kudos
Message 4 of 5
(177 Views)

@UL-00 wrote:

Thanks for your two responses. I think you're right that I'm trying to overengineer a minor issue. I'll leave it the way it is.

 

Just for the sake of completeness:

- My method for measuring the loop time is attached

- Using Windows 

- Thanks for suggesting IMAQ Wind. As you say, it's probably overkill to implement this.

- My chart histories are between 10000 and 100000 entries (I know it's a lot) but this had no impact. The stutter also occurs at very low histories (1024 etc.)

 


Still not sure about your use case behind, but probably you trying to achieve your "60 FPS" cycle with simple Wait (ms) function, something like this:

Snippet1.png

Now if you will measure exact sleep time (more or less exact, we're not in RealTime OS and please use High Res Seconds function instead of Tick Count ms), then something like that will be observed:

Screenshot 2024-05-07 12.31.10.png

As stated in Help, Wait(ms) may give you real sleep 1 ms less than requested, but also you see a lot of spikes between 16 and 18 ms. It is so, because Wait (ms) uses standard Windows Timer, which have in LabVIEW 1 ms resolution. By the way, the default value of this timer is 15.625 ms (1,000 ms divided by 64), but LabVIEW will set it to 1 ms for you.

You can easily check this by calling powercfg -energy command from Administrator command prompt, then take a look into energy-report.html, and you will see it:

 

Platform Timer Resolution:Outstanding Timer Request
A program or service has requested a timer resolution smaller than the platform maximum timer resolution.
Requested Period	10000
Requesting Process Path	\Device\HarddiskVolume5\Program Files\National Instruments\LabVIEW 2024\LabVIEW.exe

 

Requested period 10000 is exactly 1 ms (measured in 100-nanosecond units). If LabVIEW will do not do this, and leave default then if you call Wait (ms) with 1 ms (like Sleep(1)) at some random time then you will probably be woken sometime between 1 ms and 16,625 ms in the future, whenever the next interrupt fires.

The smallest finest resolution is 0,5 ms (and theoretically you can set it), and yes, this will slightly improve your result, but not significantly.

If you would like to get better accuracy, then instead of Wait (ms) you can use High Res Polling Wait:

snippet2.png

Then results will be much more accurate:

Screenshot 2024-05-07 12.28.25.png

Here we still have some spikes, but overall deviation much smaller. But again, if you will have lot of parallel threads, and in additional background OS activities, then real "sleep" time may vary more and more. And you will get higher CPU load with this, which also sated in Help: "Unlike the Wait (ms) function, if the number of seconds you specify is 0, this VI does not force the current thread to yield control of the CPU. Use this VI with caution if you are concerned about high CPU loads: this VI may use polling to achieve high timing resolution for all or a portion of the wait time.".

 

Message 5 of 5
(162 Views)