programing

C 프로그램에서 100% CPU 사용률을 얻는 방법

kingscode 2022. 8. 18. 21:31
반응형

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에서 동작하도록 코드를 처음 수정했지만 CPU의 소비전력이 15%밖에 되지 않아 안타까웠습니다.Windows가 Windows인 것이 틀림없다고 생각했기 때문에, Ubuntu의 라이브 CD로 기동했습니다.Ubuntu가 노트북에서 했던 것처럼 프로세스를 최대한으로 실행할 수 있을 것이라고 생각했습니다.

하지만 사용률은 5%밖에 되지 않았어요!Windows 7 또는 라이브 Linux에서 CPU 사용률이 100%인 게임 머신에서 실행되도록 프로그램을 어떻게 조정할 수 있을까요?또 하나의 장점은 최종 제품이 Windows 머신에서 쉽게 배포 및 실행할 수 있는 하나의 .exe가 될 수 있다는 것입니다.

정말 고마워.

P.S. 물론 이 프로그램은 Crays 8 스페셜리스트 프로세서에서는 동작하지 않았습니다.이것은 전혀 다른 문제입니다.90년대 Cray 슈퍼컴퓨터에서 사용할 수 있도록 코드를 최적화하는 방법에 대해 알고 계신 분은 저희에게 연락주세요!

CPU를 100% 사용하려면 여러 코어를 사용해야 합니다.그러기 위해서는 여러 개의 스레드가 필요합니다.

Open을 사용한 병렬 버전입니다.MP:

를 더 .10000001번으로 하다

#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개의 소수를 계산했습니다.

사용하시는 CPU는 다음과 같습니다.

여기에 이미지 설명 입력

멀티코어 머신에서 1개의 프로세스를 실행하고 있기 때문에 1개의 코어에서만 실행할 수 있습니다.

N개의 코어가 있는 경우 N개의 프로그램을 병렬로 실행하기만 하면 되기 때문에 해결 방법은 간단합니다.

입니다.NUM_OF_CORES POSIXy 코드입니다.forkLinux 서 linux linux linux linux linux linux linux linux 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

TLDR; 승인된 답변은 비효율적이고 호환성이 없습니다.following algo는 100배 빠르게 작동합니다.

에서 사용 는 MAC를 실행할 수 .omp . llvm 을 해야 했습니다.(brew install llvm )하지만 OMP 버전을 실행하는 동안 CPU 아이돌이 다운되는 것은 보지 못했습니다.

다음은 OMP 버전 실행 중 스크린샷입니다.여기에 이미지 설명 입력

또는 기본 POSIX 스레드를 사용했습니다.기본 POSIX 스레드는 임의의 c 컴파일러를 사용하여 실행할 수 있으며 CPU가 거의 모두 사용되었습니다.nos of thread=no of cores= 4(MacBook Pro, 2.3)GHz 인텔 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 전체의 사용 상황에 주의해 주세요.

추신 - 스레드 수를 늘리면 실제 CPU 사용률이 낮아집니다(스레드 수를 줄임= 20). 시스템이 실제 컴퓨팅보다 컨텍스트 전환에 더 많은 시간을 소비하기 때문입니다.

덧붙여서, 제 기계는 @mystic(응답 가능)만큼 튼튼하지 않습니다.하지만 기본적인 POSIX 스레드를 갖춘 내 버전은 OMP보다 훨씬 빠르게 작동합니다.결과는 다음과 같습니다.

여기에 이미지 설명 입력

추신: 스레드 로드를 250만까지 증가시켜 CPU 사용률을 확인합니다.이것은 1초 이내에 완료되기 때문입니다.

헥스 코어 프로세서에서 15%가 되는 이유는 코드가 100%에서 1개의 코어를 사용하기 때문입니다.100/6 = 16.67%로, 공정 스케줄링과 함께 이동 평균을 사용하면 공정이 정상 우선 순위에서 실행된다는 것을 쉽게 15%로 보고할 수 있습니다.

따라서 CPU를 100% 사용하려면 CPU의 모든 코어를 사용해야 합니다. 즉, 16진수 코어 CPU에 대해 6개의 병렬 실행 코드 경로를 실행하여 Cray 머신의 프로세서 수까지 확장해야 합니다.

얼마나 빨리 갈 수 있는지 보고 싶어요.

소수를 생성하는 알고리즘은 매우 비효율적입니다.Pentium II-350에서 최대 10000000000을 8초 만에 생성하는 primegen과 비교해 보십시오.

모든 CPU를 쉽게 소비하려면 Mandelbrot 세트를 계산하거나 유전자 프로그래밍을 사용하여 여러 스레드(공정)로 모나리자를 그리는 등 당혹스러울 정도로 병렬적인 문제를 해결할 수 있습니다.

또 다른 접근방식은 기존의 Cray 슈퍼컴퓨터 벤치마크 프로그램을 최신 PC에 이식하는 것입니다.

또, CPU의 로딩 방법에 주의해 주세요.CPU는 많은 다른 작업을 할 수 있습니다.또, 그 대부분은 「CPU의 100% 로딩」이라고 보고되지만, 각각 CPU의 다른 부분을 100% 사용하는 경우가 있습니다.즉, 2개의 CPU, 특히 2개의 CPU 아키텍처를 비교하기란 매우 어렵습니다.태스크 A를 실행하면 다른 CPU보다1개의 CPU를 우선하는 경우가 있지만 태스크 B를 실행하는 경우에는 그 반대일 수 있습니다(두 CPU는 내부적으로 다른 자원을 가지고 있고 코드를 매우 다르게 실행할 수 있습니다).

이것이 소프트웨어가 하드웨어와 마찬가지로 컴퓨터를 최적으로 동작시키는 데 중요한 이유입니다.이것은 「슈퍼 컴퓨터」에도 매우 해당됩니다.

CPU 퍼포먼스의 척도는 1초당 명령어일 수 있지만 명령어는 다른 CPU 아키텍처에서 동일하게 작성되지 않습니다.캐시 IO의 퍼포먼스를 측정할 수도 있지만 캐시 인프라스트럭처도 동등하지 않습니다.클러스터 컴퓨터를 설계할 때 전력 공급과 방산이 제한 요인이 되는 경우가 많기 때문에 사용되는 와트당 명령 수가 측정치가 될 수 있습니다.

첫 번째 질문은 다음과 같습니다.어떤 퍼포먼스 파라미터가 중요합니까?무엇을 측정하시겠습니까?Quake 4에서 FPS를 가장 많이 얻는 머신이 무엇인지 알고 싶다면 답은 간단합니다. Cray는 그 프로그램을 전혀 실행할 수 없기 때문에 게임용 리그가 가능합니다;-)

건배, 스틴

OpenMP 등을 사용하여 프로그램을 병렬화해 보십시오.병렬 프로그램을 구성하는 매우 간단하고 효과적인 프레임워크입니다.

1개의 코어를 단시간에 개선하려면 시스템콜을 삭제하고 컨텍스트스위칭을 줄입니다.다음 행을 삭제합니다.

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

첫 번째는 특히 좋지 않습니다. 왜냐하면 반복할 때마다 새로운 프로세스가 생성되기 때문입니다.

큰 파일의 압축 해제와 압축 해제만 하면, 무거운 I/O 조작으로 CPU를 사용할 수 있는 것은 없습니다.

언급URL : https://stackoverflow.com/questions/9244481/how-to-get-100-cpu-usage-from-a-c-program

반응형