当前位置: 首页 > news >正文

CUDA Graphs学习与实验

CUDA Graphs学习与实验

  • 一.参考链接
  • 二.测试方案
  • 三.测试代码

CUDA图(CUDA Graphs)为CUDA引入了一种全新的工作提交模型。它允许将一系列操作(如内核启动)以图的形式表示,并通过依赖关系将这些操作连接起来。这种图的定义过程与其执行过程是分开的,这意味着我们可以提前定义好一个图,然后多次重复执行它。

这种定义与执行的分离带来了多方面的优化:

  1. 降低CPU启动开销:相比传统的流(streams)方式,由于大量的设置工作已经在图的定义和实例化阶段完成,实际执行时的CPU开销明显减少。
  2. 全局优化机会:通过将整个工作流程以图的形式呈现给CUDA,CUDA有机会对整个流程进行优化。这在逐步提交工作的流机制中是无法实现的,因为流机制只能看到局部的、片段式的工作提交。

流机制中的问题

在传统的流中,当你向流中放置一个内核时,主机驱动程序需要执行一系列操作来准备在GPU上执行该内核。这些操作包括设置内核参数、配置执行环境等。对于执行时间较短的GPU内核,这些准备工作的开销可能占到总执行时间的很大一部分,从而降低了整体效率。

CUDA图的工作提交分为三个阶段

  1. 定义(Definition)

    在这个阶段,程序创建一个包含操作及其依赖关系的图。开发者描述需要执行的操作(如内核函数)以及这些操作之间的先后顺序或并行关系。

  2. 实例化(Instantiation)

    在定义完成后,CUDA对图进行实例化。实例化过程包括:

    • 快照:对图模板进行捕获,生成一个具体的可执行图结构。
    • 验证:检查图的正确性,确保所有的操作和依赖关系都是有效的。
    • 预处理:执行大部分的设置和初始化工作,目的是尽可能减少在实际执行时需要完成的工作量。

    实例化的结果是一个可执行图(executable graph)

  3. 执行(Execution)

    已实例化的可执行图可以像普通的CUDA工作一样被提交到流中执行。重要的是,这个可执行图可以被多次执行,而无需每次都重新实例化。这大大提高了执行的效率,特别是在需要重复执行相同操作的情况下。

CUDA图的优势

  • 性能提升:通过减少CPU的启动开销,特别是在需要频繁启动小型内核的情况下,CUDA图能够显著提升性能。
  • 优化执行:由于CUDA能够提前知道整个工作流程,它可以进行全局优化。例如,它可以重新排列操作以提高并行性,或者优化内存传输以减少延迟。
  • 简化编程模型:开发者可以以更直观的方式描述计算任务,而无需手动管理复杂的依赖关系和同步机制。

举例说明

假设我们有一系列需要按特定顺序执行的内核操作。在传统的流机制中,我们需要:

  • 为每个内核启动,都要进行一次完整的设置和启动过程。
  • 手动管理这些内核之间的依赖关系,确保它们按正确的顺序执行。

使用CUDA图后,我们可以:

  • 一次性地定义所有的内核操作和它们的依赖关系。
  • 实例化后,CUDA会处理好所有的设置和依赖关系。
  • 执行时,只需简单地启动可执行图即可。

结论

CUDA图为GPU计算提供了更高效、更灵活的工作提交方式。通过预先定义和实例化计算图,CUDA能够减少CPU的开销,并利用全局信息对执行进行优化。这对于需要高性能计算的应用,尤其是包含大量小型、短时内核的应用,具有重要意义

一.参考链接

  • graph management functions of the low-level CUDA driver api
  • CUDA Runtime Graph API

二.测试方案

请添加图片描述

三.测试代码

