C++ 在我的cuda运行时程序中,cpu和gpu可以异步计算,但不能协同计算,为什么?
在我的cuda运行时程序中,cpu和gpu可以异步计算,但不能协同计算,为什么 我测量程序的时间,总时间是cpu计算时间和gpu计算时间的总和。通过可视化配置文件,我发现gpu在cpu完成之前不会计算。我的目的是cpu的计算与gpu的计算相同 站台: 窗口10C++ 在我的cuda运行时程序中,cpu和gpu可以异步计算,但不能协同计算,为什么?,c++,cuda,C++,Cuda,在我的cuda运行时程序中,cpu和gpu可以异步计算,但不能协同计算,为什么 我测量程序的时间,总时间是cpu计算时间和gpu计算时间的总和。通过可视化配置文件,我发现gpu在cpu完成之前不会计算。我的目的是cpu的计算与gpu的计算相同 站台: 窗口10 cuda 7.5 vs2013 在调试模式下编译的代码(无优化) #包括“cuda_runtime.h” #包括“设备启动参数.h” #包括 #包括 __全局\uuuu_uu无效addKernel() { INTA; 对于(int i=0
cuda 7.5
vs2013 在调试模式下编译的代码(无优化)
#包括“cuda_runtime.h”
#包括“设备启动参数.h”
#包括
#包括
__全局\uuuu_uu无效addKernel()
{
INTA;
对于(int i=0;i<10000;i++)
对于(int j=0;j<10000;j++)
a=i;
}
无效计算机()
{
INTA=1;
对于(int i=0;i<10000;i++)
对于(int j=0;j<10000;j++)
{
对于(int k=0;k<100;k++)
a=j;
}
}
int main()
{
cudaSetDevice(0);
cudaEvent\u t启动,停止1;
cudaEventCreate(&start);
cudaEventCreate(&stop1);
时钟=时钟();
cudaEventRecord(开始,0);
addKernel();
cudaEventRecord(stop1,0);
时钟=时钟();
计算机();
clock_t ctt=clock();
cudaEventSynchronize(stop1);
cudaDeviceSynchronize();
时钟=时钟();
浮动t1;
CUDAEVENTERSEPDTIME(&t1,start,stop1);
printf(“时钟GPU:%.4fsn”,t1/1000);
printf(“时钟cpu:%f s\n”,(浮点)(ctt-ct)/每秒时钟数);
printf(“时钟总时间:%f s\n”,(浮点)(sss-ss)/每秒时钟数);
cudaEventDestroy(启动);
cudaEventDestroy(stop1);
cudaDeviceReset();
}
来自:
通过将CUDA_LAUNCH_BLOCKING环境变量设置为1,程序员可以全局禁用系统上运行的所有CUDA应用程序内核启动的异步性。此功能仅用于调试目的,不应用作使生产软件可靠运行的方法
如果通过探查器(Nsight,visualprofiler)收集硬件计数器,则内核启动是同步的。除非启用了并发内核评测。如果异步内存拷贝涉及未锁定页的主机内存,则它们也将是同步的
此外,如果没有优化,主机函数将运行很长时间,可能是内核的百万倍。如果使用优化,它实际上不会运行任何东西,并立即返回
我建议尝试分别使用CUDA\u LAUNCH\u BLOCKING=1和CUDA\u LAUNCH\u BLOCKING=0运行二进制文件,以测试运行时间。还要将内核和主机函数修改为有意义的函数。来自:
通过将CUDA_LAUNCH_BLOCKING环境变量设置为1,程序员可以全局禁用系统上运行的所有CUDA应用程序内核启动的异步性。此功能仅用于调试目的,不应用作使生产软件可靠运行的方法
如果通过探查器(Nsight,visualprofiler)收集硬件计数器,则内核启动是同步的。除非启用了并发内核评测。如果异步内存拷贝涉及未锁定页的主机内存,则它们也将是同步的
此外,如果没有优化,主机函数将运行很长时间,可能是内核的百万倍。如果使用优化,它实际上不会运行任何东西,并立即返回
我建议尝试分别使用CUDA\u LAUNCH\u BLOCKING=1和CUDA\u LAUNCH\u BLOCKING=0运行二进制文件,以测试运行时间。还要将内核和主机函数修改为有意义的函数。这里有几个问题(可能)在起作用:
- 如果您使用的是WDDM驱动程序(与TCC驱动程序相反),那么内核启动会被分批处理,以减少WDDM驱动程序较高启动开销的影响。这意味着驱动程序将推迟启动
addKernel()
等待更多的工作,直到遇到cudaEventSynchronize()
调用⁾ 但是此时,comput()
已经完成。
因此,在您的示例中,CPU和GPU的工作确实不是并行运行的,但是GPU上的addKernel()
实际上是在CPU上的comput()
之后运行的。
在调用comput()
之前,可以防止(进一步)批处理并强制立即启动addKernel()
addKernel()
和compute()
没有外部可见的效果(它们只设置局部变量a
),编译器可能会对其进行完全优化。在调试模式下编译可能不会阻止所有这些优化。这将使演示异步执行变得更加困难,因为您只需要测量内核启动和计时开销。
因此,将它们替换为执行实际工作的代码,如向量求和,并将结果存储到全局变量
- 正如halfelf在他的回答中指出的,分析器可以在特定条件下同步启动内核
⑨⁾ 如果一段时间内没有进一步的工作,等待也可能超时,并且在调用cudaEventSynchronize()
之前可能会启动addKernel()
。这里可能有几个问题:
- 如果您使用的是WDDM驱动程序(与TCC驱动程序相反),那么内核启动会被分批处理,以减少WDDM驱动程序较高启动开销的影响。这意味着驱动程序将推迟启动
addKernel()
等待更多的工作,直到遇到cudaEventSynchronize()
调用⁾ 但是此时,comput()
已经完成。
因此,在您的示例中,CPU和GPU的工作确实不是并行运行的,但是addKernel()
在GPU上运行
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include<time.h>
__global__ void addKernel()
{
int a ;
for (int i = 0; i < 10000;i++)
for (int j = 0; j < 10000;j++)
a = i;
}
void comput()
{
int a = 1;
for (int i = 0; i < 10000;i++)
for (int j = 0; j < 10000; j++)
{
for (int k = 0; k < 100;k++)
a = j;
}
}
int main()
{
cudaSetDevice(0);
cudaEvent_t start, stop1;
cudaEventCreate(&start);
cudaEventCreate(&stop1);
clock_t ss = clock();
cudaEventRecord(start,0);
addKernel<<<1,64>>>();
cudaEventRecord(stop1,0);
clock_t ct = clock();
comput();
clock_t ctt = clock();
cudaEventSynchronize(stop1);
cudaDeviceSynchronize();
clock_t sss = clock();
float t1;
cudaEventElapsedTime(&t1, start, stop1);
printf("clock GPU :%.4f s\n", t1/1000);
printf("clock cpu:%f s\n",(float) (ctt - ct)/CLOCKS_PER_SEC);
printf("clock total time: %f s\n", (float)(sss - ss) / CLOCKS_PER_SEC);
cudaEventDestroy(start);
cudaEventDestroy(stop1);
cudaDeviceReset();
}