1

openMPを使用して別々のCPUで2つのプロセスを実行しようとしています。この場合、各CPUにはハイパースレッディングを備えた6つのコアがあります(つまり、12のハードウェアスレッド)。彼らは、お互いのPIDを知っていれば、いくらか簡単に思える同期を行う必要があります。そのため、環境変数に別の値を使用してとを使用してプロセスsigCを開始しています。呼び出し後、まだ正しいアフィニティがありますが、印刷されますsigSfork()execve()GOMP_CPU_AFFINITYfork()/execve()sigSsigC

libgomp: no cpus left for affinity setting

そして、すべてのスレッドは同じコア上にあります。

のコードsigS

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <omp.h>
#include <sched.h>

int main( void )
{
   omp_set_num_threads(12); //12 hardware threads per CPU
   //this loop runs as expected
   #pragma omp parallel for
   for( int i = 0; i<12; i++ ) {
      #pragma omp critical 
      {
         printf("TEST PRE-FORK: I am thread %2d running on core %d\n",
                omp_get_thread_num(), sched_getcpu());
      }
   }

   pid_t childpid = fork();

   if( childpid < 0 ) {
      perror("Fork failed");
   } else {
      if( childpid == 0 ) { //<------ attempt to set affinity for child
         //change the affinity for the other process so it runs
         //on the other cpu
         char ompEnv[] = "GOMP_CPU_AFFINITY=6-11 18-23"; 
         char * const args[]    = { "./sigC", (char*)0 };
         char * const envArgs[] = { ompEnv,   (char*)0 };
         execve(args[0], args, envArgs);
         perror("Returned from execve");
         exit(1);
      } else {
         omp_set_num_threads(12);
         printf("PARENT: my pid     = %d\n", getpid());
         printf("PARENT: child pid  = %d\n", childpid);
         sleep(5); //sleep for a bit so child process prints first

         //This loop gives the same thread core/pairings as above
         //this is expected
         #pragma omp parallel for
         for( int i = 0; i < 12; i++ ) {
            #pragma omp critical
            {
               printf("PARENT: I'm thread %2d, on core %d.\n",
                      omp_get_thread_num(), sched_getcpu());
            }
         }
      }
   }
   return 0;
}

のコードにsigCは、完全性のために、omp並列のforループが含まれています。

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <omp.h>
#include <sched.h>

int main( void )
{
   omp_set_num_threads(12);
   printf("CHILD: my pid     = %d\n", getpid());
   printf("CHILD: parent pid = %d\n", getppid());
   //I expect this loop to have the core pairings as I specified in execve
   //i.e thread 0 -> core 6, 1 -> 7, ... 6 -> 18, 7 -> 19 ... 11 -> 23
   #pragma omp parallel for
   for( int i = 0; i < 12; i++ ) {
      #pragma omp critical
      {
         printf("CHILD: I'm thread %2d, on core %d.\n",
                omp_get_thread_num(), sched_getcpu());
      }
   }
   return 0;
}

出力:

$ env GOMP_CPU_AFFINITY="0-5 12-17" ./sigS

この部分は予想通りです

TEST PRE-FORK: I'm thread  0, on core 0.
TEST PRE-FORK: I'm thread 11, on core 17.
TEST PRE-FORK: I'm thread  5, on core 5.
TEST PRE-FORK: I'm thread  6, on core 12.
TEST PRE-FORK: I'm thread  3, on core 3.
TEST PRE-FORK: I'm thread  1, on core 1.
TEST PRE-FORK: I'm thread  8, on core 14.
TEST PRE-FORK: I'm thread 10, on core 16.
TEST PRE-FORK: I'm thread  7, on core 13.
TEST PRE-FORK: I'm thread  2, on core 2.
TEST PRE-FORK: I'm thread  4, on core 4.
TEST PRE-FORK: I'm thread  9, on core 15.
PARENT: my pid     = 11009
PARENT: child pid  = 11021

これが問題です-子のすべてのスレッドはコア0で実行されます

libgomp: no CPUs left for affinity setting
CHILD: my pid     = 11021
CHILD: parent pid = 11009
CHILD: I'm thread  1, on core 0.
CHILD: I'm thread  0, on core 0.
CHILD: I'm thread  4, on core 0.
CHILD: I'm thread  5, on core 0.
CHILD: I'm thread  6, on core 0.
CHILD: I'm thread  7, on core 0.
CHILD: I'm thread  8, on core 0.
CHILD: I'm thread  9, on core 0.
CHILD: I'm thread 10, on core 0.
CHILD: I'm thread 11, on core 0.
CHILD: I'm thread  3, on core 0.

(親糸印刷はプリフォークと同じなので省略しました)

これを修正する方法や、それが正しいアプローチであるかどうかについてのアイデアはありますか?

4

1 に答える 1

3

-ed子プロセスはfork()、その親アフィニティマスクを継承します。libgompこのアフィニティマスクをfromのセットと交差GOMP_CPU_AFFINITYさせ、両方のセットが相補的であるため、空のセットになります。この動作は文書化されていませんが、のソースコードを見ると、libgompこれが実際に当てはまることを確認できます。

execve()解決策は、呼び出しを行う前に子プロセスのアフィニティマスクをリセットすることです。

if (childpid == 0) { //<------ attempt to set affinity for child
   cpu_set_t *mask;
   size_t size;
   int nrcpus = 256; // 256 CPUs should be more than enough

   // Reset the CPU affinity mask
   mask = CPU_ALLOC(nrcpus);
   size = CPU_ALLOC_SIZE(nrcpus);
   for (int i = 0; i < nrcpus; i++)
      CPU_SET_S(i, size, mask);
   if (sched_setaffinity(0, size, mask) == -1) { handle error }
   CPU_FREE(mask);

   //change the affinity for the other process so it runs
   //on the other cpu
   char ompEnv[] ="GOMP_CPU_AFFINITY=6-11 18-23"; 
   char * const args[]    = {"./sigC", (char*)0};
   char * const envArgs[] = {ompEnv,   (char*)0};
   execve(args[0], args, envArgs);
   perror("Returned from execve");
   exit(1);
} else {
于 2013-03-06T21:22:18.680 に答える