tee cuda_graph.cu<<-'EOF'
#include <iostream>
#include <cuda_runtime.h>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <assert.h>
#include <cstdio>
#include <cuda.h>
#include <iostream>
#include <chrono>
#include <thread>#define CHECK_CUDA(call)                                            \do {                                                            \cudaError_t err = call;                                    \if (err != cudaSuccess) {                                 \std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__; \std::cerr << " code=" << err << " (" << cudaGetErrorString(err) << ")" << std::endl; \exit(EXIT_FAILURE);                                    \}                                                         \} while (0)#define CHECK_CUDA_DRV_API(call)                      \do {                              \CUresult err = call;                  \if (err != CUDA_SUCCESS) {                 \char *error_str=new char[1024];  \cuGetErrorString(err,(const char**)&error_str); \printf("[%s:%d] %s Error :%s!\n",__FILE__,__LINE__,#call,error_str); \}                                      \} while (0)__global__ void Kernel1(float *a,float *b,float *c,float *d)
{unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;a[tid]=1;b[tid]=2;c[tid]=3;d[tid]=0;if(tid==0){printf("Kernel1\n");}
}__global__ void Kernel2(float *a,float *b,float *c,float *d)
{unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;a[tid]+=1;if(tid==0){printf("Kernel2\n");}
}__global__ void Kernel3(float *a,float *b,float *c,float *d)
{unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;b[tid]+=2;if(tid==0){printf("Kernel3\n");}
}__global__ void Kernel4(float *a,float *b,float *c,float *d)
{unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;c[tid]+=3;if(tid==0){printf("Kernel4\n");}
}__global__ void Kernel5(float *a,float *b,float *c,float *d)
{unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;d[tid]=a[tid]+b[tid]+c[tid];if(tid==0){printf("Kernel5\n");}
}struct HostFuncParam
{float *a;float *b;float *c;float *d;int thread_size;
};void CUDART_CB HostFunc(void *data){HostFuncParam *pstParam=(HostFuncParam*)data;for(int i=0;i<pstParam->thread_size;i++){pstParam->d[i]+=1;}printf("HostFunc\n");
}int run(bool graph_mode)
{int deviceid=0;    int block_count=1;int block_size=8;int thread_size=block_count*block_size;int total_count=thread_size*sizeof(float);cudaStream_t stream[3];cudaEvent_t event[3];CHECK_CUDA(cudaSetDevice(deviceid)); for(int i=0;i<3;i++){CHECK_CUDA(cudaStreamCreate(&stream[i]));CHECK_CUDA(cudaEventCreate(&event[i]));}float *a,*b,*c,*d;CHECK_CUDA(cudaMallocManaged(&a, total_count));CHECK_CUDA(cudaMallocManaged(&b, total_count));CHECK_CUDA(cudaMallocManaged(&c, total_count));CHECK_CUDA(cudaMallocManaged(&d, total_count));cudaGraph_t graph;if(graph_mode){CHECK_CUDA_DRV_API(cuGraphCreate(&graph, 0));CHECK_CUDA(cudaStreamBeginCapture(stream[0],cudaStreamCaptureModeGlobal));}    Kernel1<<<block_count, block_size,0,stream[0]>>>(a,b,c,d);CHECK_CUDA(cudaEventRecord(event[0], stream[0]));CHECK_CUDA(cudaStreamWaitEvent(stream[1], event[0]));CHECK_CUDA(cudaStreamWaitEvent(stream[2], event[0]));Kernel2<<<block_count, block_size,0,stream[0]>>>(a,b,c,d);Kernel3<<<block_count, block_size,0,stream[1]>>>(a,b,c,d);CHECK_CUDA(cudaEventRecord(event[1], stream[1]));Kernel4<<<block_count, block_size,0,stream[2]>>>(a,b,c,d);CHECK_CUDA(cudaEventRecord(event[2], stream[2]));CHECK_CUDA(cudaStreamWaitEvent(stream[0], event[1]));CHECK_CUDA(cudaStreamWaitEvent(stream[0], event[2]));Kernel5<<<block_count, block_size,0,stream[0]>>>(a,b,c,d);HostFuncParam stParam;stParam.d=d;stParam.thread_size=thread_size;CHECK_CUDA(cudaLaunchHostFunc(stream[0], HostFunc, (void*)&stParam));if(graph_mode){CHECK_CUDA(cudaStreamEndCapture(stream[0], &graph));cudaGraphExec_t graphExec;CHECK_CUDA(cudaGraphInstantiate(&graphExec, graph, NULL, NULL, 0));CHECK_CUDA(cudaGraphLaunch(graphExec, 0));CHECK_CUDA(cudaDeviceSynchronize());CHECK_CUDA_DRV_API(cuGraphDebugDotPrint(graph,"graph.dot",0));CHECK_CUDA(cudaGraphExecDestroy(graphExec));CHECK_CUDA(cudaGraphDestroy(graph));}else{CHECK_CUDA(cudaStreamSynchronize(stream[0]));}for(int i=0;i<thread_size;i++){printf("%6.2f\n",d[i]);}CHECK_CUDA(cudaFree(a));CHECK_CUDA(cudaFree(b));CHECK_CUDA(cudaFree(c));CHECK_CUDA(cudaFree(d));return 0;
}int main(int argc,char *argv[])
{int mode=atoi(argv[1]);if(mode==0){printf("normal mode\n");run(0);}else{printf("graph mode\n");run(1);}
}
EOF
/usr/local/cuda/bin/nvcc -std=c++17 -arch=sm_86 -lineinfo \-o cuda_graph cuda_graph.cu \-I /usr/local/cuda/include -L /usr/local/cuda/lib64 -lcuda
./cuda_graph 0
./cuda_graph 1
dot -Tpng graph.dot -o graph.png
  • 输出
