Cuda内核没有并发运行

标签 c concurrency cuda

最初我问的是,由于某种原因,当我指定不同的流时,我的内核拒绝并发运行。这个问题现在已经解决了,但是我仍然不清楚它们的并发行为。

我知道我的系统可以运行多个流,因为 concurrentKernels CUDA 示例运行良好。我还可以扩展此示例,使其模仿我的代码并且它仍然同时运行。 提前为大量代码道歉。 我想将其全部发布,因为可能有一件小事阻止了我的内核同时运行,或者我认为这可能与具有结构或许多单独的文件有关。此外,我相信在尝试帮助我时它对你们所有人都有用!我刚刚编写了以下简化程序来复制我的问题:

测试主程序

#include <stdlib.h>
#include <signal.h>
#include "test.h"

#define Nsim 900000
#define Ncomp 20

Vector* test1;
Vector* test2;
Vector* test3;

cudaStream_t stream1;
cudaStream_t stream2;
cudaStream_t stream3;

int
main (int argc, char **argv)
{
    test1 = Get_Vector(Nsim);
    test2 = Get_Vector(Nsim);
    test3 = Get_Vector(Nsim);

    checkGPU( cudaStreamCreate(&stream1) );
    checkGPU( cudaStreamCreate(&stream2) );
    checkGPU( cudaStreamCreate(&stream3) );

    int x = 0;
    for (x = 0; x < Ncomp; x++)
    {
      computeGPU(test1, test2, test3, x);
      checkGPU( cudaThreadSynchronize() );
    }
    checkGPU( cudaThreadSynchronize() );

    checkGPU( cudaStreamDestroy(stream1) );
    checkGPU( cudaStreamDestroy(stream2) );
    checkGPU( cudaStreamDestroy(stream3) );

    Free_Vector(test1);
    Free_Vector(test2);
    Free_Vector(test3);

    checkGPU( cudaDeviceReset() );
    exit(EXIT_SUCCESS);
}

基础.c

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "basics.h"

inline void gpuAssert(cudaError_t code, const char *file, int line)
{
  if (code != cudaSuccess) 
    {
      fprintf(stderr,"CUDA error: %s %s %d\n", cudaGetErrorString(code), file, line);
      exit(EXIT_FAILURE);
    }
}

基础.h

#ifndef _BASICS_H
#define _BASICS_H

#include <cuda_runtime.h>

#define checkGPU(ans) { gpuAssert((ans), __FILE__, __LINE__); }

void gpuAssert(cudaError_t code, const char *file, int line);

#endif // _BASICS_H

测试.cu

extern "C"
{
#include "test.h"
}

__global__ void compute(int* in, int x)
{
  int i = blockIdx.x*blockDim.x + threadIdx.x;
  in[i] = (int) (x * + 1.05 / 0.4);
}

extern "C" void
computeGPU(Vector* in1, Vector* in2, Vector* in3, int x)
{
  int threadsPerBlock = 256;
  int blocksPerGrid = (in1->N + threadsPerBlock - 1) / threadsPerBlock;
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream1>>>(in1->d_data, x);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream2>>>(in2->d_data, x);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream3>>>(in3->d_data, x);
}

测试.h

#ifndef _TEST_H
#define _TEST_H

#include "vector.h"
#include "basics.h"
#include <cuda_runtime.h>

extern cudaStream_t stream1;
extern cudaStream_t stream2;
extern cudaStream_t stream3;

extern void computeGPU(Vector* in1, Vector* in2, Vector* in3, int x);

#endif // _TEST_H

vector .c

#include <stdlib.h>
#include "vector.h"
#include "basics.h"

Vector*
Get_Vector(int N)
{
  Vector* v = (Vector*) calloc(1, sizeof(Vector));
  v->N = N;
  checkGPU( cudaMalloc((void**) &v->d_data, N * sizeof(int)) );
  return v;
}

void
Free_Vector(Vector* in)
{
  checkGPU( cudaFree(in->d_data) );
  free(in);
}

vector .h

#ifndef _VECTOR_H
#define _VECTOR_H

typedef struct
{
    int N;
    int* d_data;
} Vector;

extern Vector* Get_Vector(int N);

extern void Free_Vector(Vector* in);

#endif // _VECTOR_H

我编译:

nvcc -gencode arch=compute_20,code=sm_20 -O3 -use_fast_math -lineinfo -o test testMain.c test.cu basics.c vector.c; time ./test

