CUDA 7 Stream流简化并发性
异构计算是指高效地使用系统中的所有处理器,包括 CPU 和 GPU 。为此,应用程序必须在多个处理器上并发执行函数。 CUDA 应用程序通过在 streams 中执行异步命令来管理并发性,这些命令是按顺序执行的。不同的流可以并发地执行它们的命令,也可以彼此无序地执行它们的命令。
在不指定流的情况下执行异步 CUDA 命令时,运行时使用默认流。在 CUDA 7 之前,默认流是一个特殊流,它隐式地与设备上的所有其他流同步。
CUDA 7 引入了大量强大的新功能 ,包括一个新的选项,可以为每个主机线程使用独立的默认流,这避免了传统默认流的序列化。本文将展示如何在 CUDA 程序中简化实现内核和数据副本之间的并发。

CUDA 中的异步命令
如 CUDA C 编程指南所述,异步命令在设备完成请求的任务之前将控制权返回给调用主机线程(它们是非阻塞的)。这些命令是:
• 内核启动;
• 存储器在两个地址之间复制到同一设备存储器;
• 从主机到设备的 64kb 或更少内存块的内存拷贝;
• 由后缀为 Async 的函数执行的内存复制;
• 内存设置函数调用。
为内核启动或主机设备内存复制指定流是可选的;可以调用 CUDA 命令而不指定流(或通过将 stream 参数设置为零)。下面两行代码都在默认流上启动内核。
kernel<<< blocks, threads, bytes >>>(); // default stream
kernel<<< blocks, threads, bytes, 0 >>>(); // stream 0
默认流
在并发性对性能不重要的情况下,默认流很有用。在 CUDA 7 之前,每个设备都有一个用于所有主机线程的默认流,这会导致隐式同步。正如 CUDA C 编程指南中的“隐式同步”一节所述,如果主机线程向它们之间的默认流发出任何 CUDA 命令,来自不同流的两个命令就不能并发运行。
CUDA 7 引入了一个新选项, 每线程默认流 ,它有两个效果。首先,它为每个主机线程提供自己的默认流。这意味着不同主机线程向默认流发出的命令可以并发运行。其次,这些默认流是常规流。这意味着默认流中的命令可以与非默认流中的命令同时运行。
要在 nvcc 7 及更高版本中启用每线程默认流,可以在包含 CUDA 头( cuda.h 或 cuda_runtime.h )之前,使用 nvcc 命令行选项 CUDA 或 #define 编译 CUDA_API_PER_THREAD_DEFAULT_STREAM 预处理器宏。需要注意的是:当代码由 nvcc 编译时,不能使用 #define CUDA_API_PER_THREAD_DEFAULT_STREAM 在. cu 文件中启用此行为,因为 nvcc 在翻译单元的顶部隐式包含了 cuda_runtime.h 。
Multistream多流示例
看一个小例子。下面的代码简单地在八个流上启动一个简单内核的八个副本。只为每个网格启动一个线程块,这样就有足够的资源同时运行多个线程块。作为遗留默认流如何导致序列化的示例,在默认流上添加不起作用的虚拟内核启动。这是密码。
const int N = 1 << 20;

global void kernel(float *x, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
for (int i = tid; i < n; i += blockDim.x * gridDim.x) {
x[i] = sqrt(pow(3.14159,i));
}
}

int main()
{
const int num_streams = 8;

cudaStream_t streams[num_streams];
float *data[num_streams];for (int i = 0; i < num_streams; i++) {cudaStreamCreate(&streams[i]);cudaMalloc(&data[i], N * sizeof(float));// launch one worker kernel per streamkernel<<<1, 64, 0, streams[i]>>>(data[i], N);// launch a dummy kernel on the default streamkernel<<<1, 1>>>(0, 0);
}cudaDeviceReset();return 0;

}
首先让检查遗留行为,通过不带选项的编译。
nvcc ./stream_test.cu -o stream_legacy可以在 NVIDIA visualprofiler ( nvvp )中运行该程序,以获得显示所有流和内核启动的时间轴。图 1 显示了 Macbook Pro 上生成的内核时间线,该 Macbook Pro 带有 NVIDIA GeForce GT 750M (一台开普勒 GPU )。可以看到默认流上虚拟内核的非常小的条,以及它们如何导致所有其他流序列化。

