我与计算机视觉-[CUDA]-[CPU多线程下CUDA的多流]

2023-10-28

首先问题出在cpu下的多线程,当你想要在多个线程下调用同一个cuda核函数的时候,你会发现效率很低,那么经过验证,的确,不管你有多少个线程,cuda总是将线程中的核函数放入默认流中进行队列方式的处理,相当于单线程,但是这个问题在cuda7后已经得到了解决,下面对这个问题进行一些测试。

这里使用了以下链接中的内容:

https://www.cnblogs.com/wujianming-110117/p/14091897.html

https://developer.nvidia.com/blog/gpu-pro-tip-cuda-7-streams-simplify-concurrency/

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

指定流是可选的;可以调用 CUDA 命令而不指定流(或通过将 stream 参数设置为零)。下面两行代码都在默认流上启动内核。

  kernel<<< blocks, threads, bytes >>>();    // default stream
  kernel<<< blocks, threads, bytes, 0 >>>(); // stream 0

在并发性对性能不重要的情况下,默认流很有用。在 CUDA 7 之前,每个设备都有一个用于所有主机线程的默认流,这会导致隐式同步。正如 CUDA C 编程指南中的“隐式同步”一节所述,如果主机线程向它们之间的默认流发出任何 CUDA 命令,来自不同流的两个命令就不能并发运行。

CUDA 7 引入了一个新选项, 每线程默认流 ,它有两个效果。首先,它为每个主机线程提供自己的默认流。这意味着不同主机线程向默认流发出的命令可以并发运行。其次,这些默认流是常规流。这意味着默认流中的命令可以与非默认流中的命令同时运行。

要在 nvcc7 及更高版本中启用每线程默认流,可以在包含 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 。

具体方法是,右键项目属性中的CUDA C/C++(前提是你创建的是CUDA程序,不然没有这个选项)选项中的Command Line中添加--default-stream per-thread就可以。

 

下面介绍测试方法:

1.以管理员身份打开Nsight Monitor
2.点击visual studio菜单中的Nsight,选择Start Perfoemance Analysis


3.勾选system和cuda选项


4.点击lanuch运行
5.待运行完毕后,系统自动输出运行结果,点击timeline查看stream的使用情况

 第一个例子是使用for循环测试多流,代码如下: 

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <iostream>
#include <thread>
#include <stdio.h>

#include <thread>
#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));
	}
}

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 stream
		kernel << <1, 64, 0, streams[i] >> > (data[i], N);
		// launch a dummy kernel on the default stream
		kernel << <1, 1 >> > (0, 0);
	}
	cudaDeviceReset();
	return 0;
}

 在不使用--default-stream per-thread编译命令时运行结果如下图:

可以看到核函数并没有并发运行。 

 添加后:

第二个例子使用多线程,代码如下:

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(cudaStream_t stream)
{
	float *data;
	cudaMalloc(&data, N * sizeof(float));
	kernel << <1, 64,0, stream >> > (data, N);
	//cudaStreamSynchronize(0);
	return;
}

int main()
{
	const int num_threads = 8;
	std::thread threads[num_threads];
	cudaStream_t streams[num_threads];
	for (int i = 0; i < num_threads; i++) {
		cudaStreamCreate(&streams[i]);
		threads[i] = std::thread(launch_kernel, streams[i]);
	}

	for (int i = 0; i < num_threads; i++) {
		threads[i].join();
	}

	cudaDeviceReset();

	return 0;
}

 同样在不使用编译命令时运行结果如下图:

使用后如下图:

 

 提示:
