CUDA流表示一个GPU操作队列,该队列中的操作将以添加到流中的先后顺序而依次执行。可以将一个流看做是GPU上的一个任务,不同任务可以并行执行。使用CUDA流,首先要选择一个支持设备重叠(Device Overlap)功能的设备,支持设备重叠功能的GPU能够在执行一个CUDA核函数的同时,还能在主机和设备之间执行复制数据操作。

支持重叠功能的设备的这一特性很重要,可以在一定程度上提升GPU程序的执行效率。一般情况下,CPU内存远大于GPU内存,对于数据量比较大的情况,不可能把CPU缓冲区中的数据一次性传输给GPU,需要分块传输,如果能够在分块传输的同时,GPU也在执行核函数运算,这样的异步操作,就用到设备的重叠功能,能够提高运算性能。

以下程序演示单个流的使用步骤,对比使用流操作的性能提升,不使用流的情况:

#include "cuda_runtime.h"
#include <iostream>
#include <stdio.h>
#include <math.h> #define N (1024*1024)
#define FULL_DATA_SIZE N*20 __global__ void kernel(int* a, int *b, int*c)
{
int threadID = blockIdx.x * blockDim.x + threadIdx.x; if (threadID < N)
{
c[threadID] = (a[threadID] + b[threadID]) / 2;
}
} int main()
{
//启动计时器
cudaEvent_t start, stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0); int *host_a, *host_b, *host_c;
int *dev_a, *dev_b, *dev_c; //在GPU上分配内存
cudaMalloc((void**)&dev_a, FULL_DATA_SIZE * sizeof(int));
cudaMalloc((void**)&dev_b, FULL_DATA_SIZE * sizeof(int));
cudaMalloc((void**)&dev_c, FULL_DATA_SIZE * sizeof(int)); //在CPU上分配可分页内存
host_a = (int*)malloc(FULL_DATA_SIZE * sizeof(int));
host_b = (int*)malloc(FULL_DATA_SIZE * sizeof(int));
host_c = (int*)malloc(FULL_DATA_SIZE * sizeof(int)); //主机上的内存赋值
for (int i = 0; i < FULL_DATA_SIZE; i++)
{
host_a[i] = i;
host_b[i] = FULL_DATA_SIZE - i;
} //从主机到设备复制数据
cudaMemcpy(dev_a, host_a, FULL_DATA_SIZE * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, host_b, FULL_DATA_SIZE * sizeof(int), cudaMemcpyHostToDevice); kernel << <FULL_DATA_SIZE / 1024, 1024 >> > (dev_a, dev_b, dev_c); //数据拷贝回主机
cudaMemcpy(host_c, dev_c, FULL_DATA_SIZE * sizeof(int), cudaMemcpyDeviceToHost); //计时结束
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop); std::cout << "消耗时间: " << elapsedTime << std::endl; //输出前10个结果
for (int i = 0; i < 10; i++)
{
std::cout << host_c[i] << std::endl;
} getchar(); cudaFreeHost(host_a);
cudaFreeHost(host_b);
cudaFreeHost(host_c); cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c); return 0;
}

使用流:

#include "cuda_runtime.h"
#include <iostream>
#include <stdio.h>
#include <math.h> #define N (1024*1024)
#define FULL_DATA_SIZE N*20 __global__ void kernel(int* a, int *b, int*c)
{
int threadID = blockIdx.x * blockDim.x + threadIdx.x; if (threadID < N)
{
c[threadID] = (a[threadID] + b[threadID]) / 2;
}
} int main()
{
//获取设备属性
cudaDeviceProp prop;
int deviceID;
cudaGetDevice(&deviceID);
cudaGetDeviceProperties(&prop, deviceID); //检查设备是否支持重叠功能
if (!prop.deviceOverlap)
{
printf("No device will handle overlaps. so no speed up from stream.\n");
return 0;
} //启动计时器
cudaEvent_t start, stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0); //创建一个CUDA流
cudaStream_t stream;
cudaStreamCreate(&stream); int *host_a, *host_b, *host_c;
int *dev_a, *dev_b, *dev_c; //在GPU上分配内存
cudaMalloc((void**)&dev_a, N * sizeof(int));
cudaMalloc((void**)&dev_b, N * sizeof(int));
cudaMalloc((void**)&dev_c, N * sizeof(int)); //在CPU上分配页锁定内存
cudaHostAlloc((void**)&host_a, FULL_DATA_SIZE * sizeof(int), cudaHostAllocDefault);
cudaHostAlloc((void**)&host_b, FULL_DATA_SIZE * sizeof(int), cudaHostAllocDefault);
cudaHostAlloc((void**)&host_c, FULL_DATA_SIZE * sizeof(int), cudaHostAllocDefault); //主机上的内存赋值
for (int i = 0; i < FULL_DATA_SIZE; i++)
{
host_a[i] = i;
host_b[i] = FULL_DATA_SIZE - i;
} for (int i = 0; i < FULL_DATA_SIZE; i += N)
{
cudaMemcpyAsync(dev_a, host_a + i, N * sizeof(int), cudaMemcpyHostToDevice, stream);
cudaMemcpyAsync(dev_b, host_b + i, N * sizeof(int), cudaMemcpyHostToDevice, stream); kernel << <N / 1024, 1024, 0, stream >> > (dev_a, dev_b, dev_c); cudaMemcpyAsync(host_c + i, dev_c, N * sizeof(int), cudaMemcpyDeviceToHost, stream);
} // wait until gpu execution finish
cudaStreamSynchronize(stream); cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop); std::cout << "消耗时间: " << elapsedTime << std::endl; //输出前10个结果
for (int i = 0; i < 10; i++)
{
std::cout << host_c[i] << std::endl;
} getchar(); // free stream and mem
cudaFreeHost(host_a);
cudaFreeHost(host_b);
cudaFreeHost(host_c); cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c); cudaStreamDestroy(stream);
return 0;
}

