Сходство потоков с Windows, MSVC и OpenMP
Я хочу связать потоки в моем коде с каждым физическим ядром. С GCC я успешно сделал это с помощью sched_setaffinity
так что мне больше не нужно устанавливать export OMP_PROC_BIND=true
, Я хочу сделать то же самое в Windows с MSVC. Windows и Linux используют разные топологии потоков. Linux рассеивает потоки, в то время как Windows использует компактную форму. Другими словами, в Linux с четырьмя ядрами и восемью гиперпотоками мне нужно только связать потоки с первыми четырьмя процессорами. В окнах я установил их на любой другой процессор.
Я успешно сделал это с помощью SetProcessAffinityMask
, Я могу видеть из диспетчера задач Windows, когда я щелкаю правой кнопкой мыши по процессам и нажимаю "Установить сходство", что все остальные процессоры установлены (0, 2, 4, 6 в моей системе с восемью гиперпотоками). Проблема в том, что эффективность моего кода нестабильна при запуске. Иногда это почти постоянно, но в большинстве случаев это большие изменения. Я изменил приоритет на высокий, но это не имеет значения. В Linux эффективность стабильна. Может быть, Windows все еще переносит потоки? Есть ли что-то еще, что мне нужно сделать, чтобы связать темы в Windows?
Вот код, который я использую
#ifdef _WIN32
HANDLE process;
DWORD_PTR processAffinityMask = 0;
//Windows uses a compact thread topology. Set mask to every other thread
for(int i=0; i<ncores; i++) processAffinityMask |= 1<<(2*i);
//processAffinityMask = 0x55;
process = GetCurrentProcess();
SetProcessAffinityMask(process, processAffinityMask);
#else
cpu_set_t mask;
CPU_ZERO(&mask);
for(int i=0; i<ncores; i++) CPU_SET(i, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
#endif
Изменить: вот код, который я использовал сейчас, который кажется стабильным на Linux и Windows
#ifdef _WIN32
HANDLE process;
DWORD_PTR processAffinityMask;
//Windows uses a compact thread topology. Set mask to every other thread
for(int i=0; i<ncores; i++) processAffinityMask |= 1<<(2*i);
process = GetCurrentProcess();
SetProcessAffinityMask(process, processAffinityMask);
#pragma omp parallel
{
HANDLE thread = GetCurrentThread();
DWORD_PTR threadAffinityMask = 1<<(2*omp_get_thread_num());
SetThreadAffinityMask(thread, threadAffinityMask);
}
#else
cpu_set_t mask;
CPU_ZERO(&mask);
for(int i=0; i<ncores; i++) CPU_SET(i, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
#pragma omp parallel
{
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(omp_get_thread_num(),&mask);
pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask);
}
#endif
1 ответ
Вы должны использовать SetThreadAffinityMask
функция (см. справочник MSDN). Вы устанавливаете маску процесса.
Вы можете получить thread ID
в OpenMP с этим кодом:
int tid = omp_get_thread_num();
Однако приведенный выше код обеспечивает внутреннюю поддержку OpenMP thread ID
а не система thread ID
, Эта статья объясняет больше по теме:
http://msdn.microsoft.com/en-us/magazine/cc163717.aspx
если вам нужно явно работать с этими цепями - используйте явные affinity type
как объяснено в этой документации Intel: