공유 메모리 환경 (예 : OpenMP, Pthreads 또는 TBB를 통해 스레드)에서 메모리 대역폭 제한 계산을 수행 할 때 각 스레드가 대부분의 메모리에 액세스 하도록 메모리가 실제 메모리에 올바르게 분산되도록하는 방법에는 딜레마가 있습니다. "로컬"메모리 버스. 인터페이스는 이식성이 없지만 대부분의 운영 체제에는 스레드 선호도를 설정하는 방법이 있습니다 (예 : pthread_setaffinity_np()
많은 POSIX 시스템, sched_setaffinity()
Linux, SetThreadAffinityMask()
Windows). 메모리 계층을 결정하기위한 hwloc 과 같은 라이브러리도 있지만 불행히도 대부분의 운영 체제는 아직 NUMA 메모리 정책을 설정하는 방법을 제공하지 않습니다. libnuma 와 함께 Linux는 주목할만한 예외입니다 .응용 프로그램이 페이지 단위로 메모리 정책 및 페이지 마이그레이션을 조작 할 수 있도록합니다 (2004 년 이후의 주요 내용). 다른 운영 체제에서는 사용자가 암시적인 "첫 번째 터치"정책을 준수해야합니다.
"first touch"정책으로 작업한다는 것은 호출자가 새로 할당 된 메모리에 처음 쓸 때 나중에 사용하려는 선호도를 가진 스레드를 작성하고 분배해야 함을 의미합니다. ( malloc()
실제로 페이지를 찾도록 구성되는 시스템은 거의 없으며 , 실제로는 다른 스레드에 의해 오류가 발생했을 때 해당 페이지를 찾도록 약속합니다.) 이는 사용 calloc()
후 할당을 사용 하거나 즉시 메모리를 초기화 하는 할당 memset()
은 결함이 있기 때문에 해롭다는 것을 의미합니다 할당 스레드를 실행하는 코어의 메모리 버스에있는 모든 메모리로 인해 여러 스레드에서 메모리에 액세스 할 때 최악의 메모리 대역폭이 발생합니다. new
많은 새로운 할당을 초기화 해야하는 C ++ 연산자 에도 동일하게 적용됩니다 (예 :std::complex
). 이 환경에 대한 몇 가지 관찰 :
- 할당은 "스레드 집합"으로 만들 수 있지만, 이제는 스레딩 모델에 할당이 혼합되어 다른 스레딩 모델을 사용하여 클라이언트와 상호 작용해야하는 라이브러리에는 바람직하지 않습니다 (각각 자체 스레드 풀이 있음).
- RAII는 관용적 C ++의 중요한 부분으로 여겨지지만 NUMA 환경에서 메모리 성능에 적극적으로 유해한 것 같습니다. 배치
new
는를 통해 할당 된 메모리malloc()
또는에서 루틴 과 함께 사용할 수libnuma
있지만 할당 프로세스가 변경됩니다 (필요하다고 생각합니다). - 편집 : 연산자
new
에 대한 내 이전 진술 이 잘못되었습니다. 여러 인수를 지원할 수 있습니다. Chetan의 답변을 참조하십시오. 라이브러리 또는 STL 컨테이너가 지정된 선호도를 사용하도록하는 데 여전히 우려가 있다고 생각합니다. 여러 필드가 압축 될 수 있으며, 예를 들어std::vector
올바른 컨텍스트 관리자가 활성화 된 상태 에서 재 할당 되는 것이 불편할 수 있습니다 . - 각 스레드는 자체 개인 메모리를 할당하고 오류를 일으킬 수 있지만 인접 영역으로 인덱싱하는 것이 더 복잡합니다. (희소 행렬 - 벡터 제품 고려 매트릭스 및 벡터의 로우 격벽과;의 소유되지 않은 부분의 색인 더 복잡한 데이터 구조를 필요로하는 경우 가상 메모리에서 연속이 아니다.)
NUMA 할당 / 초기화에 대한 솔루션이 관용어로 간주됩니까? 다른 중요한 문제를 배제 했습니까?
(저는 C ++ 예제가 그 언어에 중점을 두는 것을 의미하지는 않지만 C ++ 언어 는 C와 같은 언어가 아닌 메모리 관리에 대한 일부 결정을 인코딩하므로 C ++ 프로그래머가 그렇게 할 것을 제안 할 때 더 많은 저항이있는 경향이 있습니다 상황이 다릅니다.)