Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [SOLVED] High CPU usage in idle mode  (Read 9521 times)

0 Members and 1 Guest are viewing this topic.

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
[SOLVED] High CPU usage in idle mode
« on: October 05, 2015, 02:32:11 am »
I found something strange with window behavior.
I'm playing a bit with render loop which gives for about 1100 FPS.
I set VerticalSyncEnabled(true) with expecting that CPU usage will drop down below 1%...
But it is still 30-40%!!!  :o
I'm running application on 4-core processor.
So it means that my application eats 2 cores with 100% load!
WTF?!!

I opened SysInternals Process Explorer and it shows that the main loop eats the first core for 100% and some thread (which most of the time working inside nvidia driver, as I know, such call-stack looks like D3D::Present call) eats the second core for 100%.

So, it seems that SFML actually doesn't use WaitForVBlank and running some kind of spin lock loop with scanning VBlank, isn't it?

How can I fix it? I want to reduce CPU usage with using VBlankSync...

The second issue which I found is that my app hung when I open call-stack in SysInternals Process Explorer.
And it is still in hung state even if I close Process Explorer.
What happens? Some kind of deadlock?
« Last Edit: October 05, 2015, 04:03:19 pm by mkalex777 »

Brax

  • Newbie
  • *
  • Posts: 39
  • Wannabe C++ Game Developer
    • View Profile
Re: High CPU usage in idle mode
« Reply #1 on: October 05, 2015, 03:24:05 am »

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: High CPU usage in idle mode
« Reply #2 on: October 05, 2015, 01:27:45 pm »
I think this will answer your question.

There is no answer. It's just an explanation of VBlankSync flag and I already know it much deeper than it explained in your link.

Using VBlankSync flag in Dircect3D SwapChain::Present function reduces CPU load if it called much faster than physical VBlank event occurs.

For example, if your render time is 1/10 of VBlank period, using VBlankSync will reduce CPU usage for about 10x times. So, one core CPU usage will be for about 10% (or little higher) instead of 100%.

If your render time is 1/1000 of VBlank period (it's the case I'm talking about), using VBlankSync will reduce CPU usage for about 1000 times. So, one core CPU usage will be for about 0,1% (or little higher) instead of 100%.

But the problem is that with SFML it is not reduced and still remains 200% and it doesn't matter if you're using VBlankSync flag or not (in a counterweight to uisng Direct3D, where it is really reduced with VBlankSync enabled).


Actually there are two ways to implement VBlankSync:
1) Using VBlankSync flag, so the call to SwapChain::Present will be blocked until VBlank event will occurs. It's usual way which is used in most of graphics software, especially it must have for windowed mode applications.

2) Using "Spinlock" loop with direct scanning of VBlankSync flag. It's may be used internally inside video driver if an application works in fullscreen mode. Such technique allows to minimize latency time between physical VBlank event and software response (command to swap the buffers).

Spinlock means that CPU executes special opcode "pause". This opcode notifies CPU that he can relax for one cpu cycle and use this time to optimize it's cache, but CPU should NOT switch thread context. So, such instruction prevents CPU to switch thread execution and locks execution in the current thread.
It increases CPU usage, because CPU core cannot do useful work in another thread and continues to execute idle loop which goal is to check physical flag.

Spinlock approach is appropriate technique for fullscreen graphics mode, when application works in exclusive mode.
But it's not appropriate for the case when application works in windowed mode and shares videocard with another applications.

SFML behavior shows that it probably uses spinlock wait in windowed mode (CPU usage testifies it). And it's the problem. Such CPU usage should not happens in windowed mode with VBlankSync enabled.
« Last Edit: October 05, 2015, 01:49:53 pm by mkalex777 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: High CPU usage in idle mode
« Reply #3 on: October 05, 2015, 01:50:32 pm »
So, do you mean that setVerticalSyncEnabled(true) doesn't work as expected? If so, check your graphics driver settings, they can force it to on no matter what you do in your app.

And I have no idea what you're trying to tell us with your low-level technical considerations, SFML just uses the corresponding OpenGL call for v-sync, which is in turn a direct call to the driver.
Laurent Gomila - SFML developer

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: High CPU usage in idle mode
« Reply #4 on: October 05, 2015, 01:56:13 pm »
So, do you mean that setVerticalSyncEnabled(true) doesn't work as expected? If so, check your graphics driver settings, they can force it to on no matter what you do in your app.

And I have no idea what you're trying to tell us with your low-level technical considerations, SFML just uses the corresponding OpenGL call for v-sync, which is in turn a direct call to the driver.

