prosource

스레드를 생성할 때 CPU 선호도 설정

probook 2023. 10. 20. 13:50
반응형

스레드를 생성할 때 CPU 선호도 설정

첫 번째 코어에서 실행할 C++11 스레드를 생성하고 싶습니다.나는 그것을 발견합니다.pthread_setaffinity_np그리고.sched_setaffinity스레드의 CPU 선호도를 변경하고 지정된 CPU로 마이그레이션할 수 있습니다.그러나 이 선호도 사양은 스레드가 실행된 후 변경됩니다.

특정 CPU 선호도를 가진 C++11 스레드를 생성하는 방법(acpu_set_t목적)?

C++11 스레드를 초기화할 때 친화도를 지정할 수 없다면 C 내에서 어떻게 해야 합니까?

저의 환경은 우분투의 G++입니다.코드 조각을 감사히 받겠습니다.

여기서 "신비한 버스터"가 되어 유감스럽지만, 스레드 친화성 설정은 매우 중요하며, 우리 모두가 사용하는 시스템이 자연스럽게 NUMA(Non-Uniform Memory Architecture)가 점점 더 많아짐에 따라 시간이 지남에 따라 그 중요성이 더욱 커집니다.요즘은 사소한 듀얼 소켓 서버라도 각 소켓에 별도의 RAM이 연결되어 있고, 소켓에서 자체 RAM으로, 인접 프로세서 소켓(원격 RAM)으로 메모리에 대한 액세스 차이가 상당합니다.가까운 미래에 프로세서는 내부 코어 집합 자체가 NUMA인 시장에 출시되고 있습니다(코어 그룹 등을 별도로 사용하는 메모리 컨트롤러 등).여기서 다른 사람들의 작업을 반복할 필요는 없으며, 온라인에서 "NUMA 및 스레드 친화도"를 찾아 보십시오. 다른 엔지니어들의 다년간의 경험을 통해 배울 수 있습니다.

스레드 선호도를 설정하지 않는 것은 OS 스케줄러가 스레드 선호도를 올바르게 처리하는 "희망"과 효과적으로 같습니다.제가 설명해 드리겠습니다.일부 NUMA 노드(프로세싱 및 메모리 도메인)가 있는 시스템이 있습니다.스레드를 시작하면 스레드는 메모리로 어떤 일을 수행합니다. 예를 들어 메모리를 malloc하고 처리합니다.현대의 OS(최소한 Linux, 다른 OS도 마찬가지일 가능성이 있음)는 지금까지 잘 작동하고 있으며, 기본적으로 메모리는 스레드가 실행 중인 CPU의 동일한 도메인에서 할당됩니다.시간을 공유하는 OS(모든 최신 OS)가 스레드를 잠재울 것입니다.스레드가 다시 실행 상태가 되면 시스템의 모든 코어에서 스레드를 실행할 수 있게 될 수 있으며(선호도 마스크를 설정하지 않았기 때문에), 시스템의 크기가 클수록 이전에 할당하거나 사용한 메모리와 원격인 CPU에서 스레드가 "웨이크업"될 가능성이 높습니다.이제 모든 메모리 액세스가 원격으로 수행됩니다(애플리케이션 성능에 어떤 의미가 있는지 잘 모르십니까?).NUMA 시스템의 원격 메모리 액세스에 대해 온라인으로 자세히 알아보기)

따라서 요약하자면, 요즘 "모든 시스템"으로 급속히 변화하고 있는 사소한 아키텍처를 가진 시스템에서 코드를 실행할 때 친화도 설정 인터페이스는 매우 중요합니다.일부 스레드 런타임 환경/립은 특정 프로그래밍 없이 런타임에 이를 제어할 수 있도록 허용합니다(예: 인텔의 KMP_AFFINITY 환경 변수 구현에서 OpenMP 참조). C++11 구현자가 런타임 리브 및 언어 옵션에 유사한 메커니즘을 포함하는 것이 옳습니다(그리고 그 전까지는 y인 경우).우리의 코드는 서버에서 사용하기 위한 것입니다. 코드에 친화도 제어를 구현하는 것을 강력히 권장합니다.)

