▶ CPU - GPU 异步操作

▶ 源代码

 #include <stdio.h>
#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <helper_cuda.h>
#include <helper_functions.h> __global__ void increment_kernel(int *g_data, int inc_value)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
g_data[idx] = g_data[idx] + inc_value;
} bool correct_output(int *data, const int n, const int x)
{
for (int i = ; i < n; i++)
{
if (data[i] != x)
{
printf("Error! data[%d] = %d, ref = %d\n", i, data[i], x);
return false;
}
}
return true;
} int main(int argc, char *argv[])
{
printf("Start.\n");
int devID = findCudaDevice(argc, (const char **)argv); // 通过命令行参数选择设备,可以为空
cudaDeviceProp deviceProps;
cudaGetDeviceProperties(&deviceProps, devID);
printf("CUDA device [%s]\n", deviceProps.name); const int n = * * ;
const int nbytes = n * sizeof(int);
const int value = ; int *a, *d_a;
cudaMallocHost((void **)&a, nbytes);
cudaMalloc((void **)&d_a, nbytes);
memset(a, , nbytes);
cudaMemset(d_a, , nbytes); cudaEvent_t start, stop; // GPU 端计时器
cudaEventCreate(&start);
cudaEventCreate(&stop); StopWatchInterface *timer = NULL; // CPU 端计时器
sdkCreateTimer(&timer);
sdkResetTimer(&timer); dim3 threads = dim3(, , );
dim3 blocks = dim3(n / threads.x, , ); sdkStartTimer(&timer); // 注意 GPU 计时器是夹在 CPU 计时器内的,但是 GPU 函数都是异步的
cudaEventRecord(start, );
cudaMemcpyAsync(d_a, a, nbytes, cudaMemcpyHostToDevice, );
increment_kernel << <blocks, threads, , >> > (d_a, value);
cudaMemcpyAsync(a, d_a, nbytes, cudaMemcpyDeviceToHost, );
cudaEventRecord(stop, );
sdkStopTimer(&timer); unsigned long int counter = ; // 记录 GPU 运行完成以前 CPU 运行了多少次 while 的循环
while (cudaEventQuery(stop) == cudaErrorNotReady)
counter++; float gpu_time = 0.0f; // 此时保证 GPU 运行完成,才能记录时间
cudaEventElapsedTime(&gpu_time, start, stop); printf("time spent by GPU: %.2f\n", gpu_time);
printf("time spent by CPU: %.2f\n", sdkGetTimerValue(&timer));
printf("CPU executed %lu iterations while waiting for GPU to finish\n", counter);
printf("\n\tFinish: %s.", correct_output(a, n, value) ? "Pass" : "Fail"); cudaEventDestroy(start);
cudaEventDestroy(stop);
cudaFreeHost(a);
cudaFree(d_a);
getchar();
return ;
}

● 输出结果:

GPU Device : "GeForce GTX 1070" with compute capability 6.1

CUDA device [GeForce GTX ]
time spent by GPU: 11.50
time spent by CPU: 0.05
CPU executed iterations while waiting for GPU to finish Finish!

▶ 新姿势:

● 调用主函数时的第0个参数作为程序名字符串,可以用于输出。

 int main(int argc, char *argv[])
...
printf("%s", argv[]);

● 在没有附加 flag 的情况下申请主机内存,注意使用cudaFreeHost释放

 int *a, nbytes = n * sizeof(int);
cudaMallocHost((void **)&a, nbytes);
...
cudaFreeHost(a);

● 记录 CPU 调用 CUDA 所用的时间

 StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkResetTimer(&timer);
sdkStartTimer(&timer); ...// 核函数调用 sdkStopTimer(&timer);
printf("%.2f ms", sdkGetTimerValue(&timer));

● 查看GPU队列状态的函数

extern __host__ cudaError_t CUDARTAPI cudaEventQuery(cudaEvent_t event);

■ stop为放置到流中的一个事件,cudaEventQuery(stop)返回该事件的状态,等于cudaSuccess(值等于0)表示已经发生;等于cudaErrorNotReady(值等于35)表示尚未发生。源代码中利用这段时间让CPU空转,记录了迭代次数。

while (cudaEventQuery(stop) == cudaErrorNotReady) counter++;

● stdlib.h 中关于返回成功和失败的宏

 #define EXIT_SUCCESS 0
#define EXIT_FAILURE 1

● 示例文件中的错误检查函数(定义在helper_cuda.h中),报告出错文件、行号、函数名,并且重启cudaDevice。

 #define checkCudaErrors(val)  check((val), #val, __FILE__, __LINE__)

 template< typename T >
void check(T result, char const *const func, const char *const file, int const line)
{
if (result)
{
fprintf(stderr, "CUDA error at %s:%d code=%d(%s) \"%s\" \n",
file, line, static_cast<unsigned int>(result), _cudaGetErrorEnum(result), func);
DEVICE_RESET// Make sure we call CUDA Device Reset before exiting
exit(EXIT_FAILURE);
}
} #define DEVICE_RESET cudaDeviceReset();

0_Simple__asyncAPI的更多相关文章

随机推荐

  1. 转载 iOS拦截导航栏返回按钮事件的正确方式

    原文链接:http://www.jianshu.com/p/25fd027916fa 当我们使用了系统的导航栏时,默认点击返回按钮是 pop 回上一个界面.但是在有时候,我们需要在点击导航栏的返回按钮 ...

  2. /MD、/MT、/LD( 使用 多线程版本 运行时库的C runtime library)

    /MD./MT./LD(使用运行时库)(微软官网解释) Visual C++ 编译器选项 /MD./ML./MT./LD 区别 指定与你项目连接的运行期库 /MT多线程应用程序 /Mtd多线程应用程序 ...

  3. VPS修改SSH端口不小心把自己给墙掉的一般解决办法

    很多人配置服务器的时候都习惯将 SSH 端口改为其他端口,以规避批量端口扫描,但也有不少人改完端口却忘了去防火墙修改端口,导致 SSH 登陆不上. 昨天我就这么干了 我把SSH端口从22改成了2345 ...

  4. SGU180(树状数组,逆序对,离散)

    Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: sta ...

  5. php用PHPWord库生成word文档的例子

    <?php require_once '../libs/PHPWord/PHPWord/IOFactory.php'; require_once '../../config.php'; $PHP ...

  6. 使用下一代web开发框架koa2搭建自己的轻服务器

    Koa 是由 Express 原班人马亲情打造的新一代web框架.既然已经有 Express 了,为什么又要搞一个Koa出来呢?因为 Koa 相比 Express 体积更小,代码更健壮,作用更纯粹. ...

  7. Git命令(1)

    windows中文乱码: http://www.cnblogs.com/Gukw/archive/2012/01/16/2323417.html 学习地址 :http://www.liaoxuefen ...

  8. bind、apply与call

    bind.apply与call 先说观点:不论是bind.apply还是call,最大的好处就是代码复用. bind 在开发中,我们只有复用代码时,才会出现this指向需要改动的情况. 纵观bind的 ...

  9. WPF 设置输入只能英文

    有时输入只能让用户输入英文,那么如何设置输入只能英文? 首先在xaml 写一个 TextBox ,给他一个名字. <TextBox x:Name="txt"></ ...

  10. win10 UWP 全屏

    win10 可以全屏软件或窗口,窗口有一般.最小化.最大化.我们有新的API设置我们软件是全屏,是窗口.我们可以使用ApplicationView让我们软件全屏,取消. 下面是一个简单的例子,判断我们 ...