Cuda 内核不是 运行 并发
Cuda kernels not running concurrent
最初我问的是,由于某种原因,当我指定不同的流时,我的内核拒绝同时 运行。这个问题现在已经解决了,但是我仍然不清楚它们的并发行为。
我知道我的系统可以 运行 多个流,因为 concurrentKernels CUDA 示例 运行 很好。我还可以扩展此示例,使其模仿我的代码,并且它仍然 运行 并发。 提前为大量代码道歉。 我想要 post 这一切,因为可能有一件小事同时阻塞了我的内核 运行 或者我认为这可能与结构或许多独立的部分有关文件。此外,我相信在尝试帮助我时它对你们所有人都有用! 我刚刚编写了以下简化程序来复制我的问题:
testMain.c
#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);
}
basics.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);
}
}
basics.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
test.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);
}
test.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 中获取单独的内核 运行ning:
在 Roberts 的帮助下,我通过减少 Nsim 解决了这个问题。
- 如果 Nsim 像我的问题一样大 (900000),则 GPU 充满了块,因此即使在单独的流中指定,也无法同时 运行 我的内核。剖析结果如上
如果 Nsim 很小(900),理论上内核可以 运行 并发,但是我的内核非常简单,它们比启动下一个内核的开销更快完成,因此整个模拟只是 RuntimeAPI 行中的 Launch Compute(int*,int,int)。配置文件结果如下所示
如果我对我的内核和代码进行更改,使内核需要更长的时间才能运行(并将 Nsim 设置为合理的值,3000,现在不重要):
test.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);
}
我的内核现在 运行 在启动下三个内核之前同时等待三个内核完成,因为我在我的循环中同步:
- 但是,如果启动我的内核并进行以下更改,我希望因为我在循环中启动我的所有内核然后 然后 同步,内核应该全部 运行 背靠背,最快的只完成了 运行 的 1/3,第二个 2/3,最后一个和终点。这里发生了什么? CUDA 是否在施展魔法,意识到它无论如何都必须等待长内核完成,以便以某种方式更优化地散布 运行 其他内核?内核都已启动,运行时间只是在等待一个同步(这可以在 RuntimeAPI 行中看到)。
testMain.c
int x = 0;
for (x = 0; x < Ncomp; x++)
{
computeGPU(test1, test2, test3, x);
//checkGPU( cudaThreadSynchronize() );
}
checkGPU( cudaThreadSynchronize() );
- 此外,使用以下命令启动内核非常混乱,不是预期的那样。当然,他们可以比这更好地同步,两个内核花费相同的时间到 运行(1x3 和 3x1),另一个正好适合 运行 这些地方的时间。
test.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);
}
http://on-demand.gputechconf.com/gtc-express/2011/presentations/StreamsAndConcurrencyWebinar.pdf
请查看幻灯片 18,了解有关提交并发内核的有效顺序的说明。
带音频:
https://developer.nvidia.com/gpu-computing-webinars
寻找 cuda 并发和流。
最初我问的是,由于某种原因,当我指定不同的流时,我的内核拒绝同时 运行。这个问题现在已经解决了,但是我仍然不清楚它们的并发行为。
我知道我的系统可以 运行 多个流,因为 concurrentKernels CUDA 示例 运行 很好。我还可以扩展此示例,使其模仿我的代码,并且它仍然 运行 并发。 提前为大量代码道歉。 我想要 post 这一切,因为可能有一件小事同时阻塞了我的内核 运行 或者我认为这可能与结构或许多独立的部分有关文件。此外,我相信在尝试帮助我时它对你们所有人都有用! 我刚刚编写了以下简化程序来复制我的问题:
testMain.c
#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);
}
basics.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);
}
}
basics.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
test.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);
}
test.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 中获取单独的内核 运行ning:
在 Roberts 的帮助下,我通过减少 Nsim 解决了这个问题。
- 如果 Nsim 像我的问题一样大 (900000),则 GPU 充满了块,因此即使在单独的流中指定,也无法同时 运行 我的内核。剖析结果如上
如果 Nsim 很小(900),理论上内核可以 运行 并发,但是我的内核非常简单,它们比启动下一个内核的开销更快完成,因此整个模拟只是 RuntimeAPI 行中的 Launch Compute(int*,int,int)。配置文件结果如下所示
如果我对我的内核和代码进行更改,使内核需要更长的时间才能运行(并将 Nsim 设置为合理的值,3000,现在不重要):
test.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);
}
我的内核现在 运行 在启动下三个内核之前同时等待三个内核完成,因为我在我的循环中同步:
- 但是,如果启动我的内核并进行以下更改,我希望因为我在循环中启动我的所有内核然后 然后 同步,内核应该全部 运行 背靠背,最快的只完成了 运行 的 1/3,第二个 2/3,最后一个和终点。这里发生了什么? CUDA 是否在施展魔法,意识到它无论如何都必须等待长内核完成,以便以某种方式更优化地散布 运行 其他内核?内核都已启动,运行时间只是在等待一个同步(这可以在 RuntimeAPI 行中看到)。
testMain.c
int x = 0;
for (x = 0; x < Ncomp; x++)
{
computeGPU(test1, test2, test3, x);
//checkGPU( cudaThreadSynchronize() );
}
checkGPU( cudaThreadSynchronize() );
- 此外,使用以下命令启动内核非常混乱,不是预期的那样。当然,他们可以比这更好地同步,两个内核花费相同的时间到 运行(1x3 和 3x1),另一个正好适合 运行 这些地方的时间。
test.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);
}
http://on-demand.gputechconf.com/gtc-express/2011/presentations/StreamsAndConcurrencyWebinar.pdf
请查看幻灯片 18,了解有关提交并发内核的有效顺序的说明。
带音频: https://developer.nvidia.com/gpu-computing-webinars
寻找 cuda 并发和流。