CUDA流(Stream)
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)的更多相关文章
- CUDA 7 Stream流简化并发性
CUDA 7 Stream流简化并发性 异构计算是指高效地使用系统中的所有处理器,包括 CPU 和 GPU .为此,应用程序必须在多个处理器上并发执行函数. CUDA 应用程序通过在 streams ...
- cuda流测试=basic_single_stream
cuda流测试 /* * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. * * NVIDIA Corporation and ...
- JAVA基础知识之IO——IO流(Stream)的概念
Java IO 流 Java将不同的设备或载体(键盘.文件.网络.管道等)的输入输出数据统称为"流"(Stream),即JAVA的IO都是基于流的. JAVA传统的所有流类型类都包 ...
- [Linux] 流 ( Stream )、管道 ( Pipeline ) 、Filter - 笔记
流 ( Stream ) 1. 流,是指可使用的数据元素一个序列. 2. 流,可以想象为是传送带上等待加工处理的物品,也可以想象为工厂流水线上的物品. 3. 流,可以是无限的数据. 4. 有一种功能, ...
- 【stanford C++】字符串(String)与流(Stream)
字符串(String)与流(Stream) 一.C++中字符串(String) 字符串(String):就是(可能是空的)字符序列. C++中的字符串在概念上和Java中的字符串类似. C++字符串用 ...
- nodeJS之流stream
前面的话 当内存中无法一次装下需要处理的数据时,或者一边读取一边处理更加高效时,我们就需要用到数据流.NodeJS中通过各种Stream来提供对数据流的操作.本文将详细说明NodeJS中的流strea ...
- c#中字节数组byte[]、图片image、流stream,字符串string、内存流MemoryStream、文件file,之间的转换
字节数组byte[]与图片image之间的转化 字节数组转换成图片 public static Image byte2img(byte[] buffer) { MemoryStream ms = ne ...
- Java笔记:Java 流(Stream)、文件(File)和IO
更新时间:2018-1-7 12:27:21 更多请查看在线文集:http://android.52fhy.com/java/index.html java.io 包几乎包含了所有操作输入.输出需要的 ...
- Java - 17 Java 流(Stream)、文件(File)和IO
Java 流(Stream).文件(File)和IO Java.io包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io包中的流支持很多种格式,比如:基本类型. ...
随机推荐
- js进阶 13-2 jquery动画滑动效果哪些注意事项
js进阶 13-2 jquery动画滑动效果哪些注意事项 一.总结 一句话总结:滑动里面这里up是隐藏,down是显示. 1.jquery动画默认的两个切换效果是什么(swing默认和linear的区 ...
- 4、C++快速入门2
1.抽象类 如果一个类里面有纯虚函数,其被编译器认为是一个抽象类,抽象类不能用来实例化一个对象 纯虚函数定义:virtual void 函数名(void)= 0; 抽象类是给派生类定义好接口函数,如 ...
- zynq+linux+ramdisk can调试
由于采用ramdisk文件系统,自带的ip工具版本太旧无法配置can,需要自行编译ip,具体参见参考文献2 1.vivado配置ps 2.设备树增加can0,一般开发板均已提供此配置 can@e000 ...
- 一、Github博客搭建之jekyll安装
注意:以下步骤是FQ后操作的,需要了解FQ的可以移步 -> 枫叶主机 一.安装jekyll需要Ruby-2.1.0以上版本,本人是mac pro系统版本10.12.5(macOS Sierra) ...
- 【跟我一起学Unity3D】代码中分割图片而且载入帧序列动画
在Cocos2dx中.对大图的处理已经封装好了一套自己的API,可是在Unity3D中貌似没有类似的API(好吧,实际上是有的,并且功能更强大),或者说我没找到. 只是这也在情理之中,毕竟Unity3 ...
- 【2024】求X到Y之间的整数和
Time Limit: 3 second Memory Limit: 2 MB [问题描述] 计算X到Y之间的整数和(要求用函数实现).注意输入时X不一定小于Y,且X.Y不一定都是整数. [输入] 两 ...
- [JS Compose] 2. Enforce a null check with composable code branching using Either
We define the Either type and see how it works. Then try it out to enforce a null check and branch o ...
- Lucene学习总结之二:Lucene的总体架构 2014-06-25 14:12 622人阅读 评论(0) 收藏
Lucene总的来说是: 一个高效的,可扩展的,全文检索库. 全部用Java实现,无须配置. 仅支持纯文本文件的索引(Indexing)和搜索(Search). 不负责由其他格式的文件抽取纯文本文件, ...
- mysql 按日期分组
select DATE_FORMAT(NOW(),'%Y%m%d') days,count(caseid) count from tc_case group by days; //date_forma ...
- SDE 空间表操作
1. 创建空间表(包含st_geometry属性字段) CREATE TABLE sensitive_areas (area_id integer, name varchar(128), area_s ...