一个简单的多流示例在将任何交错内核发送到默认流时不会实现并发现在尝试新的每线程默认流。
nvcc --default-stream per-thread ./stream_test.cu -o stream_per-thread
图 2 显示了来自 nvvp 的结果。在这里可以看到九个流之间的完全并发:默认流(在本例中映射到流 14 )和创建的其他八个流。请注意,虚拟内核运行得如此之快,以至于很难看到在这个图像中默认流上有八个调用。

图 2 :使用新的每线程默认流选项的多流示例,它支持完全并发执行。
MultiThread多线程示例
看另一个例子,该示例旨在演示新的默认流行为如何使多线程应用程序更容易实现执行并发。下面的例子创建了八个 POSIX 线程,每个线程在默认流上调用的内核,然后同步默认流。(需要在本例中进行同步,以确保探查器在程序退出之前获得内核开始和结束时间戳。)
#include <pthread.h>
#include <stdio.h>

const int N = 1 << 20;

global void kernel(float *x, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
for (int i = tid; i < n; i += blockDim.x * gridDim.x) {
x[i] = sqrt(pow(3.14159,i));
}
}

void *launch_kernel(void *dummy)
{
float *data;
cudaMalloc(&data, N * sizeof(float));

kernel<<<1, 64>>>(data, N);cudaStreamSynchronize(0);return NULL;

}

int main()
{
const int num_threads = 8;

pthread_t threads[num_threads];for (int i = 0; i < num_threads; i++) {if (pthread_create(&threads[i], NULL, launch_kernel, 0)) {fprintf(stderr, "Error creating threadn");return 1;}
}for (int i = 0; i < num_threads; i++) {if(pthread_join(threads[i], NULL)) {fprintf(stderr, "Error joining threadn");return 2;}
}cudaDeviceReset();return 0;

}
首先,编译时不使用任何选项来测试遗留的默认流行为。
nvcc ./pthread_test.cu -o pthreads_legacy
在 nvvp 中运行它时,看到一个流,默认流,所有内核启动都序列化,如图 3 所示。

图 3 :一个具有遗留默认流行为的多线程示例:所有八个线程都被序列化。
让用新的 per-thread default stream 选项编译它。
nvcc --default-stream per-thread ./pthread_test.cu -o pthreads_per_thread
图 4 显示,对于每个线程的默认流,每个线程都会自动创建一个新的流,它们不会同步,因此所有八个线程的内核都会并发运行。