In terms of synchronization it works as expected - buffer swap is really synchronized. But it should reduce CPU usage (at least in windowed mode). But CPU load still remains on 200% (2x CPU core with each 100% load)

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: High CPU usage in idle mode
« Reply #5 on: October 05, 2015, 02:00:17 pm »
And I have no idea what you're trying to tell us with your low-level technical considerations, SFML just uses the corresponding OpenGL call for v-sync, which is in turn a direct call to the driver.

Hm... may be there is a problem with OpenGL implementation. I never worked with OpenGL, but I think it should works in the same way as Direct3D. Isn't it?
Could you please help me to find on how exactly vblank sync is implemented in SFML?

« Last Edit: October 05, 2015, 02:07:32 pm by mkalex777 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: High CPU usage in idle mode
« Reply #6 on: October 05, 2015, 02:04:19 pm »
Quote
In terms of synchronization it works as expected - buffer swap is really synchronized
I may be wrong, but I don't think you can experience screen tearing in windowed mode anyway. So how can you be sure that it is active?
Have you checked your driver settings as I suggested?

Quote
Could you please help me to find on how exactly vblank sync is implemented in SFML?
Follow the call in source code :P
But to be honest, I don't think you need to check the implementation. I can't test right now, but I'm pretty sure that v-sync works as expected in SFML on Windows, even in windowed mode.
Laurent Gomila - SFML developer

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: High CPU usage in idle mode
« Reply #7 on: October 05, 2015, 02:14:33 pm »
I may be wrong, but I don't think you can experience screen tearing in windowed mode anyway. So how can you be sure that it is active?
Have you checked your driver settings as I suggested?

There is no problem with vblank sync in windowed mode. And there is no problem to disable vblank sync in windowed mode and get screen tearing. At least with Direct3D it's true. But I see the same behavior in SFML. When I disable VBlankSyncEnabled, I get screen tearing in windowed mode.

I'm not sure what driver settings you are talking about, but my Direct3D application works with vblank as expected and reduces CPU usage when VBlankSync enabled.

I need to mention that there is no screen tearing in SFML with vblank sync enabled. The problem is that it consumes too much CPU time in windowed mode. It shows that vblank sync in SFML for windowed mode uses bad thread synchronization which burn CPU time in idle loop. Such behavior is appropriate for fullscreen mode only. I'm not sure if it's OpenGL issue or SFML, but the issue definitely exists.

I notice strange short display flicker when I starting SFML application in windowed mode and when I close it. It looks like some kind of change display mode. What happens exactly? I think it may be related to the issue.
« Last Edit: October 05, 2015, 02:24:35 pm by mkalex777 »

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
[SOLVED] Re: High CPU usage in idle mode
« Reply #8 on: October 05, 2015, 03:23:56 pm »
It seems that I found the root of cause  :D

I added call to SetFramerateLimit(0) and now it works as expected - cpu load drops down bellow 1% and some jerks that I seen before with VerticalSyncEnabled disappears! Game works absolutely smooth and with low CPU usage  :D

It's strange I used to think that if I don't touch SetFramerateLimit, then it's should be disabled by default.
But it turns out it is not so.

So, now my init code looks in the following way:
            _window.SetVerticalSyncEnabled(GameSettings.VSync);
            _window.SetFramerateLimit(0);   // <== this call was added to resolve CPU usage issue
 

With vblank disabled it works also as expected - maximum fps (I get for about 1250 fps for empty map renderer, it even higher than it was before - 1100 fps).
I can add that this fix also reduces CPU load from 200% to 100% even with vblank sync disabled!  :D
It's just I was expected!

PS: I think that SetFramerateLimit is useless feature and may be removed to complain with minimalism principle. I have no idea when it needs to be used. At least it should be fixed to be disabled by default to avoid confusion.
« Last Edit: October 05, 2015, 03:32:56 pm by mkalex777 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: High CPU usage in idle mode
« Reply #9 on: October 05, 2015, 03:32:30 pm »
So you don't do as we suggest and wonder why it doesn't work. ::)
Checking your driver settings doesn't mean checking some random applications behavior, it means to open up the control panel of your GPU driver; for AMD that would be called Catalyst.

Additionally you should not be using both VSync and framerate limit.

And last but not least you should limit your framerate. Your monitor's refresh rate is around 60 Hz anyways, so anything above it, is wasted energy.
« Last Edit: October 05, 2015, 03:40:23 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: High CPU usage in idle mode
« Reply #10 on: October 05, 2015, 03:33:10 pm »
Quote
It's strange I used to think that if I don't touch SetFramerateLimit, then it's should be disabled by default.
Yes, should be. I see that you're using SFML.Net, this might be a bug in the binding.
Laurent Gomila - SFML developer

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: High CPU usage in idle mode
« Reply #11 on: October 05, 2015, 03:48:37 pm »
So you don't do as we suggest and wonder why it doesn't work. ::)
Checking your driver settings doesn't mean checking some random applications behavior, it means to open up the control panel of your GPU driver; for AMD that would be called Catalyst.

