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

bag*_*man 78 c linux windows performance cray

这是一个非常有趣的问题,所以让我设置场景.我在国家计算机博物馆工作,我们刚刚设法从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);
}
Run Code Online (Sandbox Code Playgroud)

在我们运行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.

非常感谢!

PS当然这个程序并没有真正与Crays 8专业处理器一起工作,这是另一个问题......如果你对90码Cray超级计算机的优化代码有所了解,那么我们也会大声呼喊!

Mys*_*ial 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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

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

这是你的100%CPU:

在此输入图像描述

  • Augh!太......多......粉红色! (18认同)
  • @MohammadFadin http://en.wikipedia.org/wiki/Parallel_computing基本上,您需要能够并行处理多个任务才能使用多核计算机. (2认同)

cha*_*ite 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;
}
Run Code Online (Sandbox Code Playgroud)

产量

$ ./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
Run Code Online (Sandbox Code Playgroud)

  • 哦!现在你已经拥有了这个例子.:) (2认同)

jfs*_*jfs 7

我们真的想看看它有多快!

生成素数的算法效率很低.将它与Primegen相比较,在Pentium II-350上仅需8秒即可生成50847534素数至1000000000.

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

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

  • 该算法效率低下并不重要,因为目标不是实际计算素数,而是执行一项一般困难的任务,看看它比现代桌面好多少或差多少。高效的算法只会使比较变得更加困难,如果算法太好而故意利用现代 CPU 功能/怪癖,甚至可能会破坏结果。 (2认同)

Car*_*arl 5

十六进制核心处理器获得15%的收益的原因是因为您的代码在100%的情况下使用1个核心。100/6 = 16.67%,使用移动平均和流程计划(您的流程将在正常优先级下运行)可以很容易地报告为15%。

因此,为了使用100%cpu,您将需要使用CPU的所有内核-为六核内核CPU启动6个并行执行代码路径,并且可以将此规模扩展到Cray计算机拥有的许多处理器:)