这是一个非常有趣的问题,所以让我设置场景。我在国家计算机博物馆工作,我们刚刚设法从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上试用它,这就是我们第一次遇到问题的地方。
我首先调整了在Windows上运行的代码,因为这是游戏PC正在使用的,但很遗憾发现这个过程只获得了大约15%的CPU功率。我认为Windows必须是Windows,所以我启动了一张Ubuntu的Live CD,认为Ubuntu可以让这个过程充分发挥其在笔记本电脑上的作用。
然而我只有5%的使用率!所以我的问题是,我怎样才能使程序在Windows 7或Linux上以100%的CPU利用率在我的游戏机上运行?另一件很棒但不必要的事情是,如果最终产品可以是一个可以在Windows机器上轻松分发和运行的.exe。
非常感谢!
P.S。当然这个程序并没有真正与Crays 8专业处理器一起使用,这是另一个问题......如果你对90码Cray超级计算机的优化代码有所了解,那么我们也会大声呼喊!
答案 0 :(得分:81)
如果您想要100%CPU,则需要使用1个以上的核心。要做到这一点,你需要多个线程。
这是使用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:
答案 1 :(得分:23)
您在多核计算机上运行一个进程 - 因此它只在一个核心上运行。
解决方案很简单,因为你只是试图固定处理器 - 如果你有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
答案 2 :(得分:8)
我们真的想知道它有多快!
生成素数的算法效率很低。将其与primegen进行比较,在Pentium II-350上仅需8秒即可生成50847534素数至1000000000。
要轻松使用所有CPU,您可以在多个线程(进程)中解决embarrassingly parallel problem,例如计算Mandelbrot set或使用genetic programming to paint Mona Lisa。
另一种方法是为Cray超级计算机采用现有的基准程序,并将其移植到现代PC中。
答案 3 :(得分:5)
您在十六进制核心处理器上获得15%的原因是因为您的代码在100%时使用了1个核心。 100/6 = 16.67%,使用具有流程调度的移动平均值(您的流程将在正常优先级下运行)可以轻松报告为15%。
因此,为了使用100%的cpu,您需要使用CPU的所有内核 - 为十六进制核心CPU启动6个并行执行代码路径,并且这个规模可以达到您的Cray机器所拥有的多个处理器:)
答案 4 :(得分:2)
还要非常清楚如何您正在加载CPU。 CPU可以执行许多不同的任务,虽然其中许多将被报告为“100%加载CPU”,但它们可能各自使用100%的CPU不同部分。换句话说,很难比较两个不同的CPU的性能,特别是两种不同的CPU架构。执行任务A可能有利于一个CPU而不是另一个CPU,而执行任务B则很容易相反(因为两个CPU内部可能有不同的资源,并且执行代码的方式可能非常不同)。
这就是软件与硬件一样使计算机表现最佳的原因。对于“超级计算机”来说确实如此。
CPU性能的一个衡量指标可能是每秒指令数,但在不同的CPU架构上,指令不会相同。另一项措施可能是缓存IO性能,但缓存基础架构也不相同。然后,度量可以是每瓦使用的指令数,因为在设计集群计算机时,功率传输和耗散通常是一个限制因素。
所以你的第一个问题应该是:哪个性能参数对你很重要?你想测量什么?如果你想看看哪个机器从Quake 4中获得最多的FPS,答案很简单;你的游戏装备将会,因为Cray根本无法运行该程序; - )
干杯, 斯廷
答案 5 :(得分:1)
TLDR; 接受的答案既低效又不兼容。以下算法更快地 100x 。
MAC上可用的gcc编译器无法运行omp
。我不得不安装llvm (brew install llvm )
。但在运行OMP版本时,我没有看到CPU空闲下降。
或者,我使用基本的POSIX线程,可以使用任何c编译器运行,在nos of thread
= no of cores
= 4时看到几乎整个CPU用完(MacBook Pro,2.3 GHz Intel Core i5)。这是程序 -
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define NUM_THREADS 10
#define THREAD_LOAD 100000
using namespace std;
struct prime_range {
int min;
int max;
int total;
};
void* findPrime(void *threadarg)
{
int i, primes = 0;
struct prime_range *this_range;
this_range = (struct prime_range *) threadarg;
int minLimit = this_range -> min ;
int maxLimit = this_range -> max ;
int flag = false;
while (minLimit <= maxLimit) {
i = 2;
int lim = ceil(sqrt(minLimit));
while (i <= lim) {
if (minLimit % i == 0){
flag = true;
break;
}
i++;
}
if (!flag){
primes++;
}
flag = false;
minLimit++;
}
this_range ->total = primes;
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
struct timespec start, finish;
double elapsed;
clock_gettime(CLOCK_MONOTONIC, &start);
pthread_t threads[NUM_THREADS];
struct prime_range pr[NUM_THREADS];
int rc;
pthread_attr_t attr;
void *status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(int t=1; t<= NUM_THREADS; t++){
pr[t].min = (t-1) * THREAD_LOAD + 1;
pr[t].max = t*THREAD_LOAD;
rc = pthread_create(&threads[t], NULL, findPrime,(void *)&pr[t]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
int totalPrimesFound = 0;
// free attribute and wait for the other threads
pthread_attr_destroy(&attr);
for(int t=1; t<= NUM_THREADS; t++){
rc = pthread_join(threads[t], &status);
if (rc) {
printf("Error:unable to join, %d" ,rc);
exit(-1);
}
totalPrimesFound += pr[t].total;
}
clock_gettime(CLOCK_MONOTONIC, &finish);
elapsed = (finish.tv_sec - start.tv_sec);
elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
printf("This machine calculated all %d prime numbers under %d in %lf seconds\n",totalPrimesFound, NUM_THREADS*THREAD_LOAD, elapsed);
pthread_exit(NULL);
}
P.S。 - 如果增加线程数,则实际CPU使用率会下降(尝试不使用线程= 20。)因为系统在上下文切换中使用的时间比实际计算时多。
顺便说一下,我的机器不像@mystical那样强壮(接受的答案)。但我的基本POSIX线程版本比OMP版本更快。结果如下 -
P.S。将线程负载增加到250万以查看CPU使用情况,因为它在不到一秒的时间内完成。
答案 6 :(得分:0)
尝试使用例如OpenMP并行化您的程序。它是构建并行程序的一个非常简单有效的框架。
答案 7 :(得分:0)
要快速改进一个核心,请删除系统调用以减少上下文切换。删除这些行:
system("clear");
printf("%d prime numbers calculated\n",primes);
第一个特别糟糕,因为它会在每次迭代时产生一个新进程。
答案 8 :(得分:0)
只需尝试Zip和解压缩一个大文件,没有任何重要的I / O操作可以使用cpu。