CPU usage caps at 25%?

I’ve noticed while running diagnostics on my game while working on optimization, the percentage of CPU usage never seems to go above 25%. Instead, when it hits 25%, the framerate just plummets. Now, obviously the best solution would be to sufficiently optimize until the game stays below 25%, but I was wondering, would there be any way to allow the game to go beyond 25%? Is that some kind of limit enforced by the Windows operating system, or is that enforced somehow by MonoGame itself?

In power options of my computer, the minimum and maximum processor state are both set to 100%.

Do you have 4 cores? Cause 25% is 100% of one core. Take a look at the utilization of each core and see if not one of them hits 100%.

Good thinking. The task manager says I have two cores and four logical processors. The CPU usage is evenly distributed across all four logical processors in the graphs that the task manager displays, though. Does MonoGame only use one core?

If that’s what’s going on, I guess I just need to make sure I optimize really well. Or pick up a different hobby.

As far as I can see MonoGame only spins on 1 core ‘by default’. Easiest way to test the theory; create a console project. Create two threads and just run a while-loop forever inside each thread.

How would you enable all cores?

You can’t ‘enable’ all the cores. You have to write code that uses all the threads. You can start with looking into multithreading, tasks, and parallel.

That may be what I have to end up doing, but I’ve been studiously avoiding the concept of multithreading because of the amount of learning required.

ah, I was hoping it’d do it for me but threading isn’t too hard! :smile:

Its honestly not hard. I self learned it by just playing around with the thread class.

So if I make a game multithreaded, does that mean that users with single cores will be unable to run the game?

Not at all, Windows handles all of that and happily runs hundreds (if not thousands) of threads on whatever system is running it regardless of the number of cores, so a multi-threaded program on a single core cpu will only suffer in a lack of performance compared to a multi-core system. Basically, Windows is constantly swapping out threads across all available cores, if it has only 1, that’s all it uses, if it has 4 it will use them all and so on.

The biggest thing I’ve learned about multi-threading is, always design your program so you can run everything in multi-threaded or single-threaded mode, it makes bug-finding a ton easier to do everything in a single thread. But then you can separate everything into the multi-threaded mode to benefit from the additional power.

BUT there are things that only happen in a multi-threaded situation, so its worth doing research into things like ‘thread-locking’, ‘thread syncronisation’ and ‘memory concurrency’.

If you find multithreading that easy, you are gifted. I personally find multithreading is one of the worst things to debug.

MonoGame itself generally runs in one thread. There are a few subsystems that might spawn a thread, but for all intents and purposes it is single-threaded. This is also the same for most game engines and frameworks out there. It is up to your code to make the best use of the cores available. Be careful though because not many of the public APIs in MonoGame have been tested for thread safety.

Multithreading is not easy. It is difficult to get right, and can be even more difficult to debug. Making it scalable to suit single cores (not many of them around any more) and multiple cores to make the best use of the extra power without sacrificing performance is even more difficult.

Some future plans for MonoGame may involve more threads, e.g. DirectX 12, Metal and Vulkan support, but these will be kept internal to MonoGame where possible.

Yeah, I think I’m going to need to do a lot of research. I tried just throwing a few uses of Parallel.Invoke in my code and invariably hit runtime exceptions because my code wasn’t built for multithreading and had shared memory access conflicts.

Unfortunately, Microsoft’s documentation doesn’t help me much, since it mostly just tells the what and why but not how—or if it does, the explanations given aren’t easy to follow for someone who knows little to nothing about parallel programming.

Although actually, when I removed the shared memory conflicts, Parallel.Invoke seems to work really well for running multiple tasks concurrently. There must be some catch involved, though, because that seems almost too easy.

Well then, better start testing :wink: I usually find myself saying “Ah, now it works” and next week a customer reports some obscure bug that seems to be connected to multithreading, but support is not able to reproduce. Fun times.

Naughty Dog studio, with Christian Gyrling has a GDC post;

Yeah, I figure that sort of thing is likely, so later on I’ll do extensive testing—several hour play sessions, playing the entire game through multiple times—when the game is closer to complete. I should probably do so right now, but several hour play sessions so early on in the design process are really boring and won’t really accurately represent what it’ll be like later on.

Don’t use multiple threads, find the cause of high CPU usage in your code and fix it. Seriously. Multithreading a game is extremely complex and I bet the problem is the code, also, it will not necessarily fix your problem as it sounds like you have loop anyway so you will just max out all cores.

One way to find the code that is taking long is profiling with a tool - run it for a bit and which method call is talking up the time. Another is just to step over every method in your update and Draw, feel which method takes long and repeat the exercise in that method.

The problem is that even with a lot of optimization, if I don’t use multithreading, the only way to get the CPU usage to an acceptable level is by removing elements of the game, since the causes of the high CPU usage can’t really be fixed, they can only be eliminated. I’m just using multithreading to concurrently run some tasks which are, as much as possible, independent of each other.

Lets see the code of the method that is taking the time :slight_smile: