web-dev-qa-db-ja.com

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を実行しているデュアルコアラップトップ(CrayがUNICOSを実行)は、完全に機能し、CPU使用率が100%で、約10分ほどかかります。私が家に帰ったとき、私は自分の六角コアの現代のゲーミングPCでそれを試してみることにしました。

ゲーミングPCが使用しているコードであるため、最初にWindowsで実行するようにコードを適合させましたが、プロセスがCPUの電力の約15%しか得られなかったことに悲しみました。 WindowsがWindowsであるに違いないと思ったので、UbuntuのLive CDを起動し、Ubuntuがラップトップで以前に行ったようにプロセスを最大限に実行できると考えました。

ただし、使用率は5%しかありません!だから私の質問は、Windows 7またはライブLinuxのいずれかで、100%CPU使用率でゲーム機で実行するようにプログラムを適応させるにはどうすればよいですか?すばらしいが必要ではない別のことは、最終製品がWindowsマシンで簡単に配布および実行できる1つの.exeである場合です。

どうもありがとう!

追伸もちろん、このプログラムはCrays 8のスペシャリストプロセッサでは実際には動作しませんでした。それはまったく別の問題です。90年代のCrayスーパーコンピューターで動作するようにコードを最適化することについて何か知っているなら、私たちも叫んでください!

77
bag-man

100%のCPUが必要な場合は、複数のコアを使用する必要があります。そのためには、複数のスレッドが必要です。

OpenMPを使用した並列バージョン:

マシンで1秒以上かかるようにするには、1000000の制限を増やす必要がありました。

#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です:

enter image description here

81
Mysticial

マルチコアマシンで1つのプロセスを実行しているため、1つのコアでのみ実行されます。

プロセッサをペグしようとしているだけなので、ソリューションは十分に簡単です。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
23
cha0site

どれだけ速くなるのか本当に見たいです!

素数を生成するアルゴリズムは非常に非効率的です。 Pentium II-350でわずか8秒で1000000000までの50847534素数を生成する primegen と比較してください。

すべてのCPUを簡単に消費するには、 厄介な並列問題 を解くことができます。たとえば、compute Mandelbrot set または 遺伝的プログラミングを使用して、複数のスレッド(プロセス)でMona Lisa をペイントします。

別のアプローチは、Crayスーパーコンピューター用の既存のベンチマークプログラムを使用して、それを最新のPCに移植することです。

8
jfs

16進コアプロセッサで15%を取得している理由は、コードが100%で1コアを使用しているためです。 100/6 = 16.67%。プロセススケジューリングで移動平均を使用すると(プロセスは通常の優先順位で実行されます)、15%として簡単に報告できます。

したがって、CPUを100%使用するには、CPUのすべてのコアを使用する必要があります。16進数のコアCPUに対して6つの並列実行コードパスを起動し、Crayマシンに搭載されているプロセッサ数に応じてこのスケールを拡張します:)

5
Carl

TLDR;受け入れられた答えは、非効率的で互換性がありません。次のアルゴリズムは、100xより高速です。

MACで利用可能なgccコンパイラは、ompを実行できません。 llvm (brew install llvm )をインストールする必要がありました。しかし、IOMPバージョンの実行中にCPUアイドルがダウンしているのを見なかった

OMPバージョンの実行中のスクリーンショットを次に示します。 enter image description here

別の方法として、基本的なPOSIXスレッドを使用しました。これは、任意のcコンパイラーを使用して実行でき、saw使用されるCPUのほぼ全体を使用しましたnos of thread = no of cores = 4(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);
}

CPU全体がどのように使い果たされるかに注意してください- enter image description here

追伸-スレッドの数を増やした場合、システムがコンテキストの切り替えに実際のコンピューティングよりも多くの時間を使用するため、実際のCPU使用率は低下します(スレッド数= 20にしてみてください)。

ちなみに、私のマシンは@mystical(受け入れられた答え)ほど強力ではありません。しかし、基本的なPOSIXスレッドを使用した私のバージョンは、OMPよりもずっと高速に動作します。結果は次のとおりです-

enter image description here

追伸CPU使用率を確認するには、スレッドロードを250万に増やして、1秒未満で完了します。

2
sapy

また、非常に注意してくださいhow CPUをロードしています。 CPUは多くの異なるタスクを実行できますが、それらの多くは「CPUに100%の負荷をかける」と報告されますが、それぞれCPUの異なる部分を100%使用する場合があります。つまり、2つの異なるCPU、特に2つの異なるCPUアーキテクチャのパフォーマンスを比較することは非常に困難です。タスクAを実行すると1つのCPUが優先されますが、タスクBを実行すると逆になります(2つのCPUは内部で異なるリソースを持ち、コードを非常に異なる方法で実行するため)。

これが、コンピューターがハードウェアと同様に最適なパフォーマンスを発揮するためにソフトウェアが重要である理由です。これは確かに「スーパーコンピューター」にも当てはまります。

CPUパフォーマンスの指標の1つは1秒あたりの命令数ですが、異なるCPUアーキテクチャでは同じように命令が作成されません。キャッシュIOパフォーマンスですが、キャッシュインフラストラクチャも同等ではありません。その後、電力供給と消費は多くの場合、設計時に制限要因となるため、使用ワットあたりの命令数になります。クラスターコンピューター。

最初の質問は次のとおりです。あなたにとって重要なパフォーマンスパラメータはどれですか。何を測定しますか?どのマシンがQuake 4の中で最もFPSが高いかを知りたい場合、答えは簡単です。 Crayはそのプログラムをまったく実行できないため、ゲーミングリグを使用します;-)

乾杯、スティーン

2
Steen Schmidt

OpenMPなどを使用してプログラムを並列化してみてください。これは、並列プログラムを作成するための非常にシンプルで効果的なフレームワークです。

0
mikithskegg

大きなファイルをZipおよびUnzipするだけで、重いI/O操作ではCPUを使用できません。

0
Nima Mohammadi

1つのコアをすばやく改善するには、システムコールを削除してコンテキスト切り替えを減らします。次の行を削除します。

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

1つ目は、繰り返しごとに新しいプロセスを生成するため、特に悪いです。

0
Joel