virabhadra's picture

Performance problem in the fullscreen mode

Hello together!

My program makes a scene with flying particles based on one idea from one example. I already don't remember where it goes from.
I use OpenTK.GameWindow

And now I have a strange (at least for me) performance problem.

1 case:
The program starts in full screen mode, it works smooth and nice, but after some seconds the CPU load increases and uses permanently one core for 100%. (see picture 1)

2 case:
If I start the program and immediately switch to another window (f.e. task manager) putting the GL-window to work on the background, but still visible behind, it doesn't load CPU, only some percents. (see pictire 2).
I tested it and during many minutes it works constantly with very low CPU load.

The behavior doesn't depend on a number of objects: same for 50 and 5000 particles.

P.S.
I cannot load the code example. It writes me that the spam filter is triggered.
I will try to upload it to a comment.

Inline Images
picture 1
picture 2

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
virabhadra's picture

Another bug with the GameWindow and Form+Control.

If behind the GameWindow in fullscreen mode is a window with the "always on top" property,
even when the cursor is hidden, the cursor is visible when it's above the window behind and you can make it visible by click.

the Fiddler's picture

I just tested your code on my Win7 VM, and fullscreen consumes no more than 2-3% with 500 particles (5000 are too much for my virtualized GPU). Windowed mode consumes a little bit more, 4-8%, which is actually expected in this case (Parallels VM does not support OpenGL vsync in windowed-mode, only in fullscreen.) According to the Visual Studio 2013 profiler, around 80% of the time is spent inside SwapBuffers and 15% inside Thread.Sleep.

It appears that there are some reports of Nvidia using 100% CPU when vsync is enabled. See for instance: http://www.retrocopy.com/blog/5/the-battle-of-v-sync-opengl-on-nvidia-vs...

According to this thread https://stackoverflow.com/questions/5829881/avoid-waiting-on-swapbuffers SwapBuffers is not actually burning CPU time:

Quote:

SwapBuffers is not busy waiting, it just blocks your thread in the driver context, which makes Windows calculating the CPU usage wrongly: Windows calculates the CPU usage by determining how much CPU time the idle process gets + how much time programs don't spend in driver context. SwapBuffers will block in driver context and your program obviously takes away that CPU time from the idle process. But your CPU is doing literally nothing in the time, the scheduler happily waiting to pass the time to other processes. [...] If you'd measure the actual power consumption or heat output, for a simple OpenGL program this will stay rather low.

This irritating behaviour is actually an OpenGL FAQ!

I am not sure how accurate this is, but it sounds plausible.

I would still suggest testing with the SDL2 backend (your application appears to be running in x86 mode, so use the x86 version of SDL2.dll). If the issue persists, then you might wish to contact Nvidia for clarification (they are usually pretty responsive.)

Edit: some people recommend moving Thread.Sleep(1) after SwapBuffers(). Might be worth a try.

virabhadra's picture

Hmmm.
I switched V-Sync in the system to "off" and in my program too.
And now, if I keep Sleep(1), it runs with fps about 500, but without full loading of any core in both cases!
If remove Sleep(1), then it runs with fps 1200.

So it looks like V-Sync problem.
Does it mean that there is only one way to define the refresh rate: using Sleep(n)?

I have tested SDL2.dll separately for x86 and x64 with V-Sync on.
In both cases the problem is raised.

Only the V-Sync option affects the behavior.

the Fiddler's picture

Ok, I've done some more searching and this indeed appears to be a known issue with Nvidia drivers. It is not clear if the CPU usage is indeed high, or if this is simply an issue of the task manager reporting CPU usage incorrectly. In any case, this is expected behavior if you enable vsync on Nvidia - nothing OpenTK can do about it.

You can use the soft-limiter in OpenTK to control the framerate:

        static void Main(string[] args)
	{
		GL_Window N = new GL_Window();
		N.Run(60.0, 60.0);
	}

The two parameters control the number of UpdateFrame and RenderFrame events per second, respectively.

virabhadra's picture

It behaves even more strange.
When I use VSync = VSyncMode.On; and N.Run(60.0, 60.0); it uses 27% of CPU in both cases: full screen and window back.

I started solving the performance problem not from the reason of bad CPU reporting.
I heard acceleration of a cooler in my pc every time when I started the program in the full screen mode.
I don't know how the cooler works, directly from the core temperature or from bad reporting too.

So now I have only one working configuration: V-Sync off and Sleep(15).

the Fiddler's picture

If you use the soft-limiter, Run(60, 60), you should turn vsync off. The first value is the desired logic update rate (UpdateFrame event) and the second value is the desired fps (RenderFrame event).

If you use vsync, then the fps will be limited by your monitor, so you don't need to limit your fps with the soft-limiter. With vsync, prefer something like Run(60) which means raise 60 UpdateFrame events per second (use these to animate your particles) and as many RenderFrame events as the hardware can handle (with vsync enabled this would be 60 fps.)

The soft-limiter will not reduce CPU usage, it will simply limit your framerate to the values you set. To reduce CPU usage, you always need to call Thread.Sleep() with a suitable parameter.

virabhadra's picture

One thing is still not clear.

When another window is in front of the GL window with V-Sync, there is no the CPU overload problem.
At the same time all moves are smooth, so V-Sync works.

There must exist a trick how to keep this behavior even when the GL window is on the top.

the Fiddler's picture

In my experience, when running in windowed mode, or when the window is partially covered, then its contents are routed through the DWM. SwapBuffers is now synchronized to the DWM instead of the monitor vblank. Since DWM itself is vsynced, you should still not get tearing.

At least, that is a theory that describes what behavior I am seeing in my systems. Only the driver engineers can answer for certain what is going on and whether this can be somehow controlled by the application.

The nvidia and opengl forums have additional information on this topic, but unfortunately I do not have time to dig deeper right now:

I would be very interested to know if you happen to uncover any more information.

virabhadra's picture

Thank you for the links.
I will try to dig something out.

virabhadra's picture

I have found one interesting link:

VSync causes high CPU usage when "threaded optimization" is "on" in Nvidia driver.

I tried to change the option and it works. Now there is no cores loaded by 100%.
But one core is still loaded a little bit higher in the fullscreen mode. I my case it was about 30%.

May be it's a key to find a software solution.