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包中的流支持很多种格式,比如:基本类型. ...
随机推荐
- 仿招商银行载入loading效果
在招商银行android手机app中.有例如以下图所看到的的loading载入效果: 实现这个效果还是比較简单,就是自己定义dialog,设置自己想要的布局.然后设置旋转动画. 主要步骤: 1,写布局 ...
- Hadoop笔记(一)
1.大数据的概述 大数据:巨量数据.海量数据,首先在数据的量上达到一定的规模,首先是人或者计算机在不合理时间内是不能够实现的数据量. 2.特点:数据量比较大,数据类型多样化.处理速度问题 3.大数据平 ...
- Docker基础(一)
1.安装:安装教程很多,Ubuntu14.04安装比较简单docker[之前使用Ubuntu13.04结果安装了好久也没有安装好,后来就直接是14,04了] 2.docker是容器,那么什么是容器? ...
- C语言主要做哪些方面的开发---一个来自“IT技术学习”微信群的问题及答复
近期,在"IT技术学习"微信群中,有同学问了这样一个问题:C语言主要做哪些方面的开发?在这篇文章中,我想结合自身的经验,对这个问题进行下解答. C语言是计算机及其相关专业(如通信. ...
- 【solr专题之一】Solr快速入门 分类: H4_SOLR/LUCENCE 2014-07-02 14:59 2403人阅读 评论(0) 收藏
一.Solr学习相关资料 1.官方材料 (1)快速入门:http://lucene.apache.org/solr/4_9_0/tutorial.html,以自带的example项目快速介绍发Solr ...
- 【a702】贷款利率
Time Limit: 10 second Memory Limit: 2 MB 问题描述 当一个人从银行贷款后,在一段时间内他将不得不每月尝还固定的分期付款.这个问题要求计算机出贷款者向银行支付的利 ...
- mysqlsla安装
#下载mysqlsla https://github.com/daniel-nichter/hackmysql.com yum install perl-ExtUtils-CBuilder per ...
- oracle 内存结构具体解释
Oracle 内存结构 与 Oracle 实例关联的基本内存结构包含: 系统全局区 (SGA):由全部server和后台进程共享.SGA 中存储的数据演示样例包含快速缓存的数据块和共享 SQL 区域. ...
- 【转】Boost.Python
http://edyfox.codecarver.org/html/boost_python.html Boost.Python 是 Boost 中的一个组件,使用它能够大大简化用 C++ 为 Pyt ...
- iOS中打电话、打开网址、发邮件、发短信等
常用小功能 小功能简介 iOS中的很多小功能都是非常简单的,几行代码就搞定了,比如打电话.打开网址.发邮件.发短信等 打电话-方法1 最简单最直接的方式:直接跳到拨号界面 NSURL *url = [ ...