There is programs that is able to limit the CPU usage of processes in Windows. For example BES and ThreadMaster. I need to write my own program that does the same thing as these programs but with different configuration capabilities. Does anybody know how the CPU throttling of a process is done (code)? I'm not talking about setting the priority of a process, but rather how to limit it's CPU usage to for example 15% even if there is no other processes competing for CPU time.
Update: I need to be able to throttle any processes that is already running and that I have no source code access to.
You probably want to run the process(es) in a job object, and set the maximum CPU usage for the job object with SetInformationJobObject
, with JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
.
Very simplified, it could work somehow like this:
GetProcessTimes
once.GetProcessAffinityMask
returns 0, call SetProcessAffinityMask(old_value)
. This means we've suspended that process in our last iteration, we're now giving it a chance to run again. GetProcessTimes
to get the "current" valueGetSystemTimeAsFileTime
cpu_usage = (deltaKernelTime + deltaUserTime) / (deltaTime)
old_value = GetProcessAffinityMask
followed by SetProcessAffinityMask(0)
which will take the process offline.This is basically a very primitive version of the scheduler that runs in the kernel, implemented in userland. It puts a process "to sleep" for a small amount of time if it has used more CPU time than what you deem right. A more sophisticated measurement maybe going over a second or 5 seconds would be possible (and probably desirable).
You might be tempted to suspend all threads in the process instead. However, it is important not to fiddle with priorities and not to use SuspendThread
unless you know exactly what a program is doing, as this can easily lead to deadlocks and other nasty side effects. Think for example of suspending a thread holding a critical section while another thread is still running and trying to acquire the same object. Or imagine your process gets swapped out in the middle of suspending a dozen threads, leaving half of them running and the other half dead.
Setting the affinity mask to zero on the other hand simply means that from now on no single thread in the process gets any more time slices on any processor. Resetting the affinity gives -- atomically, at the same time -- all threads the possibility to run again.
Unluckily, SetProcessAffinityMask
does not return the old mask as SetThreadAffinityMask
does, at least according to the documentation. Therefore an extra Get...
call is necessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With