首先声明一个Stream,可以把不同的操作放到Stream内,按照放入的先后顺序执行。

cudaMemcpyAsync操作只是一个请求,表示在流中执行一次内存复制操作,并不能确保cudaMemcpyAsync函数返回时已经启动了复制动作,更不能确定复制操作是否已经执行完成,可以确定的是放入流中的这个复制动作一定是在其后 放入流中的其他动作之前完成的。使用流(同时要使用页锁定内存)和不使用流的结果一致,运算时间分别是30ms和50ms。

CUDA流(Stream)的更多相关文章

  1. CUDA 7 Stream流简化并发性

    CUDA 7 Stream流简化并发性 异构计算是指高效地使用系统中的所有处理器,包括 CPU 和 GPU .为此,应用程序必须在多个处理器上并发执行函数. CUDA 应用程序通过在 streams  ...

  2. cuda流测试=basic_single_stream

    cuda流测试 /* * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. * * NVIDIA Corporation and ...

  3. JAVA基础知识之IO——IO流(Stream)的概念

    Java IO 流 Java将不同的设备或载体(键盘.文件.网络.管道等)的输入输出数据统称为"流"(Stream),即JAVA的IO都是基于流的. JAVA传统的所有流类型类都包 ...

  4. [Linux] 流 ( Stream )、管道 ( Pipeline ) 、Filter - 笔记

    流 ( Stream ) 1. 流,是指可使用的数据元素一个序列. 2. 流,可以想象为是传送带上等待加工处理的物品,也可以想象为工厂流水线上的物品. 3. 流,可以是无限的数据. 4. 有一种功能, ...

  5. 【stanford C++】字符串(String)与流(Stream)

    字符串(String)与流(Stream) 一.C++中字符串(String) 字符串(String):就是(可能是空的)字符序列. C++中的字符串在概念上和Java中的字符串类似. C++字符串用 ...

  6. nodeJS之流stream

    前面的话 当内存中无法一次装下需要处理的数据时,或者一边读取一边处理更加高效时,我们就需要用到数据流.NodeJS中通过各种Stream来提供对数据流的操作.本文将详细说明NodeJS中的流strea ...

  7. c#中字节数组byte[]、图片image、流stream,字符串string、内存流MemoryStream、文件file,之间的转换

    字节数组byte[]与图片image之间的转化 字节数组转换成图片 public static Image byte2img(byte[] buffer) { MemoryStream ms = ne ...

  8. Java笔记:Java 流(Stream)、文件(File)和IO

    更新时间:2018-1-7 12:27:21 更多请查看在线文集:http://android.52fhy.com/java/index.html java.io 包几乎包含了所有操作输入.输出需要的 ...

  9. Java - 17 Java 流(Stream)、文件(File)和IO

    Java 流(Stream).文件(File)和IO Java.io包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io包中的流支持很多种格式,比如:基本类型. ...

随机推荐

  1. [Angular] Component architecture and Reactive Forms

    It it recommeded that when deals with form component, we can create a container component to hold st ...

  2. element ui源码解析 -- input篇

    el-input是element ui中使用最频繁的组件之一了,分析其构成从四个方面入手:DOM结构,属性,样式,事件入手 DOM结构: <div> <input /> < ...

  3. [TypeScript] Define a function type

    type DigitValidator = (char) => boolean; -]{}/.test(char); export const digitValidators: {[key: s ...

  4. C API函数描写叙述(S-W)

    25.2.3.59. mysql_select_db() int mysql_select_db(MYSQL *mysql, const char *db) 描写叙述 使由db指定的数据库成为由mys ...

  5. css3-6 表格如何设置样式和定位样式是什么

    css3-6 表格如何设置样式和定位样式是什么 一.总结 一句话总结:css可以解决所有属性设置的样式. 1.表格如何设置样式? css样式可以解决一切问题,没必要在表格上面加属性来设置样式. 7 t ...

  6. Thinking in UML 学习笔记(二)——UML核心视图之用例图

    在UML中,需求模型又称为用例模型,它主要用于描述系统的功能性需求,即软件可以实现的功能,如登录.注册.入库.出库.查看库存报表.增加员工信息等.常规的用例建模一般包括两个组成部分:绘制用例图和编写用 ...

  7. <Linux> Linux下一些常用命令(个人记录)

    mount -o loop XXXX  XXX ./XXX &   后台运行 rm -rf XXX  删除文件夹 rm -rf *  删除当前目录下的所有文件 包括文件夹 ps -ef | g ...

  8. [Angular] Updating and resetting FormGroups and FormControls

    If you want to reset or just update field value, you can do: reset: reset({key: value, k2:v2}); upda ...

  9. 基于 Android NDK 的学习之旅-----环境搭建

    工欲善其事 必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建. 1.Android 开发环境搭建 Android开发环境搭建不是重点,相信看此文章的 ...

  10. MCMC:Gibbs 采样(matlab 实现)

    MCMC: The Gibbs Sampler 多元高斯分布的边缘概率和条件概率 Marginal and conditional distributions of multivariate norm ...