1 gpu 用に作成した関数があり、1 セットの引数で 10 秒間実行され、通過する引数の非常に長いリストがあります。AMD gpu の両方を使用したいので、2 つのスレッドを起動し、引数 gpu_idx 0 を持つスレッド 0 と引数 gpu_idx 1 を持つスレッド 1 で関数を実行するラッパー コードがあります。
別のマシン用のcudaバージョンがあり、実行checkCudaErrors(cudaSetDevice((unsigned int)device_id));
して目的の動作を取得するだけです。
openCL を使用して、次のことを試みました。
void createDevice(int device_idx)
{
cl_device_id *devices;
ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
HANDLE_CLERROR_G(ret);
ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_ALL, 0, NULL, &ret_num_devices);
HANDLE_CLERROR_G(ret);
devices = (cl_device_id*)malloc(ret_num_devices*sizeof(cl_device_id));
ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_ALL, ret_num_devices, devices, &ret_num_devices);
HANDLE_CLERROR_G(ret);
if (device_idx >= ret_num_devices)
{
fprintf(stderr, "Found %i devices but asked for device at index %i\n", ret_num_devices, device_idx);
exit(1);
}
device_id = devices[device_idx];
// usleep(((unsigned int)(500000*(1-device_idx)))); // without this line multithreaded 2 gpu execution does not work.
context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);
HANDLE_CLERROR_G(ret);
}
context は *c ファイル内の静的変数であり、後でカーネルを作成するときに再度使用します。
このコードは、device_idx 0 のみ、または device_idx 1 のみで実行した場合に機能し、2 つのターミナル ウィンドウで手動で実行可能ファイルを device_idx 0 と device_idx 1 で「同時に」実行した場合でも機能します。
しかし、スレッドが「あまりにも」同時実行されているため、このコードが機能しません。実際、スリープの量 (上記のコメント) に応じて、異なる動作が得られます (両方のスレッドが gpu 0 で動作する場合もあれば、両方のスレッドが gpu 1 で動作する場合もあり、両方のスレッドが両方の gpu でバランスが取れている場合もあります)。睡眠時間が短すぎるCL_INVALID_CONTEXT
と、次のようになります。まったく眠らないと、次のようになりますCL_INVALID_KERNEL_NAME
。
私が言ったように、gpu 0 または gpu 1 だけで実行している場合はエラーは発生しません。スレッド 0 の device_idx 0 と同時に、このコードを呼び出す複数のスレッドを (go から extern C 関数を使用して *so として) 生成する場合のみです。スレッド 1 の device_idx 1。
どうすれば問題を解決できますか? 私は、1 つの GPU で動作する実行可能ファイルがあり、そのためにどの GPU を指定するかという考えに執着しており、その仕様を尊重する必要があります。
両方のデバイスを使用する必要があり、一方が他方から完全に分離されている場合、デバイスを選択する適切な方法は何ですか?