Programing

스레드 컨텍스트 스위칭 오버헤드를 추정하는 방법

c10106 2022. 5. 18. 21:34
반응형

스레드 컨텍스트 스위칭 오버헤드를 추정하는 방법

실시간 마감으로 스레드 애플리케이션의 성능을 향상시키기 위해 노력하고 있다.Windows Mobile에서 실행되며 C / C++로 작성된다.나는 높은 빈도의 나사산 전환이 실질적인 오버헤드를 야기할 수 있다는 의심을 가지고 있지만, 그것을 증명하거나 반증할 수는 없다.모두가 알고 있듯이 증거의 부족은 반대 :)의 증거가 아니다.

그래서 내 질문은 두 가지다.

  • 만약 존재한다면, 스레드 컨텍스트 전환 비용의 실제 측정치는 어디에서 찾을 수 있는가?

  • 테스트 애플리케이션 작성에 시간을 들이지 않고 기존 애플리케이션에서 오버헤드를 전환하는 스레드를 추정하는 방법은 무엇인가?

  • 주어진 스레드의 컨텍스트 스위치(켜짐/꺼짐) 수를 알아낼 수 있는 방법을 아는 사람?

컨텍스트 스위치는 매우 비싸다.CPU 작동 자체 때문이 아니라 캐시 무효화 때문이다.만약 당신이 집중적인 작업을 실행한다면, CPU 캐시는 지시사항과 데이터를 위해, 또한 메모리 프리페치, TLB, RAM은 램의 일부 영역을 위해 작업을 최적화할 것이다.

컨텍스트를 변경하면 이러한 모든 캐시 메커니즘이 재설정되고 새 스레드가 "빈" 상태에서 시작된다.

당신의 실이 단지 카운터를 증가시키는 것이 아니라면, 받아들여진 답은 틀렸다.물론 이 사건에는 캐시 플러쉬가 포함되어 있지 않다.실제 애플리케이션처럼 캐시를 채우지 않고 컨텍스트 전환을 벤치마킹하는 것은 의미가 없다.

이 오버헤드를 웹 어딘가에서 찾을 수 있을 것 같진 않은데.단지 너무 많은 다른 플랫폼들이 존재한다.오버헤드는 다음 두 가지 요인에 따라 달라진다.

  • 필요한 작업이 서로 다른 CPU 유형에서 더 쉽거나 어려울 수 있으므로 CPU
  • 서로 다른 커널이 각 스위치에서 서로 다른 작업을 수행해야 하므로 시스템 커널

다른 요인으로는 스위치가 어떻게 발생하는지 등이 있다.스위치는 다음과 같은 경우에 발생할 수 있다.

  1. 그 실은 모든 시간 양자들을 사용했다.스레드가 시작되면, 스레드는 다음 누가 다음인지 결정할 커널로 제어 권한을 되돌려야 하기 전에 일정 시간 동안 실행될 수 있다.

  2. 실을 선취했다.이는 다른 스레드에 CPU 시간이 필요하고 우선 순위가 더 높을 때 발생한다.예를 들어 마우스/키보드 입력을 처리하는 스레드는 그러한 스레드가 될 수 있다.당장 CPU를 소유한 스레드가 무엇이든, 사용자가 무언가를 타이핑하거나 클릭할 때, 그는 현재의 스레드 시간 퀀텀이 완전히 소모될 때까지 기다리지 않고, 시스템이 즉시 반응하는 것을 보고 싶어한다.따라서 일부 시스템은 현재 스레드를 즉시 중지하고 우선 순위가 더 높은 다른 스레드로 제어 권한을 되돌릴 수 있다.

  3. 스레드는 실행을 중지하기 위해 절전() 또는 이와 유사한 작업을 차단하기 때문에 더 이상 CPU 시간이 필요하지 않다.

