如何从C程序中获得100%的CPU使用率

这是一个非常有趣的问题,所以让我来设置一下这个场景。 我在国家计算机博物馆工作,从1992年开始,我们就成功地获得了一台Cray Y-MP EL超级计算机,我们真的想看看它有多快!

我们决定做这件事的最好方法是编写一个简单的C程序来计算素数,并显示这个过程需要多长时间,然后在一台快速的现代桌面PC上运行程序并比较结果。

我们很快提出了这个代码来计算素数:

#include <stdio.h> #include <time.h> void main() { clock_t start, end; double runTime; start = clock(); int i, num = 1, primes = 0; while (num <= 1000) { i = 2; while (i <= num) { if(num % i == 0) break; i++; } if (i == num) primes++; system("clear"); printf("%d prime numbers calculated\n",primes); num++; } end = clock(); runTime = (end - start) / (double) CLOCKS_PER_SEC; printf("This machine calculated all %d prime numbers under 1000 in %g seconds\n", primes, runTime); } 

在运行Ubuntu的双核心笔记本电脑(The Cray运行UNICOS)上,运行得非常完美,CPU使用率达到100%,耗时约10分钟左右。 当我回到家的时候,我决定在我的六核现代游戏PC上试试它,这是我们开始第一个问题的地方。

因为这是游戏PC正在使用的,所以我第一次调整了在Windows上运行的代码,但是却发现这个过程只能获得大约15%的CPU功耗,我感到很难过。 我认为Windows必须是Windows,所以我启动进入Ubuntu的Live CD,认为Ubuntu将允许这个进程像我之前在笔记本上做的那样充分发挥其潜力。

但是我只有5%的使用率! 所以我的问题是,如何让我的游戏机在Windows 7或运行在100%CPU的情况下运行在我的游戏机上运行程序? 另一件好事,但不是必需的是,如果最终产品可以是一个.exe,可以很容易地分布和运行在Windows机器上。

非常感谢!

PS当然,这个程序并没有真正与Crays 8专业处理器一起工作,这是一个其他的问题。如果你知道关于优化代码工作在90年代Cray超级计算机上的任何事情,也给我们留言!

如果你想100%的CPU,你需要使用多个核心。 要做到这一点,你需要多个线程。

以下是使用OpenMP的并行版本:

我不得不把限制增加到1000000 ,使我的机器花费1秒以上。

 #include <stdio.h> #include <time.h> #include <omp.h> int main() { double start, end; double runTime; start = omp_get_wtime(); int num = 1,primes = 0; int limit = 1000000; #pragma omp parallel for schedule(dynamic) reduction(+ : primes) for (num = 1; num <= limit; num++) { int i = 2; while(i <= num) { if(num % i == 0) break; i++; } if(i == num) primes++; // printf("%d prime numbers calculated\n",primes); } end = omp_get_wtime(); runTime = end - start; printf("This machine calculated all %d prime numbers under %d in %g seconds\n",primes,limit,runTime); return 0; } 

输出:

本机在29.753秒内计算了1000000以下的所有78498个素数

这是你的100%CPU:

在这里输入图像描述

你在多核机器上运行一个进程 – 所以它只能运行在一个核心上。

这个解决scheme很简单,因为你只是试图挂住处理器 – 如果你有N个内核,运行你的程序N次(当然是并行)。

这是一些代码,并行运行你的程序NUM_OF_CORES次。 这是POSIXy代码 – 它使用fork – 所以你应该在Linux下运行。 如果我正在读Cray的内容是正确的,那么移植这个代码可能比另一个答案中的OpenMP代码更容易。

 #include <stdio.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define NUM_OF_CORES 8 #define MAX_PRIME 100000 void do_primes() { unsigned long i, num, primes = 0; for (num = 1; num <= MAX_PRIME; ++num) { for (i = 2; (i <= num) && (num % i != 0); ++i); if (i == num) ++primes; } printf("Calculated %d primes.\n", primes); } int main(int argc, char ** argv) { time_t start, end; time_t run_time; unsigned long i; pid_t pids[NUM_OF_CORES]; /* start of test */ start = time(NULL); for (i = 0; i < NUM_OF_CORES; ++i) { if (!(pids[i] = fork())) { do_primes(); exit(0); } if (pids[i] < 0) { perror("Fork"); exit(1); } } for (i = 0; i < NUM_OF_CORES; ++i) { waitpid(pids[i], NULL, 0); } end = time(NULL); run_time = (end - start); printf("This machine calculated all prime numbers under %d %d times " "in %d seconds\n", MAX_PRIME, NUM_OF_CORES, run_time); return 0; } 

产量

 $ ./primes Calculated 9592 primes. Calculated 9592 primes. Calculated 9592 primes. Calculated 9592 primes. Calculated 9592 primes. Calculated 9592 primes. Calculated 9592 primes. Calculated 9592 primes. This machine calculated all prime numbers under 100000 8 times in 8 seconds 

我们真的想看看它能走多快!

生成素数的algorithm是非常低效的。 比较一下,在Pentium II-350上,只需8秒就能产生10亿分之50847534的素数。

为了方便地使用所有的CPU,您可以解决一个令人尴尬的并行问题,例如,计算Mandelbrot集合或使用遗传编程在多个线程(进程)中绘制Mona Lisa 。

另一种方法是采用Cray超级计算机的现有基准程序,并将其移植到现代PC上。

在hex核心处理器上获得15%的原因是因为您的代码在100%时使用了1个核心。 100/6 = 16.67%,使用移动平均值和进程调度(您的进程将在正常优先级下运行)很容易报告为15%。

因此,为了使用100%的cpu,你需要使用CPU的所有核心 – 为六核CPU启动6个并行执行代码path,并且这个比例直到你的Cray机器拥有的多个处理器:)

也要非常清楚你如何加载CPU。 一个CPU可以执行许多不同的任务,而其中许多将被报告为“加载CPU 100%”,它们可以分别使用CPU的100%的不同部分。 换句话说,比较两个不同CPU的性能是非常困难的,特别是两种不同的CPU架构。 执行任务A可能有利于一个CPU而不是另一个CPU,而在执行任务B时,它可以很容易地反过来(因为两个CPU可能在内部具有不同的资源并且可能执行代码的方式非常不同)。

这就是软件对于使计算机在硬件上performance最佳的同样重要的原因。 这对于“超级计算机”也是如此。

CPU性能的一个衡量标准可能是每秒钟的指令,但是不同的CPU体系结构中的指令不会相同。 另一个措施可能是cachingIO性能,但caching基础设施也不相同。 然后,可以使用每瓦特指令的数量,因为在devise集群计算机时,功率传递和耗散通常是限制因素。

所以你的第一个问题应该是:哪个性能参数对你很重要? 你想要衡量什么? 如果你想知道哪台机器从地震4中获得最多的FPS,答案很简单。 你的游戏平台将会像Cray无法运行那个程序一样;-)

干杯,斯蒂恩

尝试使用例如OpenMP来并行化您的程序。 这是构build并行程序的一个非常简单有效的框架。

要在一个内核上快速改进,请删除系统调用以减less上下文切换。 删除这些行:

 system("clear"); printf("%d prime numbers calculated\n",primes); 

第一个特别糟糕,因为它会在每一次迭代中产生一个新的进程。