【问题标题】:cudaDeviceReset for multiple gpu's多个 gpu 的 cudaDeviceReset
【发布时间】:2013-06-17 17:36:30
【问题描述】:

我目前正在使用具有 4 个 Tesla T10 gpu 的 gpu 服务器。当我不断测试内核并且不得不经常使用 ctrl-C 终止进程时,我在一个简单的设备查询代码的末尾添加了几行代码。代码如下:

#include <stdio.h>

 // Print device properties
 void printDevProp(cudaDeviceProp devProp)
{
    printf("Major revision number:         %d\n",  devProp.major);
    printf("Minor revision number:         %d\n",  devProp.minor);
    printf("Name:                          %s\n",  devProp.name);
    printf("Total global memory:           %u\n",  devProp.totalGlobalMem);
    printf("Total shared memory per block: %u\n",  devProp.sharedMemPerBlock);
    printf("Total registers per block:     %d\n",  devProp.regsPerBlock);
    printf("Warp size:                     %d\n",  devProp.warpSize);
    printf("Maximum memory pitch:          %u\n",  devProp.memPitch);
    printf("Maximum threads per block:     %d\n",  devProp.maxThreadsPerBlock);
    for (int i = 0; i < 3; ++i)
    printf("Maximum dimension %d of block:  %d\n", i, devProp.maxThreadsDim[i]);
    for (int i = 0; i < 3; ++i)
    printf("Maximum dimension %d of grid:   %d\n", i, devProp.maxGridSize[i]);
    printf("Clock rate:                    %d\n",  devProp.clockRate);
    printf("Total constant memory:         %u\n",  devProp.totalConstMem);
    printf("Texture alignment:             %u\n",  devProp.textureAlignment);
    printf("Concurrent copy and execution: %s\n",  (devProp.deviceOverlap ? "Yes" : "No"));
    printf("Number of multiprocessors:     %d\n",  devProp.multiProcessorCount);
    printf("Kernel execution timeout:      %s\n",  (devProp.kernelExecTimeoutEnabled ? "Yes" : "No"));
    return;
}

 int main()
{
    // Number of CUDA devices
    int devCount;
    cudaGetDeviceCount(&devCount);
    printf("CUDA Device Query...\n");
    printf("There are %d CUDA devices.\n", devCount);

    // Iterate through devices
    for (int i = 0; i < devCount; ++i)
    {
        // Get device properties
        printf("\nCUDA Device #%d\n", i);
        cudaDeviceProp devProp;
        cudaGetDeviceProperties(&devProp, i);
        printDevProp(devProp);
    }

    printf("\nPress any key to exit...");
    char c;
    scanf("%c", &c);

    **for (int i = 0; i < devCount; i++) {
        cudaSetDevice(i);
        cudaDeviceReset();
    }**

    return 0;
}

我的查询与 main() 结束之前的 for 循环有关,在该循环中我一一设置每个设备,然后使用 cudaResetDevice 命令。我有一种奇怪的感觉,这段代码虽然没有产生任何错误,但我无法重置所有设备。相反,程序每次只重置默认设备,即设备 0。谁能告诉我我应该怎么做才能重置 4 个设备中的每一个。

谢谢

【问题讨论】:

    标签: cuda


    【解决方案1】:

    看起来您可以向 GPU 程序添加一个函数来捕获 ctrl+c 信号 (SIGINT) 并为程序使用的每个设备调用 cudaDeviceReset() 函数。

    捕捉到 SIGINT 时调用函数的示例代码可以在这里找到:

    https://stackoverflow.com/a/482725

    在你编写的每个 GPU 程序中包含这样的代码似乎是一个好习惯,我也会这样做:-)

    我没有时间写一个完整的详细答案,所以请阅读另一个答案,它也是 cmets。

    【讨论】:

      【解决方案2】:

      这可能为时已晚,但如果您编写信号处理函数,您可以消除内存泄漏并以可靠的方式重置设备:

      // State variables for 
      extern int no_sigint;
      int no_sigint = 1;
      extern int interrupts;
      int interrupts = 0;
      
      /* Catches signal interrupts from Ctrl+c.
         If 1 signal is detected the simulation finishes the current frame and
         exits in a clean state. If Ctrl+c is pressed again it terminates the
         application without completing writes to files or calculations but
         deallocates all memory anyway. */
      void
      sigint_handler (int sig)
      {
        if (sig == SIGINT)
          {
            interrupts += 1;
            std::cout << std::endl
                      << "Aborting loop.. finishing frame."
                      << std::endl;
      
            no_sigint = 0;
      
            if (interrupts >= 2)
              {
                std::cerr << std::endl
                          << "Multiple Interrupts issued: "
                          << "Clearing memory and Forcing immediate shutdown!"
                          << std::endl;
      
                // write a function to free dynamycally allocated memory
                free_mem ();
      
                int devCount;
                cudaGetDeviceCount (&devCount);
      
                for (int i = 0; i < devCount; ++i)
                  {
                    cudaSetDevice (i);
                    cudaDeviceReset ();
                  }
                exit (9);
              }
          }
      }
      

      ....

      int main(){ 
      .....
      for (int simulation_step=1 ; simulation_step < SIM_STEPS && no_sigint; ++simulation_step)
      {
         .... simulation code
      }
      free_mem();
      ... cuda device resets
      return 0;
      }
      

      如果您使用此代码(您甚至可以将第一个 sn-p 包含在外部标头中,它可以工作。您可以对 ctrl+c 进行 2 个级别的控制:第一次按下会停止您的模拟并正常退出,但应用程序完成渲染步骤,这很适合优雅地停止并获得正确的结果,如果再次按 ctrl+c 它将关闭应用程序以释放所有内存。

      【讨论】:

        【解决方案3】:

        cudaDeviceReset 旨在销毁与运行它的进程中的给定 GPU 上下文相关联的资源。一个 CUDA 进程不能重置或以其他方式影响另一个进程的上下文。因此,当您修改后的设备查询调用cudaDeviceReset 时,它只会释放它分配的资源,而不是任何其他进程正在使用的资源。

        【讨论】:

        • 感谢您的及时回复。那么我应该如何去一一重置每个设备。为了获得 devcount,无论如何我都必须调用 cudaGetDeviceCount。这会在默认设备 0 中启动上下文吗?您能否建议一种确保为每个 gpu 设备显式清除 gpu 内存的方法?谢谢
        • 在 CUDA 4.0 中,您需要在执行任何其他操作之前调用 cudaSetDevice。但我重复一遍,cudaDeviceReset 仅重置执行的程序已完成的操作。如果 GPU 由于另一个进程所做的事情而处于“坏”状态,则它无法重置或以其他方式影响该状态。在驱动程序中实现了对上下文的基本保护,明确防止了这种情况。
        • 所以,如果我必须在中间使用 ctrl-C 终止一个内核,然后如果我使用上面提到的程序来清除资源,那么你的意思是说它会是徒劳的,可能由于突然终止而没有被擦除的全局设备内存不会被清理?
        • 您能否为这个问题提出一个解决方案,因为我肯定会在开发阶段使用 ctrl-C 故意终止我的内核。目前我只能想到重启机器作为一种解决方案,但非常烦人。另外,非常感谢您的及时回复。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-03
        • 1970-01-01
        • 1970-01-01
        • 2021-02-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多