이 세 가지 시나리오는 이론적으로 서로 다른 스레드 전환 시간을 가질 수 있다.예: 마지막이 가장 느릴 것으로 예상되는데, 왜냐하면 () 절전 호출은 CPU가 커널에 다시 전달되고 커널이 절전 요청된 시간 정도 후에 스레드가 깨는지 확인하는 웨이크업 호출을 설정해야 하기 때문이다. 그런 다음 스케줄링 프로세스에서 스레드를 꺼내고 일단 스레드가 깨어나면 스레드가 가장 느리게 된다.스레드를 스케줄링 프로세스에 다시 추가하십시오.이 모든 급경사는 어느 정도 시간이 걸릴 것이다.따라서 실제 수면 호출은 다른 실로 전환하는 데 걸리는 시간보다 길어질 수 있다.

확실히 알고 싶다면 벤치마킹해야 한다고 생각해.문제는 보통 실을 재워야 하거나 뮤텍스를 사용하여 동기화해야 한다는 것이다.수면 또는 잠금/잠금 해제 뮤텍스 자체에는 오버헤드가 있다.이것은 당신의 벤치마크에 이러한 오버헤드도 포함됨을 의미한다.강력한 프로파일러가 없으면 실제 스위치에 사용된 CPU 시간과 절전/무테x 호출에 사용된 CPU 시간을 나중에 말하기 어렵다.반면에, 실생활 시나리오에서, 당신의 실들은 잠기거나 자물쇠를 통해 동기화될 것이다.컨텍스트 스위치 시간을 순수하게 측정하는 벤치마크는 실제 상황을 모델링하지 않기 때문에 종합 벤치마크다.벤치마크는 실제 시나리오에 기초한다면 훨씬 더 "현실적"이다.만약 이 결과가 실제 3D 애플리케이션에서 결코 달성될 수 없다면 나의 GPU가 이론상 초당 20억 폴리곤을 처리할 수 있다는 것을 말해주는 GPU 벤치마크는 무슨 소용이 있는가?실제 생활 3D 애플리케이션에서 GPU를 1초간 처리할 수 있는 폴리곤이 몇 개인지 알면 훨씬 더 흥미롭지 않을까?

불행하게도 나는 윈도우즈 프로그래밍의 아무것도 모른다.나는 자바나 C#에 있지만, C/C++ Windows에 나를 울게 해 Windows용 응용 프로그램 쓸 수 있었다.내가 너만 POSIX의 소스 코드 제시할 수 있다.

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

uint32_t COUNTER;
pthread_mutex_t LOCK;
pthread_mutex_t START;
pthread_cond_t CONDITION;

void * threads (
    void * unused
) {
    // Wait till we may fire away
    pthread_mutex_lock(&START);
    pthread_mutex_unlock(&START);

    pthread_mutex_lock(&LOCK);
    // If I'm not the first thread, the other thread is already waiting on
    // the condition, thus Ihave to wake it up first, otherwise we'll deadlock
    if (COUNTER > 0) {
        pthread_cond_signal(&CONDITION);
    }
    for (;;) {
        COUNTER++;
        pthread_cond_wait(&CONDITION, &LOCK);
        // Always wake up the other thread before processing. The other
        // thread will not be able to do anything as long as I don't go
        // back to sleep first.
        pthread_cond_signal(&CONDITION);
    }
    pthread_mutex_unlock(&LOCK); //To unlock
}

int64_t timeInMS ()
{
    struct timeval t;

    gettimeofday(&t, NULL);
    return (
        (int64_t)t.tv_sec * 1000 +
        (int64_t)t.tv_usec / 1000
    );
}


int main (
    int argc,
    char ** argv
) {
    int64_t start;
    pthread_t t1;
    pthread_t t2;
    int64_t myTime;

    pthread_mutex_init(&LOCK, NULL);
    pthread_mutex_init(&START, NULL);   
    pthread_cond_init(&CONDITION, NULL);

    pthread_mutex_lock(&START);
    COUNTER = 0;
    pthread_create(&t1, NULL, threads, NULL);
    pthread_create(&t2, NULL, threads, NULL);
    pthread_detach(t1);
    pthread_detach(t2);
    // Get start time and fire away
    myTime = timeInMS();
    pthread_mutex_unlock(&START);
    // Wait for about a second
    sleep(1);
    // Stop both threads
    pthread_mutex_lock(&LOCK);
    // Find out how much time has really passed. sleep won't guarantee me that
    // I sleep exactly one second, I might sleep longer since even after being
    // woken up, it can take some time before I gain back CPU time. Further
    // some more time might have passed before I obtained the lock!
    myTime = timeInMS() - myTime;
    // Correct the number of thread switches accordingly
    COUNTER = (uint32_t)(((uint64_t)COUNTER * 1000) / myTime);
    printf("Number of thread switches in about one second was %u\n", COUNTER);
    return 0;
}

