Afinidade de threads com Windows, MSVC e OpenMP
Quero vincular os threads no meu código a cada núcleo físico. Com o GCC, fiz isso com sucesso usandosched_setaffinity
então não preciso mais definirexport OMP_PROC_BIND=true
. Eu quero fazer a mesma coisa no Windows com MSVC. Windows e Linux usando uma topologia de encadeamento diferente. O Linux dispersa os threads enquanto o Windows usa um formato compacto. Em outras palavras, no Linux com quatro núcleos e oito hiper-threads, eu só preciso vincular os threads às quatro primeiras unidades de processamento. No Windows, eu os defino em todas as outras unidades de processamento.
Eu fiz isso com sucesso usandoSetProcessAffinityMask
. Consigo ver no Gerenciador de tarefas do Windows quando clico com o botão direito do mouse nos processos e clico em "Definir afinidade" que todas as outras CPUs estão definidas (0, 2, 4, 6 no meu sistema de oito hiper threads). O problema é que a eficiência do meu código é instável quando executo. Às vezes é quase constante, mas na maioria das vezes tem grandes mudanças. Mudei a prioridade para alta, mas não faz diferença. No Linux, a eficiência é estável. Talvez o Windows ainda esteja migrando os threads? Há algo mais que preciso fazer para vincular os threads no Windows?
Aqui está o código que estou usando
#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
Edit: aqui está o código que usei agora que parece estável no Linux e 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