在为并发进行编程时,还需要记住以下几点。
1.对于每线程的默认流,每个线程中的默认流的行为与常规流相同,只要同步和并发就可以了。对于传统的默认流,这是不正确的。
2.--default-stream 选项是按编译单元应用的,确保将其应用于所有需要它的 nvcc 命令行。
3.cudaDeviceSynchronize() 继续同步设备上的所有内容,甚至使用新的每线程默认流选项。如果只想同步单个流,请使用 cudaStreamSynchronize(cudaStream_t stream) ,如的第二个示例所示。
4.从 CUDA 7 开始,还可以使用句柄 cudaStreamPerThread 显式地访问每线程的默认流,也可以使用句柄 cudaStreamLegacy 访问旧的默认流。请注意, cudaStreamLegacy 仍然隐式地与每个线程的默认流同步,如果碰巧在一个程序中混合使用它们。
5.可以通过将 cudaStreamCreate() 标志传递给 cudaStreamCreate() 来创建不与传统默认流同步的 非阻塞流 。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我与计算机视觉-[CUDA]-[CPU多线程下CUDA的多流] 的相关文章

  • Windows 上使用 g++ 的 Makefile,链接库

    我已经厌倦了 MSVC 6 以及每个人总是告诉我它是一个蹩脚的编译器等等 所以现在我决定尝试使用 vim 加 g 和 makefile 这是我的问题 我有以下 makefile This is supposed to be a commen
  • C 中的变量定义是什么意思[重复]

    这个问题在这里已经有答案了 你们能告诉我 这在 C 中意味着什么吗 define Privileged Data Privileged Data static int dVariable 编译器对变量进行寻址有特殊意义吗 这只是一个宏Pri
  • MVC 重定向到没有控制器的视图

    希望应该是一个简单的 我创建了一个通用错误视图 当整个站点的操作方法内发生异常时 我想显示该视图 我创建了一个部分页面 所有导航都位于其中 因此我不需要在此视图上使用控制器 那么如何从控制器内的操作方法重定向到它 像这样的东西 HttpPo
  • 必须打开存储才能执行此操作 - System.IO.Packaging.Package

    我正在使用 System IO Packaing Package 类来压缩文件 我的应用程序的多个实例可以同时运行 并读取和保存文件 当处理小文件时 一切似乎都很好 但是当涉及大文件时 如果应用程序的两个实例同时保存 我会收到一个异常 消息
  • 切换图片框可见性 C#

    为什么图片框控件的可见性属性在这里不起作用 我最初将它们设置为 false 以便在屏幕加载时它们不可见 但后来我想切换这个 我已完成以下操作 但似乎不起作用 这是一个 Windows 窗体应用程序 private void Action w
  • 如何将pdf页面设置设置为打印属性对话框?

    大家好 我想知道如何设置 pdf 页面设置到打印属性对话框 例如 如果我的 PDF 页面设置为横向 则布局会自动显示横向而不是纵向 如果我的 PDF 页面设置为纵向 则布局会自动显示纵向 我在这个主题上做了很多研发 但没有找到任何满意的链接
  • 在运行时设置 DataGridView 上的 DataFormatString?

    是否可以在运行时设置 ASP NET DataGridView 中的列或单元格的 DataFormatString 属性 这应该有效 BoundField priceField grid Columns 0 as BoundField pr
  • 关闭 XDOCUMENT 的实例

    我收到这个错误 该进程无法访问文件 C test Person xml 因为它是 被另一个进程使用 IOException 未处理 保存文件内容后如何关闭 xml 文件的实例 using System using System Collec
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • F10键没被抓住

    I have a Windows Form and there overriden ProcessCmdKey However this works with all of the F Keys except for F10 I am tr
  • 在通过网络发送之前压缩位图

    我正在尝试通过网络发送位图屏幕截图 因此我需要在发送之前对其进行压缩 有一个库或方法可以做到这一点吗 当您将图像保存到流时 您have选择一种格式 几乎所有位图格式 bmp gif jpg png 都使用一种或多种压缩形式 因此 只需选择适
  • 特定设备的不同字体大小

    我目前正在开发通用应用程序 我需要分别处理移动设备和桌面的文本框字体大小 我找到了一些方法 但都不能解决问题 使用 VisualStateManager 和 StateTrigger 为例
  • 为什么重载方法在 ref 仅符合 CLS 方面有所不同

    公共语言规范对方法重载非常严格 仅允许根据其参数的数量和类型来重载方法 如果是泛型方法 则根据其泛型参数的数量进行重载 根据 csc 为什么此代码符合 CLS 无 CS3006 警告 using System assembly CLSCom
  • c# 如何生成锦标赛括号 HTML 表

    所以我已经被这个问题困扰了三个星期 但我一生都无法弄清楚 我想做的是使用表格获得这种输出 演示 http www esl world net masters season6 hanover sc2 playoffs rankings htt
  • 如何不在类中实现接口的功能?

    面试时面试官问了我以下问题 但我不知道这个问题的答案是什么 请帮忙 如果我不想 我必须做什么 在我的类中实现一个函数 在接口中声明为 由我班实施 Edited 我正在使用 NET 和 C 如果有人可以提供 C 示例代码示例 那就太好了 Th
  • 当在 Repository/UnitOrWork 之上使用 Service 类时,我应该在哪里放置逻辑不适合 Repository 的常用数据访问代码?

    In my 先前的问题 https stackoverflow com questions 24906548 using the generic repository unit of work pattern in large projec
  • Dynamics Crm:获取状态代码/状态代码映射的元数据

    在 Dynamics CRM 2011 中 在事件实体上 状态原因 选项集 也称为状态代码 与 状态 选项集 也称为状态代码 相关 例如看这个截图 当我使用 API 检索状态原因选项集时 如下所示 RetrieveAttributeRequ
  • 你能解释一下这个C++删除问题吗?

    我有以下代码 std string F WideString ws GetMyWideString std string ret StringUtils ConvertWideStringToUTF8 ws ret return ret W
  • 为什么 C# 接口名称前面加上“I”

    这种命名约定背后的基本原理是什么 我没有看到任何好处 额外的前缀只会污染 API 我的想法与康拉德一致response https stackoverflow com a 222502 9898与此相关的question https sta
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use