산출량

Number of thread switches in about one second was 108406

동안 100'000 너무 알고, 심지어 우리가 잠금 및 조건 기다린다가 썩은 것은 아닙니다.많은 실 스위치는 초당이 가능하다면 나는 이 모든 것들 없이 적어도 두번 자금일 겁니다

Linux를 위해 C++의 나의 50선 쇼(QuadCore Q6600) 컨텍스트 스위치 시간부터 0.9us(0.75us 2스레드에, 최소한 0.95가 50개를 실을).그들이 시간의 양자 이 기준에서 스레드 즉시 수익률이라고 부른다.

컨텍스트 스위치의 문제점들은 고정된 시간이 있다.GPU의 실들 사이를 한 주기가 컨텍스트 스위치를 실행했다.그 예로 다음과 같은 CPU에:관통할 수 없다.

double * a; 
...
for (i = 0; i < 1000; i ++)
{
    a[i] = a[i] + a[i]
}

왜냐하면 집행의 시간은 훨씬 컨텍스트 스위치 비용보다 적다.코어에 i7 이 코드 1마이크로 2(컴파일러에 따라 달라지)정도 걸린다.왜냐하면 그것은 어떻게 작은 일들을 나사식으로를 정의합니다 그래서context 스위치 시간 중요하다.나는 이 또한 컨텍스트 스위치의 효과적인 측정을 위한 방법을 제공한다 것 같아요.확인하세요 어떻게 오래 있는 배열(상단 예에서)이들 두 스레드에서 스레드 풀을 보여 주는 몇가지 실질적인 장점에 비교하는 것이 단일 스레드 하나.이것은 아마도 금새 100000요소이고 그래서 효과적인 컨텍스트 스위치 이제 어딘가에 20us의 범위에서 같은 앱 내에 있을 것이다.

모든 encapsulations은 스레드 풀에서 사용하기 때문에 계산(말에)는 지가 있는 스레드 스위치 시간으로 기대되야 한다.

Atmapuri

컨텍스트 스위치, 30µs CPU오버 헤드http://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html의 비용 경험 법칙이 비싸다.

내가 너 시험 지원서 쓰고 싶지 않다고 말했다, 나는 ARM9 리눅스 플랫폼에 이전 시험이 되는지 알아보기 위해 이 했다.그것을 높여 줄것 그것은 단지 두개의 실이기 때문::스레드::yield()(또는, 너도 알다시피)과 약간의 변수 올린 후 1분 가량( 다른 달리기 과정 없이는 무슨 일을 하면 적어도 아무도), 앱이 초당을 할 수 있다면 얼마나 많은 컨텍스트 스위치에 입혔습니다.물론 이 모르지만, 점은 둘 다 실을 서로에게, 그리고 너무 빨라서 더 이상 드는 비용에 대해 생각하는 건 말지 못한 CPU를은 정확한 것이 아니다.그래서 단순히 그냥 너무 많이 존재하지 않는 수 있는 문제에 대해 대신 생각하는 간단한 테스트를 작성해야 한다.

그것 말고는 성능 카운터와 함께 1800번 정도 해 볼 수도 있다.

그리고 Windows CE 4.X에서 실행 중인 애플리케이션을 기억하는데, 이 애플리케이션은 때때로 집중적인 스위칭이 가능한 네 개의 스레드를 가지고 있고, 성능 문제에 부딪힌 적이 없다.우리는 또한 핵심 스레딩 사물을 스레드 없이 구현하려고 노력했고, 성능 향상은 보이지 않았다(GUI는 훨씬 느리게 반응했을 뿐, 다른 것은 모두 동일했다).컨텍스트 스위치 수를 줄이거나 스레드를 완전히 제거하여(테스트용) 동일한 방법을 시도할 수 있다.