normal mode
Kernel1
Kernel2
Kernel3
Kernel4
Kernel5
HostFunc13.0013.0013.0013.0013.0013.0013.0013.00
graph mode
Kernel1
Kernel2
Kernel3
Kernel4
Kernel5
HostFunc13.0013.0013.0013.0013.0013.0013.0013.00

请添加图片描述

相关文章:

CUDA Graphs学习与实验

CUDA Graphs学习与实验 一.参考链接二.测试方案三.测试代码 CUDA图&#xff08;CUDA Graphs&#xff09;为CUDA引入了一种全新的工作提交模型。它允许将一系列操作&#xff08;如内核启动&#xff09;以图的形式表示&#xff0c;并通过依赖关系将这些操作连接起来。这种图的定义…...

【自注意力与Transformer架构在自然语言处理中的演变与应用】

背景介绍 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;序列到序列&#xff08;seq2seq&#xff09;模型和Transformer架构的出现&#xff0c;极大地推动了机器翻译、文本生成和其他语言任务的进展。传统的seq2seq模型通常依赖于循环神经网络&#xff08;RNN&…...

LabVIEW交直流接触器动态检测系统

LabVIEW软件与霍尔传感器技术结合的交直流接触器动态检测系统通过实时数据采集和处理技术&#xff0c;有效地测量并分析交直流接触器在吸合及吸持阶段的电流和电压变化&#xff0c;以及相应的功率消耗&#xff0c;从而优化电力和配电系统的性能和可靠性。 项目背景 交直流接触…...

Unity3D中基于四叉树的范围检测算法详解

在游戏开发中&#xff0c;碰撞检测和范围检测是常见的需求&#xff0c;尤其是在处理大量物体时&#xff0c;传统的暴力检测法&#xff08;即每个物体与其他所有物体进行碰撞检测&#xff09;会消耗大量的计算资源&#xff0c;导致性能下降。为了优化这一过程&#xff0c;四叉树…...

k8s网络通信

k8s通信整体架构 k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel&#xff0c;calico等 CNI插件存放位置&#xff1a;# cat /etc/cni/net.d/10-flannel.conflist 插件使用的解决方案如下 虚拟网桥&#xff0c;虚拟网卡&#xff0c;多个容器共用一个虚…...

07 欢乐的跳

题目&#xff1a; 代码&#xff1a; #include<bits/stdc.h> using namespace std; #define M 1000005int main() {int n;cin>>n;int a[M]{0};for(int i0;i<n;i){cin>>a[i];}int c[M]{0};for(int i1;i<n;i){c[i]abs(a[i]a[i1]);}sort(c1,cn); // 注意f…...

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【262-271】

文章目录 262. 回顾上一章内容263. IDEA介绍263.1 IDEA 介绍263.2 Eclipse 介绍 264. IDEA下载265. IDEA使用1257. IDEA使用2268. IDEA使用3268. 269. 270. IDEA快捷键1,2,3271. IDEA模板 262. 回顾上一章内容 看视频 263. IDEA介绍 263.1 IDEA 介绍 IDEA 全称 IntelliJ ID…...

GNU链接器(LD):输入分区的垃圾回收及保护处理(KEEP命令)介绍

0 参考资料 GNU-LD-v2.30-中文手册.pdf GNU linker.pdf1 前言 一个完整的编译工具链应该包含以下4个部分&#xff1a; &#xff08;1&#xff09;编译器 &#xff08;2&#xff09;汇编器 &#xff08;3&#xff09;链接器 &#xff08;4&#xff09;lib库 在GNU工具链中&…...

论文翻译 | Fairness-guided Few-shot Prompting for LargeLanguage Models

摘要 大型语言模型已经显示出令人惊讶的执行上下文学习的能力&#xff0c;也就是说&#xff0c;这些模型可以通过对由几个输入输出示例构建的提示进行条件反射&#xff0c;直接应用于解决大量下游任务。然而&#xff0c;先前的研究表明&#xff0c;由于训练示例、示例顺序和提示…...