图 4 :每个线程默认流的多线程示例:所有八个线程的内核同时运行。
更多提示
在为并发进行编程时,还需要记住以下几点。
• 记住:对于每线程的默认流,每个线程中的默认流的行为与常规流相同,只要同步和并发就可以了。对于传统的默认流,这是不正确的。
• --default-stream 选项是按编译单元应用的,确保将其应用于所有需要它的 nvcc 命令行。
• cudaDeviceSynchronize() 继续同步设备上的所有内容,甚至使用新的每线程默认流选项。如果只想同步单个流,请使用 cudaStreamSynchronize(cudaStream_t stream) ,如的第二个示例所示。
• 从 CUDA 7 开始,还可以使用句柄 cudaStreamPerThread 显式地访问每线程的默认流,也可以使用句柄 cudaStreamLegacy 访问旧的默认流。请注意, cudaStreamLegacy 仍然隐式地与每个线程的默认流同步,如果碰巧在一个程序中混合使用它们。
• 可以通过将 cudaStreamCreate() 标志传递给 cudaStreamCreate() 来创建不与传统默认流同步的 非阻塞流 。
立即下载 CUDA 7rc CUDA toolkitversion7 . 0 的发布候选者今天可以向 NVIDIA 注册的开发人员提供。如果不是注册开发者, 在 NVIDIA 开发区注册免费访问 。了解 这里是 CUDA 7 的特点。
想了解更多关于 Tesla 平台上的加速计算以及使用 CUDA 进行 GPU 计算的信息吗?参加 3 月 17 日至 20 日在圣何塞会议中心举行的 GPU 技术会议 ,这是世界上规模最大、最重要的 GPU 开发者大会。 Parallel Forall 的读者可以使用折扣代码 GM15PFAB 获得任何会议通行证 20% 的折扣!`

CUDA 7 Stream流简化并发性相关推荐

  1. CUDA 7流简化并发

    CUDA 7流简化并发 异构计算是指有效使用系统中的所有处理器,包括CPU和GPU.为此,应用程序必须在多个处理器上同时执行功能.CUDA应用程序通过在流(按顺序执行的命令序列)中,执行异步命令来管理 ...

  2. stream 流的并发

    jdk  8  以后增加stream   接口: stream 流的 各个方法使用如下: package Test01;import java.util.ArrayList; import java. ...

  3. CUDA C/C++ 流和并发

    一.并发 1.同时执行多个CUDA操作的能力(超越多线程并行) CUDA Kernel <<<>>> cudaMemcpyAsync(HostToDevice) c ...

  4. CUDA Stream流并发性

    目录 1.CUDA 中的异步命令 2.默认流 3.Multistream多流示例 异构计算是指高效地使用系统中的所有处理器,包括 CPU 和 GPU .为此,应用程序必须在多个处理器上并发执行函数. ...

  5. CUDA 7 流并发性优化

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

  6. JavaSE基础笔记——不可变集合简介、Stream流体系、异常处理

    1.不可变集合简介 不可变集合,就是不可被修改的集合. 集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变.否则报错. 为什么要创建不可变集合? 如果某个数据不能被修改,把它防御性地拷贝到不 ...

  7. 不可变集合 Stream流 异常

    目录 创建不可变集合 如何创建不可变集合? Stream流 Stream流的概述 Stream流的获取 Stream流的常用API Stream流的综合应用 收集Stream流 异常处理 异常概述.体 ...

  8. java(九)-方法引用, Stream流,File类 , 递归 ,字节流

    day09[方法引用.Lambda表达式.Stream流] 今日目标 线程状态 等待与唤醒 Lambda表达式 Stream流 教学目标 能够说出线程6个状态的名称 能够理解等待唤醒案例 能够掌握La ...

  9. Java SE基础知识详解第[13]期—不可变集合、Stream流、异常

    写在前面: 每一个不曾起舞的日子,都是对生命的辜负. 希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己. 以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力 ...

最新文章

  1. redis.conf配置文件详解
  2. 800万,这位两院院士全捐了!
  3. 虚拟机随服务器启动,VMware Server中虚拟机随宿主机自动启动
  4. 我喜欢阅读和计算机英语,关于自考中的计算机专业
  5. android系统换动画,Android Activity动画跳转修改
  6. Excel 关于新建xls文件 新建sheet 合并sheet的VBA操作代码
  7. c#转换XML文件和json对象
  8. Laravel 成为最佳 PHP 框架的 14 个理由!
  9. android tabspec英文自动大写问题,为什么不能在drawable下访问xml文件?所有的
  10. modbus协议的常用测试工具
  11. solidworks图纸模板添加_如何建立符合国标的SolidWorks工程图模板
  12. nagios——短讯报警
  13. java转大写的方法_Java字母大小写转换的方法
  14. 卓有成效的管理者—第一章 卓有成效是可以学会的
  15. 中国知音导出mysql_央视社会发展纪录片《从〈中国〉到中国 From Chung Kuo to China》全5集 720P/1080i高清纪录片资源百度云盘下载...
  16. Python OpenCv 实现实时人脸识别及面部距离测量
  17. 刘强东为苏宁易购做了嫁衣
  18. c/c++ accumulation
  19. web前端开发经验总结
  20. icloud账户如何注销_如何从您的iCloud帐户中删除设备

热门文章

  1. 2022-2028年中国科技馆行业研究及前瞻分析报告
  2. RPC 笔记(01)— RPC概念、调用流程、RPC 与 Restful API 区别
  3. 2022-2028年中国热塑性聚酯PBT工程塑料行业市场全景调查及发展趋势分析报告
  4. centos 非root用户(普通用户)替换yum安装软件方法
  5. 毕业,新的开始,撸起袖子加油干!
  6. 矩阵乘法的性能提升 AutoKernel
  7. Python---哈夫曼树---Huffman Tree
  8. TensorRT-8量化分析
  9. 部署可扩展的目标检测管道:推理过程(下)
  10. CUDA功能和通用功能