잘은 모르겠지만 혹시 윈도 모바일에 있는 보통 성능 카운터가 있어?컨텍스트 스위치/초 같은 것을 볼 수 있다.컨텍스트 전환 시간을 구체적으로 측정하는 것이 있는지 모르겠다.

너는 그것을 추정할 수 없다.재야 돼.그리고 장치에 있는 프로세서에 따라 달라질 겁니다.

컨텍스트 스위치를 측정하는 두 가지 매우 간단한 방법이 있다.하나는 코드를 포함하지만 다른 하나는 그렇지 않다.

첫째, 코드 방식(시소코드):

DWORD tick;

main()
{
  HANDLE hThread = CreateThread(..., ThreadProc, CREATE_SUSPENDED, ...);
  tick = QueryPerformanceCounter();
  CeSetThreadPriority(hThread, 10); // real high
  ResumeThread(hThread);
  Sleep(10);
}

ThreadProc()
{
  tick = QueryPerformanceCounter() - tick;
  RETAILMSG(TRUE, (_T("ET: %i\r\n"), tick));
}

분명히 반복해서 하고 평균을 내는 것이 더 나을 것이다.이것은 단순히 컨텍스트 스위치를 측정하는 것이 아니라는 것을 명심하십시오.계속 진행하기 위한 통화도 측정하는 중이고스레드와 스케줄러가 즉시 다른 스레드로 전환할 것이라는 보장은 없다(우선순위 10은 스레드가 될 확률을 높이는 데 도움이 될 것이다).

스케줄러 이벤트에 연결하면 CeLog로 보다 정확한 측정을 얻을 수 있지만, 하기에는 너무 간단하고 문서화도 잘 되지 않는다.만약 당신이 정말로 그 길을 가고 싶다면, Sue Loh는 검색엔진이 찾을 수 있는 블로그를 몇 개 가지고 있다.

비코드 경로는 원격 커널 트래커를 사용하는 것이 될 것이다.이 버전을 가져오려면 eVC 4.0 또는 Platform Builder 평가 버전을 설치하십시오.그것은 커널이 하고 있는 모든 것을 그래픽으로 표시해 줄 것이고 당신은 제공된 커서 기능으로 스레드 컨텍스트 스위치를 직접 측정할 수 있다.다시 말하지만, 나는 Sue가 커널 트래커 사용에 대한 블로그도 가지고 있다고 확신한다.

CE 프로세스 내 스레드 컨텍스트 스위치가 정말, 정말 빠르다는 것을 알게 될 겁니다.프로세스 스위치는 RAM에서 활성 프로세스를 스와핑한 후 마이그레이션을 수행해야 하므로 비용이 많이 든다.

나는 단지 한번만 이것을 추정하려고 노력했고 그것은 486에 있었다!결론은 프로세서 컨텍스트 스위치가 완료하기 위해 약 70개의 지침을 취하고 있다는 것이었습니다(참고 이는 스레드 스위칭뿐만 아니라 많은 OS api 호출에도 일어나고 있음).우리는 DX3의 스레드 스위치(OS 오버헤드 포함)당 약 30us가 소요된다고 계산했다.초당 몇 천 개의 컨텍스트 스위치가 프로세서 시간의 5-10%를 흡수하고 있었다.

그것이 멀티코어 멀티-ghz 현대 프로세서로 어떻게 해석될지는 모르겠지만, 나는 당신이 스레드를 완전히 넘기지 않는 한 무시할 수 있는 오버헤드라고 추측할 수 있다.

스레드 생성/삭제는 스레드를 활성화/비활성화하는 것보다 더 비싼 CPU/OS 호거라는 점에 유의하십시오.스레드가 많은 앱에 대한 좋은 정책은 스레드 풀을 사용하고 필요에 따라 활성화/비활성화하는 것이다.

참조URL: https://stackoverflow.com/questions/304752/how-to-estimate-the-thread-context-switching-overhead

반응형