Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simulating CPU Load In C++

Tags:

c++

cpu

cpu-usage

I am currently writing an application in Windows using C++ and I would like to simulate CPU load.

I have the following code:

void task1(void *param) { 

unsigned elapsed =0;
unsigned t0;

while(1){

    if ((t0=clock())>=50+elapsed){//if time elapsed is 50ms

        elapsed=t0;
        Sleep(50);
    }
  }
}

int main(){

int ThreadNr;

for(int i=0; i < 4;i++){//for each core (i.e. 4 cores)
    _beginthread( task1, 0, &ThreadNr );//create a new thread and run the "task1" function
}

while(1){}
}

I wrote this code using the same methodology as in the answers given in this thread: Simulate steady CPU load and spikes

My questions are:

  1. Have I translated the C# code from the other post correctly over to C++?
  2. Will this code generate an average CPU load of 50% on a quad-core processor?
  3. How can I, within reasonable accuracy, find out the load percentage of the CPU? (is task manager my only option?)

EDIT: The reason I ask this question is that I want to eventually be able to generate CPU loads of 10,20,30,...,90% within a reasonable tolerance. This code seems to work well for to generate loads 70%< but seems to be very inaccurate at any load below 70% (as measured by the task manager CPU load readings).

Would anyone have any ideas as to how I could generate said loads but still be able to use my program on different computers (i.e. with different CPUs)?

like image 936
user206631 Avatar asked Jan 09 '13 08:01

user206631


3 Answers

At first sight, this looks like not-pretty-but-correct C++ or C (an easy way to be sure is to compile it). Includes are missing (<windows.h>, <process.h>, and <time.h>) but otherwise it compiles fine.

Note that clock and Sleep are not terribly accurate, and Sleep is not terribly reliable either. On the average, the thread function should kind of work as intended, though (give or take a few percent of variation).

However, regarding question 2) you should replace the last while(1){} with something that blocks rather than spins (e.g. WaitForSingleObject or Sleep if you will). otherwise the entire program will not have 50% load on a quadcore. You will have 100% load on one core due to the main thread, plus the 4x 50% from your four workers. This will obviously sum up to more than 50% per core (and will cause threads to bounce from one core to the other, resulting in nasty side effects).

Using Task Manager or a similar utility to verify whether you get the load you want is a good option (and since it's the easiest solution, it's also the best one).

Also do note that simulating load in such a way will probably kind of work, but is not 100% reliable.
There might be effects (memory, execution units) that are hard to predict. Assume for example that you're using 100% of the CPU's integer execution units with this loop (reasonable assumption) but zero of it's floating point or SSE units. Modern CPUs may share resources between real or logical cores, and you might not be able to predict exactly what effects you get. Or, another thread may be memory bound or having significant page faults, so taking away CPU time won't affect it nearly as much as you think (might in fact give it enough time to make prefetching work better). Or, it might block on AGP transfers. Or, something else you can't tell.

EDIT:

Improved version, shorter code that fixes a few issues and also works as intended:

  • Uses clock_t for the value returned by clock (which is technically "more correct" than using a not specially typedef'd integer. Incidentially, that's probably the very reason why the original code does not work as intended, since clock_t is a signed integer under Win32. The condition in if() always evaluates true, so the workers sleep almost all the time, consuming no CPU.
  • Less code, less complicated math when spinning. Computes a wakeup time 50 ticks in the future and spins until that time is reached.
  • Uses getchar to block the program at the end. This does not burn CPU time, and it allows you to end the program by pressing Enter. Threads are not properly ended as one would normally do, but in this simple case it's probably OK to just let the OS terminate them as the process exits.
  • Like the original code, this assumes that clock and Sleep use the same ticks. That is admittedly a bold assumption, but it holds true under Win32 which you used in the original code (both "ticks" are milliseconds). C++ doesn't have anything like Sleep (without boost::thread, or C++11 std::thread), so if non-Windows portability is intended, you'd have to rethink anyway.
  • Like the original code, it relies on functions (clock and Sleep) which are unprecise and unreliable. Sleep(50) equals Sleep(63) on my system without using timeBeginPeriod. Nevertheless, the program works "almost perfectly", resulting in a 50% +/- 0.5% load on my machine.
  • Like the original code, this does not take thread priorities into account. A process that has a higher than normal priority class will be entirely unimpressed by this throttling code, because that is how the Windows scheduler works.

    #include <windows.h>
    #include <process.h>
    #include <time.h>
    #include <stdio.h>
    
    
    void task1(void *)
    {
        while(1)
        {
            clock_t wakeup = clock() + 50;
            while(clock() < wakeup) {}
            Sleep(50);
        }
    }
    
    int main(int, char**)
    {
        int ThreadNr;
        for(int i=0; i < 4; i++) _beginthread( task1, 0, &ThreadNr );
    
        (void) getchar();
        return 0;
    }
    
like image 59
Damon Avatar answered Nov 20 '22 11:11

Damon


Here is an a code sample which loaded my CPU to 100% on Windows.

#include "windows.h"

DWORD WINAPI thread_function(void* data)
{
    float number = 1.5;
    while(true)
    {
        number*=number;
    }
    return 0;
}

void main()
{
    while (true)
    {
        CreateThread(NULL, 0, &thread_function, NULL, 0, NULL);
    }
}

When you build the app and run it, push Ctrl-C to kill the app.

like image 43
Саша Зезюлинский Avatar answered Nov 20 '22 11:11

Саша Зезюлинский


You can use the Windows perf counter API to get the CPU load. Either for the entire system or for your process.

like image 1
selbie Avatar answered Nov 20 '22 09:11

selbie