属性:Win 10,VS 2013,CUDA 7.5,GeForce 920M 两种情况都没有任何错误或警告。两种情况的输出均为SAME。唯一的区别是:
在第二种情况下,Stream2和Stream3不存在。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "../../common/common.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
__global__ void kernel1(char *value){
for (int i = 0; i < 100; i++){
printf("%s\n", value);
}
}
__global__ void kernel2(){
cudaStream_t s1, s2;
cudaStreamCreateWithFlags(&s1, cudaStreamNonBlocking);
cudaStreamCreateWithFlags(&s2, cudaStreamNonBlocking);
kernel1 << < 1, 1, 0, s1 >> >("up stream");
kernel1 << < 1, 1, 0, s2 >> >("bottom stream");
}
int main(int argc, char **argv){
printf("%s Starting...\n", argv[0]); // set up device
int dev = 0;
cudaDeviceProp deviceProp;
CHECK(cudaGetDeviceProperties(&deviceProp, dev));
printf("Using Device %d: %s\n", dev, deviceProp.name);
CHECK(cudaSetDevice(dev));
// FIRST CASE
//cudaStream_t s1, s2;
//cudaStreamCreateWithFlags(&s1, cudaStreamNonBlocking);
//cudaStreamCreateWithFlags(&s2, cudaStreamNonBlocking);
//kernel1 << <1, 1, 0, s1 >> >();
//kernel1 << <1, 1, 0, s2 >> >();
//SECOND CASE
kernel2 << < 1, 1>> >();
CHECK(cudaDeviceSynchronize());
CHECK(cudaGetLastError()); // check kernel error
CHECK(cudaDeviceReset()); // reset device
printf("\nEnd\n");
getchar();
return (0);
}
我还添加了common.h
#include <time.h>
#include <stdio.h>
#ifndef _COMMON_H
#define _COMMON_H
#define CHECK(call) \
{ \
const cudaError_t error = call; \
if (error != cudaSuccess) \
{ \
fprintf(stderr, "Error: %s:%d, ", __FILE__, __LINE__); \
fprintf(stderr, "code: %d, reason: %s\n", error, \
cudaGetErrorString(error)); \
getchar();exit(1); \
} \
}
#define CHECK_CUBLAS(call) \
{ \
cublasStatus_t err; \
if ((err = (call)) != CUBLAS_STATUS_SUCCESS) \
{ \
fprintf(stderr, "Got CUBLAS error %d at %s:%d\n", err, __FILE__, \
__LINE__); \
getchar();exit(1); \
} \
}
#define CHECK_CURAND(call) \
{ \
curandStatus_t err; \
if ((err = (call)) != CURAND_STATUS_SUCCESS) \
{ \
fprintf(stderr, "Got CURAND error %d at %s:%d\n", err, __FILE__, \
__LINE__); \
getchar();exit(1); \
} \
}
#define CHECK_CUFFT(call) \
{ \
cufftResult err; \
if ( (err = (call)) != CUFFT_SUCCESS) \
{ \
fprintf(stderr, "Got CUFFT error %d at %s:%d\n", err, __FILE__, \
__LINE__); \
getchar();exit(1); \
} \
}
#define CHECK_CUSPARSE(call) \
{ \
cusparseStatus_t err; \
if ((err = (call)) != CUSPARSE_STATUS_SUCCESS) \
{ \
fprintf(stderr, "Got error %d at %s:%d\n", err, __FILE__, __LINE__); \
cudaError_t cuda_err = cudaGetLastError(); \
if (cuda_err != cudaSuccess) \
{ \
fprintf(stderr, " CUDA error \"%s\" also detected\n", \
cudaGetErrorString(cuda_err)); \
} \
getchar();exit(1); \
} \
}
clock_t seconds()
{
return clock();
}
#endif // _COMMON_H
答案 0 :(得分:1)
两种可能性:
当您对各种并发感兴趣时,Windows WDDM模式不是GPU的最佳操作模式。这在许多其他地方都有涉及,例如this recent SO question。
您正在使用的工具(nsight VSE)可能无法向您提供最佳信息,否则您可能会误解它(您还没有提供您所看到的截图。)< / p>
你应该注意的另一件事是你的GT 920M(GK208)是一个相当低端的GPU,它可能在内核并发方面受到限制,因为它只有2个SM,但我不认为这是这个具体案例的限制因素。
我修改了你发布的代码以取消注释kernel2的启动(因为那是你要问的那个)并在CUDA 7.5,Fedora 20,GT 640(也使用GK208)上运行它。没有做任何其他更改,这是我在linux上的nvvp
中看到的输出:
我们看到的是:
kernel1首先显示,在两个不同的流中启动两次。这对应于你的主机端启动kernel1,我们在这里看到内核并发。
之后,kernel2从主机启动。它会根据您的代码启动到默认流中,并以nvvp
的方式显示。此外,我们注意到nvvp
计算时间轴中的kernel2在其持续时间的第一部分显示为实心条,在其持续时间的最后部分显示为空心条。这表示kernel2的所有线程都已在实心栏的末尾完成,但由于implicit child kernel synchronization associated with CDP而导致kernel2完成。
在这个&#34;空心区域&#34;在时间轴上的kernel2,我们还看到了2个kernel1的新实例。这两个新实例相互重叠,表明正确的并发性,并且在这两个子内核完成时,父内核2启动也完成。
基本上,当我使用nvvp
在linux上运行它时,一切看起来都是正确的。如果你想以无限的方式探索并发,我绝对推荐Windows TCC模式或Linux over Windows WDDM模式。但是,大多数GeForce GPU无法进入TCC模式。您可能会问为什么子内核启动时没有为它们确定单独的流时间轴。我不知道答案,但我认为这是某种工具限制。可能还有一个&#34;演示文稿&#34;问题:父内核属于默认流,因此它的子内核也会这样做(即使你必须为它们创建单独的流以实现并发目的)。如果这让您感到困扰,您可以考虑在developer.nvidia.com上提交增强请求(包含关键字RFE的错误)