네, 만드는 방법이 있습니다.이 블로그 링크에서 우연히 이 방법을 발견했습니다.

Eli Bendersky 블로그에 코드를 다시 작성해보니 위에 링크가 붙여져 있었습니다.아래 코드를 test.cpp에 저장하고 컴파일하여 실행할 수 있습니다.

 // g++ ./test.cpp  -lpthread && ./a.out
// 
#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
#include <sched.h>
#include <pthread.h>
int main(int argc, const char** argv) {
  constexpr unsigned num_threads = 4;
  // A mutex ensures orderly access to std::cout from multiple threads.
  std::mutex iomutex;
  std::vector<std::thread> threads(num_threads);
  for (unsigned i = 0; i < num_threads; ++i) {
    threads[i] = std::thread([&iomutex, i,&threads] {
      // Create a cpu_set_t object representing a set of CPUs. Clear it and mark
      // only CPU i as set.
      cpu_set_t cpuset;
      CPU_ZERO(&cpuset);
      CPU_SET(i, &cpuset);
      int rc = pthread_setaffinity_np(threads[i].native_handle(),
                                      sizeof(cpu_set_t), &cpuset);
      if (rc != 0) {
        std::cerr << "Error calling pthread_setaffinity_np: " << rc << "\n";
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(20));
      while (1) {
        {
          // Use a lexical scope and lock_guard to safely lock the mutex only
          // for the duration of std::cout usage.
          std::lock_guard<std::mutex> iolock(iomutex);
          std::cout << "Thread #" << i << ": on CPU " << sched_getcpu() << "\n";
        }

        // Simulate important work done by the tread by sleeping for a bit...
        std::this_thread::sleep_for(std::chrono::milliseconds(900));
      }
    });


  }

  for (auto& t : threads) {
    t.join();
  }
  return 0;
}

C++ 11에서는 스레드가 생성될 때 스레드 선호도를 설정할 수 없지만, 스레드가 생성되면 스레드에 대한 네이티브 핸들(thread.native_handle())을 가져와 네이티브 인터페이스를 통해 선호도를 설정할 수 있습니다.리눅스의 경우 다음을 통해 pthread ID를 얻을 수 있습니다.

pthread_tmy_thread_native =my_thread.native_handle();

그러면 pthread 스레드 ID를 원하는 곳에 my_thread_native를 통과하는 pthread 호출을 사용할 수 있습니다.

대부분의 스레드 기능은 구현에 특정적이라는 점, 즉 pthreads, window threads, native threads for 다른 OS들은 모두 고유한 인터페이스를 가지고 있으며 코드의 이 부분은 매우 휴대성이 좋지 않을 것입니다.

잠시 검색해보니 C++를 생성할 때 CPU 친화도를 설정할 수 없는 것 같습니다.thread.

스레드를 생성할 때 선호도를 지정할 필요가 없기 때문입니다.그래서 왜 굳이 언어로 가능하게 만드나요?

예, 우리는 작업량을 필요로 합니다.f()CPU0에 바인딩됩니다.실제 워크로드 직전에 선호도를 CPU0으로 변경하면 됩니다.pthread_setaffinity_np.

그러나 C에서 스레드를 생성할 때 (Tony D의 코멘트 덕분에) 친화도를 지정할 수 있습니다.예를 들어, 다음 코드는 "Hello pthread"를 출력합니다.

void *f(void *p) {
  std::cout<<"Hello pthread"<<std::endl;
}

cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
pthread_attr_t pta;
pthread_attr_init(&pta);
pthread_attr_setaffinity_np(&pta, sizeof(cpuset), &cpuset);
pthread_t thread;
if (pthread_create(&thread, &pta, f, NULL) != 0) {
    std::cerr << "Error in creating thread" << std::endl;
}
pthread_join(thread, NULL);
pthread_attr_destroy(&pta);

언급URL : https://stackoverflow.com/questions/24645880/set-cpu-affinity-when-create-a-thread

반응형