随机推荐

  • FIO使用说明(最详细最全的参数说明)

    这个文档是对fio 2 0 9 HOWTO文档的翻译 fio的参数太多了 翻译这个文档时并没有测试每一个参数的功能和使用方法 只有少量参数做了试验 大部分的参数采用的是根据字面翻译或是个人理解的翻译 必然有些出入 先发出来 以后有使用的时候
  • 迁移学习花式Finetune方法大汇总

    如果觉得我的算法分享对你有帮助 欢迎关注我的微信公众号 圆圆的算法笔记 更多算法笔记和世间万物的学习记录 迁移学习广泛地应用于NLP CV等各种领域 通过在源域数据上学习知识 再迁移到下游其他目标任务上 提升目标任务上的效果 其中 Pret
  • JS之arguments、arguments.callee、caller介绍

    arguments 调用函数时产生的 保存实参 arguments callee 被调用时指向函数自身 caller 指向调用某函数的那个函数 下面通过一段代码说明它们的用处 function A n console log argumen
  • 线程同步之Volatile

    编译器优化 c 编译器会在不改变我们的意图的情况下做一些优化 比如 a 1 a 2 编译器编译之后 可能就只剩下第二行了 再比如 a 1 b a 编译器优化后 可能会把第二行优化成b 1 再比如 a m b n 编译器生成IL时 有可能会改
  • APP安全(一)-防二次打包(C、C++签名校验)

    前言 由于Android系统的开放性 开发出来的APP很容易被逆向 修改代码逻 加入广告 病毒等二次打包后发布 对开发者和用户造成一定的损失 因此我们的APP运行过程中需要进行签名校验 以及使用加解密算法对数据进行处理 从而保证访问服务端的
  • 开源自动化测试框架httprunner4.x的学习-2

    使用教程 接口自动化 1 如何安装 以我正在使用的v4 3 0为例 pip install httprunner 4 3 0 安装完成后检查一下 hrp v 看到如下版本信息就说明安装成功 2 创建脚手架 执行命令hrp startproj
  • windows密码获取凭证

    目录 一 Windows HASH hash windows HASH简介 二 Windows认证基础 Windows本地认证 LM HASH LM HASH简介 LM HASH生成原理 Mysql数据库密码破解 1 MYSQL数据库文件类
  • mysql程序连接驱动_Mysql驱动及其连接

    import java sql public class DB public static Connection getConn Connection conn null try Class forName com mysql jdbc D
  • 求旋转后的坐标

    坐标点target 中心点center 角度angle 旋转后坐标 function getRotatePoint targetX targetY centerX centerY angle const rotation angle Mat
  • settings.xml详解(很详细读这一篇就够了)

    目录 一 settings xml在哪里配置 有什么用 二 settings xml元素详解 2 1 LocalRepository 2 2 InteractiveMode 2 3 UsePluginRegistry 2 4 Offline
  • RT-Thread ——RTC配置

    RT Thread RTC配置 STM32F103系列芯片的RTC功能存在一些缺陷 一 显示时间戳 RTC Real Time Clock 译为实时时钟 因为它一般是集成电路 故也称为时钟芯片 它能提供精确的实时时间 可以用于产生年 月 日
  • MySQL 中视图和表的区别以及联系是什么?

    两者的区别 1 视图是已经编译好的 SQL 语句 是基于 SQL 语句的结果集的可视化的表 而表不是 2 视图没有实际的物理记录 而基本表有 3 表是内容 视图是窗口 4 表占用物理空间而视图不占用物理空间 视图只是逻辑概念的存在 表可以及
  • Codeforces Round #697 (Div. 3) C. Ball in Berland

    我的第一篇博客 XD 第一次写 小激动 一 解题思路 我一个菜鸡 看到这题 刚开始也就能想到n2算法 但肯定是过不了的 所以我又绞尽脑汁 想了一波 终于在 这题必有巧 的信念指导下 想出来了 目标是找到2个组合 让他们不冲突 那么可以显然知
  • C++学习(五十六)qt如何同时做debug和release

    CONFIG debug and release
  • Java开发 Eclipse使用技巧(转)

    1 如何设置默认的代码目录为src 默认的输出目录为bin window gt Preferences gt java gt Build Path中 右侧选择Folders就可以2 如何为快速局部变量设置getX setX属性 在代码里 g
  • node cron 动态任务调度,不同timeZone配置

    系列文章目录 前言 一 安装cron和timezone 二 创建相关db 1 定时任务开关表 2 定时任务表和运行记录表 三 相关代码实现 四 时区数据下载 五 time cron 前言 使用cron 插件实现动态任务调度 配置不同时区的定
  • C语言:猜数字游戏

    define CRT SECURE NO WARNINGS include
  • 又是一年中秋至|Python Pygame制作中秋兔子接月饼游戏【源码+解析】

    一年中秋又快到了 今年加入了Python的学习行列 得益于Python的开发效率和易读性 网上写文章的次数多了起来 既然是中秋节那肯定要搞个应景的游戏才行 左思右想没有头绪时 刚好看到一篇介绍Pygame制作飞机大战的文章 文章写的不错 文
  • MySQL常用的存储引擎

    MySQL常用的存储引擎为MyISAM InnoDB MEMORY MERGE 其中InnoDB提供事务安全表 其他存储引擎都是非事务安全表 MyISAM是MySQL的默认存储引擎 MyISAM不支持事务 也不支持外键 但其访问速度快 对事
  • 我与计算机视觉-[CUDA]-[CPU多线程下CUDA的多流]

    首先问题出在cpu下的多线程 当你想要在多个线程下调用同一个cuda核函数的时候 你会发现效率很低 那么经过验证 的确 不管你有多少个线程 cuda总是将线程中的核函数放入默认流中进行队列方式的处理 相当于单线程 但是这个问题在cuda7后