在C++中模拟CPU负载

5

我目前正在使用C++在Windows上编写应用程序,并希望模拟CPU负载。

以下是我的代码:

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){}
}

我使用与此线程中给出的答案相同的方法编写了这段代码:模拟稳定的CPU负载和峰值
我的问题是:
  1. 我是否已正确将其他帖子中的C#代码转换为C++?
  2. 这段代码是否会在四核处理器上生成50%的平均CPU负载?
  3. 如何以合理的准确度找到CPU的负载百分比?(任务管理器是唯一的选择吗?)
编辑:我提出这个问题的原因是我最终想能够在合理的容差范围内生成10,20,30,...,90%的CPU负载。这段代码似乎很适合生成70%<的负载,但在70%以下的任何负载下都非常不准确(根据任务管理器CPU负载读数测量)。是否有任何想法可以让我生成所需的负载,同时仍然能够在不同计算机上使用我的程序(即具有不同CPU)?

获取GetSystemTimes的CPU使用率:http://www.codeproject.com/Articles/9113/Get-CPU-Usage-with-GetSystemTimes - Didac Perez Parera
  1. 我相信是这样的。
  2. 应该可以,你试过了吗?没有得到想要的结果吗?
  3. 你是指仅由你的进程引起的负载百分比吗?如果是这样,可以使用Windows的性能计数器进行分析。
- Andy Prowl
任务管理器应该是一个不错的选择。 - Mark Garcia
3个回答

8
乍一看,这似乎是不太好看但正确的C++或C代码(可以通过编译来确认)。缺少包含文件(<windows.h><process.h><time.h>),但除此之外它可以正常编译。
请注意,clockSleep的精度并不高,Sleep也不是特别可靠。平均而言,线程函数应该能够按照预期工作,尽管会有几个百分点的变化。
然而,关于问题2),你应该将最后一个while(1){}替换为某个阻塞操作而不是自旋(例如WaitForSingleObjectSleep)。否则,整个程序将不会在四核上占用50%的负载。由于主线程,你将在一个核心上占用100%的负载,加上四个工作线程的4倍50%。这显然会导致每个核心的负载总和超过50%(并且会导致线程在不同核心之间跳动,导致不良的副作用)。
使用任务管理器或类似的实用程序验证是否获得所需的负载是一个不错的选择(因为它是最简单的解决方案,所以也是最好的)。
还要注意,以这种方式模拟负载可能会“大致”工作,但不是100%可靠。有些效果(内存、执行单元)很难预测。例如,假设您使用此循环占用了CPU整数执行单元的100%(合理的假设),但没有占用其浮点或SSE单元。现代CPU可能会在真实或逻辑核心之间共享资源,您可能无法准确预测会产生什么影响。或者,另一个线程可能会受到内存限制或具有显着的页面错误,因此占用CPU时间不会对其产生太大影响(事实上,可能足以使预取工作得更好)。或者,它可能会阻塞在AGP传输上。或者,其他你无法确定的情况。 编辑: 改进版本,代码更短,修复了一些问题,并且可以按预期工作:
  • 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;
    }
    

谢谢您的回复。如果这是一个基本问题,我很抱歉,但是您说要用像Sleep这样的阻塞方法替换“last while(1){}”,而不是旋转。请问我该如何在我的代码中实现它,同时仍然以50%的负载运行CPU? - user206631
我觉得我在这里漏掉了什么。据我理解,当我运行我的代码并使用Sleep(INFINITE)而不是while(1){}时,任务管理器不应该显示50%的CPU使用率吗? - user206631
是的,完全正确。但使用while循环,CPU利用率大约只有75%,而且可能会出现重度线程迁移,因为您有5个具有相同优先级的竞争者,但只有4个核心,无论操作系统如何智能地调度,都不可能在一个核心上提供150%的CPU时间。因此,每当服务员唤醒时(这会暂时提高其优先级),它将把主线程踢到等待队列中(稍后可能会得到另一个核心)。对于其他程序中的任何其他线程也是如此。考虑到这一点,使用完成端口将是一个有趣的想法... - Damon
完成端口,正如您所知,每次会唤醒_N_个被阻塞的线程(默认值= CPU核心数),在一个线程被阻塞时唤醒另一个线程,并在已经有足够运行的线程时阻止试图分离消息的线程。作为一个疯狂的想法,理论上应该能够利用这一点更加紧密地模拟类似于模拟X%的东西,而不必(只可能在一小部分时间内)遇到_N+1_个准备好的线程的问题。但这只是一个想法,也许这并没有更好的效果。 - Damon
请原谅我的愚蠢,但是当我使用Sleep(INFINITE)而不是while(1){}运行相同的代码时,根据任务管理器,我的CPU使用率约为2-3%,如果我尝试模拟60ms的工作,则任务管理器仅指示CPU使用率为约25%。这是有原因的吗? - user206631
显示剩余2条评论

2

这里有一段代码示例,它在Windows上将我的CPU占用率提高到了100%。

#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);
    }
}

当您构建并运行应用程序时,按Ctrl-C以终止应用程序。

1

您可以使用Windows 性能计数器API来获取CPU负载。无论是整个系统还是您的进程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接