Additionally you should not be using both VSync and framerate limit. Plus are you using SFML 1.6? Otherwise the function use camelCase spelling.

And last but not least you should limit your framerate. Your monitor's refresh rate is around 60 Hz anyways, so anything above it, is wasted energy.

1) I'm using nVidia GeForce GTX460
2) I'm using SFML.NET binding which actually using CSFML 2.2
3) My display refresh rate is 75 Hz
4) It's better to set frame limit by using standard practice - set vblank sync flag. It's reduce CPU load and makes graphics movements maximum smooth.

In opposite, SetFrameLimit is completely useless because it grows up CPU usage at about 40x times (4000%), also it causes movement jerky and stress overall system by making extremely high CPU load with no result (just burns CPU time in idle loop and prevents other threads to do useful job). It's some kind of single thread programming practice which is a bad style at our multi core processors time.

vblank sync is a standard way to set frame limit and actually FAQ has big mistake in the following quote:
Quote
vertical synchronization was necessary and still exists today. In the future however, it will become less and less of an issue and at some point, vertical synchronization will no longer be necessary

vblank sync is the single way to synchronize graphics and make it smooth, and it will not be "no longer be necessary" in future  ;)
« Last Edit: October 05, 2015, 03:52:53 pm by mkalex777 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: High CPU usage in idle mode
« Reply #12 on: October 05, 2015, 03:55:46 pm »
Quote
I'm using nVidia GeForce GTX460
My UI is in french so sorry if the translation is not accurate... but:
In nVidia control panel > Manage 3D parameters > Vertical synchronization
... you can control how the driver applies vertical synchronization (on, off, half-rate, let app decide).

Quote
In opposite, SetFrameLimit is completely useless because it grows up CPU usage at about 40x times (4000%), also it causes movement jerky and stress overall system by making extremely high CPU load with no result (just burns CPU time in idle loop and prevents other threads to do useful job).
Framerate limit puts the thread (that calls window.Display()) to sleep, it doesn't use a busy-wait loop.
You should not make such assumptions without actually checking what happens under the hood.

Quote
vblank sync is a standard way to set frame limit and actually FAQ has big mistake
I don't know who wrote that, but I agree. If it's part of the official FAQ, then it should be removed, or someone explains me why it's true ;)
Laurent Gomila - SFML developer

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: High CPU usage in idle mode
« Reply #13 on: October 05, 2015, 04:03:05 pm »
Quote
I'm using nVidia GeForce GTX460
My UI is in french so sorry if the translation is not accurate... but:
In nVidia control panel > Manage 3D parameters > Vertical synchronization
... you can control how the driver applies vertical synchronization (on, off, half-rate, let app decide).

I'm always using "Use the 3D application settings"

Quote
In opposite, SetFrameLimit is completely useless because it grows up CPU usage at about 40x times (4000%), also it causes movement jerky and stress overall system by making extremely high CPU load with no result (just burns CPU time in idle loop and prevents other threads to do useful job).
Framerate limit puts the thread (that calls window.Display()) to sleep, it doesn't use a busy-wait loop.
You should not make such assumptions without actually checking what happens under the hood.

If its designed to make frame skip, it has a bug. Because when I'm trying to use it, my application starts to consume 2 of 4 CPU cores with 100% load on each core. I don't think that it may be called "sleep"  :)

It's very strange, because when I didn't call SetFrameLimit(0), the process running 2 threads with no sleep at all, so each thread eats one CPU core for 100%. The first thread is a main thread with game loop and the second thread working inside nVidia driver, I didn't analyzed who spawned it.
« Last Edit: October 05, 2015, 04:08:48 pm by mkalex777 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: [SOLVED] High CPU usage in idle mode
« Reply #14 on: October 05, 2015, 04:05:49 pm »
Quote
I'm always using "Use the 3D application settings"
Ok, now at least it is clear.

Quote
If its designed to make frame skip, it has a bug. Because when I'm trying to use it, my application starts to consume 2 of 4 CPU cores with 100% load on each core. I don't think that it may be called "sleep"
It's implemented with a direct call to the underlying OS sleep function. Nothing more.

If it's not already the case, you should first try all these timing functions in a new, empty project. You know, just to be sure that the rest of your code is not interfering... ;)
Laurent Gomila - SFML developer