并让单独的内核在 nvvp 中运行:

Kernels running serially instead of concurrently.

在 Roberts 的帮助下,我通过减少 Nsim 解决了这个问题。

  1. 如果像我的问题一样 Nsim 很大 (900000),则 GPU 充满了 block ,因此即使在单独的流中指定,也无法同时运行我的内核。配置文件结果如上。
  2. 如果 Nsim 很小 (900),理论上内核可以同时运行,但是我的内核非常简单,它们完成得比启动下一个内核的开销要快,因此整个模拟只是 Launch Compute(int* ,int,int) 在 RuntimeAPI 行中。配置文件结果如下所示 profile results with small Nsim (900)

  3. 如果我更改我的内核和代码,使内核运行时间更长(并将 Nsim 设置为合理的值,3000,现在不重要):

测试.cu

__global__ void compute(int* in, int x, int y)
{
  int i = blockIdx.x*blockDim.x + threadIdx.x;
  in[i] = (int) (x * + 1.05 / 0.4);

  int clock_count = 5000000 * y;
  clock_t start_clock = clock();
  clock_t clock_offset = 0;
  while (clock_offset < clock_count)
  {
    clock_offset = clock() - start_clock;
  }
}

extern "C" void
computeGPU(Vector* in1, Vector* in2, Vector* in3, int x)
{
  int threadsPerBlock = 256;
  int blocksPerGrid = (in1->N + threadsPerBlock - 1) / threadsPerBlock;
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream1>>>(in1->d_data, x, 1);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream2>>>(in2->d_data, x, 2);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream3>>>(in3->d_data, x, 3);
}

我的内核现在并发运行,等待三个内核完成,然后再启动下三个内核,因为我在我的循环中同步: kernels running concurrently

  1. 但是,如果通过以下更改启动我的内核,我希望因为我在循环中启动我的所有内核,然后然后同步,所有内核都应该背靠背运行,而最快的只是完成运行的 1/3,第二个 2/3,最后一个和终点。这里发生了什么? CUDA 是否在施展魔法,意识到它无论如何都必须等待长内核完成,以便以某种方式更加优化以穿插运行其他内核?内核全部启动,运行时仅等待一个同步(这可以在 RuntimeAPI 行中看到)。

测试主程序

int x = 0;
for (x = 0; x < Ncomp; x++)
{
  computeGPU(test1, test2, test3, x);
  //checkGPU( cudaThreadSynchronize() );
}
checkGPU( cudaThreadSynchronize() );

kernels running concurrent but not as expected

  1. 此外,使用以下命令启动内核非常困惑,并非预期的那样。当然,它们可以比这更好地同步,两个内核花费相同的时间运行(1x3 和 3x1),另一个正好适合在某个地方运行这些内核的时间。

测试.cu

extern "C" void
computeGPU(Vector* in1, Vector* in2, Vector* in3, int x)
{
  int threadsPerBlock = 256;
  int blocksPerGrid = (in1->N + threadsPerBlock - 1) / threadsPerBlock;
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream1>>>(in1->d_data, x, 1);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream1>>>(in1->d_data, x, 1);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream1>>>(in1->d_data, x, 1);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream2>>>(in2->d_data, x, 2);
  compute<<<blocksPerGrid, threadsPerBlock, 0, stream3>>>(in3->d_data, x, 3);
}

confusing results

最佳答案

http://on-demand.gputechconf.com/gtc-express/2011/presentations/StreamsAndConcurrencyWebinar.pdf

请查看幻灯片 18,了解有关提交并发内核的有效顺序的说明。

有音频: https://developer.nvidia.com/gpu-computing-webinars

寻找 cuda 并发和流。

关于Cuda内核没有并发运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28364356/

相关文章:

exception - 在CUDA内核中触发运行时错误

c - 接收 SMTP 消息

c - 链表内存图

C 如何将 strcat 与静态偏移量字符数组一起使用

Java Hashmap 之类的数据结构,在获取时锁定键值对并在放回时解锁 - 为了爬虫的礼貌

database - Hibernate,高并发问题

c - Xcode 错误 : "Undefined symbols for architecture x86_64: "_addStudent", 从 : _main in main. o 引用

JAVA的 future 是运行?

c++ - Cuda:将设备常量声明为模板

c++ - 出现错误: “nvlink error : Undefined reference to ' _ZN8Strategy8backtestEPddd'”