【分布式微服务云原生】战胜Redis脑裂:深入解析与解决方案

战胜Redis脑裂&#xff1a;深入解析与解决方案 摘要&#xff1a; Redis脑裂问题&#xff08;Split Brain Syndrome&#xff09;是分布式系统中的一个常见且复杂的问题&#xff0c;通常发生在网络分区或主节点出现问题时。本文将详细探讨脑裂的主要原因、导致的问题以及有效的解…...

数据治理与可持续发展:开启企业价值新模式——The Open Group 2024生态系统架构·可持续发展年度大会邀您共襄盛举

在当今数字化转型的浪潮中&#xff0c;企业正面临着前所未有的机遇和挑战。当数据治理遇上可持续发展&#xff0c;企业价值的新模式应运而生。那么&#xff0c;如何在数字化时代实现数据治理与可持续发展的融合&#xff0c;推动企业价值的飞跃&#xff1f; The Open Group 202…...

数据库的分类及主流数据库

一、数据库的分类 &#xff08;一&#xff09;关系型数据库&#xff08;RDBMS&#xff09; 定义与原理 关系型数据库是基于关系模型建立的数据库。它以表格&#xff08;关系&#xff09;的形式组织数据&#xff0c;每个表格包含行&#xff08;记录&#xff09;和列&#xff0…...

Qt C++设计模式->备忘录模式

备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;用于在不破坏封装性的前提下&#xff0c;捕获并保存对象的内部状态&#xff0c;以便在将来的某个时刻可以恢复到之前的状态。备忘录模式的核心是状态的保存和恢复&#xff0c;常用于实现撤销…...

Vue使用@别名替换后端ip地址

1. 安装 types/node types/node 包允许您在TypeScript项目中使用Node.js的核心模块和API&#xff0c;并提供了对它们的类型检查和智能提示的支持。 npm install types/node --save-dev 比如安装之后&#xff0c;就可以导入nodejs的 path模块&#xff0c;在下面代码 import path…...

强大的PDF到Word转换工具

Solid Converter&#xff1a;强大的PDF到Word转换工具推荐 在日常工作和学习中&#xff0c;PDF是最常用的文件格式之一。然而&#xff0c;编辑PDF文档并不总是那么方便&#xff0c;尤其是当你需要将PDF文件转换为Word文档时。Solid Converter 是一款强大的工具&#xff0c;专为…...

js进阶——深入解析JavaScript中的URLSearchParams

深入解析 JavaScript 中的 URLSearchParams 在现代Web开发中&#xff0c;我们经常需要处理URL中的查询参数&#xff0c;尤其是在构建动态Web应用时。这些查询参数&#xff08;query parameters&#xff09;通常以 ?keyvalue&key2value2 的形式存在。JavaScript 提供了一个…...

如何利用wsl-Ubuntu里conda用来给Windows的PyCharm开发

前提&#xff1a;咱们在wsl-Ubuntu上&#xff0c;有conda的虚拟环境 咱们直接打开PyCharm,打开Settings 更换Python Interpreter即可 当然一开始可能没有下面的选项&#xff0c;需要我们点击右边的Add Interpreter 这里选择wsl 点击next 将这两步进行修改 可以看出来&#xff0…...

操作系统的了解及安装

一、linux系统认识 linux是指操作系统的内核&#xff0c;ubuntu是指基于这种内核的操作系统&#xff0c;Ubuntu属于Linux的一个发行版本&#xff0c;有简易的用户界面&#xff0c;完善的包管理系统&#xff0c;Ubuntu还对大多数硬件有着良好的兼容性&#xff0c;包含最新的图形…...

【C++篇】虚境探微:多态的流动诗篇,解锁动态的艺术密码

文章目录 C 多态详解&#xff08;进阶篇&#xff09;前言第一章&#xff1a;多态的原理1.1 虚函数表的概念1.1.1 虚函数表的生成过程 1.2 虚表的存储位置 第二章&#xff1a;动态绑定与静态绑定2.1 静态绑定2.1.1 静态绑定的实现机制&#xff1a;2.1.2 示例代码&#xff1a; 2.…...

uniapp的相关知识(1)

1、hover-class&#xff1a;当有鼠标按下时&#xff0c;会切换对应的样式&#xff1b;也可以设置对应的变色时间。 2、selectable&#xff1a;设置text组件的文本是否可以进行复制。 3、with&#xff1a;当设置为80%时&#xff0c;表示宽占整个屏幕的80%。 4、border&#x…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...