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

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1562050.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

C语言—双链表

一、双向链表的结构 注意&#xff1a;这⾥的“带头”跟前⾯我们说的“头节点”是两个概念&#xff0c;实际前⾯在单链表阶段称呼不严谨&#xff0c;带头链表⾥的头节点&#xff0c;实际为“哨兵位”&#xff0c;哨兵位节点不存储任何有效元素&#xff0c;只是站在这⾥“放哨的”…

【C++】C++的引用

一.引用 1.引用的概念和定义 引用不是新定义⼀个变量&#xff0c;而是给已存在变量取了⼀个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同⼀块内存空间。 类型& 引用别名 引用对象; 2.引用的特征 a.引用在定义时必须初始化 …

Visual Studio--VS安装配置使用教程

Visual Studio Visual Studio 是一款功能强大的开发人员工具&#xff0c;可用于在一个位置完成整个开发周期。 它是一种全面的集成开发环境 (IDE)。对新手特别友好&#xff0c;使用方便&#xff0c;不需要复杂的去配置环境。用它学习很方便。 Studio安装教程 Visual Studio官…

详解前端开发都需要掌握的十个 JavaScript 基本数组函数

假设你正在开发一个复杂的 Web 项目。你的数据来自许多 API&#xff0c;你的工作是高效地处理、过滤和分析这些数据。你的时间很紧张&#xff0c;所以每一行代码都很重要。 这时学习高级 JavaScript 数组方法就会对你有所帮助。 这些函数不仅可以减少代码量&#xff0c;还可以…

阻塞socket 和非阻塞socket的区别(浅显易懂版)

什么是阻塞socket&#xff0c;什么是非阻塞socket。 对于这个问题&#xff0c;我们要先弄清什么是阻塞/非阻塞。 阻塞与非阻塞是对一个文件描述符指定的文件或设备的两种工作方式。 阻塞的意思是指&#xff0c;当试图对该文件描述符进行读写时&#xff0c;如果当时没有东西可…

基于Feign的远程调用

目录 前言 RestTemplate方式调用存在的问题 存在的问题 Feign Feign介绍 Feign的使用步骤 引入依赖 添加注解 编写Feign客户端 使用客户端&#xff08;修改orderService&#xff09; 原代码 修改后 总结 前言 RestTemplate方式调用存在的问题 以前利用RestTempla…

【Unity 100个实用小技巧】 UI分辨率适配

UI分辨率适配 学习实际项目中&#xff0c;分辨率适配的方案&#xff0c;基础版本。 以下适配以720*1680为基准适配 具体操作 Canvas Scaler的Screen Match Model 设置为Match Width Or Height&#xff0c;Match设置为0 这个设置&#xff0c;是以宽为基准进行分辨率适配 其实在…

uniapp__微信小程序使用秋云ucharts折线图双轴

1、子组件 <template><view class"charts-box"><qiun-data-charts type"line":opts"computedOpts":chartData"chartData"/></view> </template><script> export default {props: {chartData: {t…

【优选算法】(第三十五篇)

目录 验证栈序列&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 N叉树的层序遍历&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 验证栈序列&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;L…

只需5步,就可以使用大语言模型(LLM)打造高效的应用

01 概述 随着人工智能技术的飞速发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;正逐渐成为各个领域的得力助手。从最初的文本理解、生成到翻译&#xff0c;这些模型在自然语言处理&#xff08;NLP&#xff09;中的出色表现&#xff0c;让它们在聊天机器人、虚拟助…

98. UE5 GAS RPG 实现技能眩晕效果

我们在技能伤害基类上面设置了对应的负面效果应用的配置项&#xff0c;用来实现技能的负面效果应用。 在之前实现火球术的负面效果时&#xff0c;我们我们在创建火球时&#xff0c;通过伤害基类上的创建技能配置用于后续应用。 在火球攻击到敌人时&#xff0c;通过函数库书写…

68 Netty

68 Netty 参考资料 【硬核】肝了一月的Netty知识点 概念 Netty 是一个高性能、异步事件驱动的网络应用框架&#xff0c;简化了 Java 网络编程&#xff0c;适用于构建高效、可扩展的网络服务器和客户端。 Netty 是基于 Java NIO 的异步事件驱动的网络应用框架&#xff0c;使…

Premiere半色调动漫风格视频叠加特效素材MOGRT

Premiere Pro 半色调叠加素材视频模板&#xff0c;使用这个半色调效果轻松设置视频或图像的样式。可以使用自定义选项&#xff0c;让工作流程更加高效。 特征&#xff1a; 15个半色调叠加效果。 Adobe Premiere Pro 2023 4K分辨率&#xff08;38402160&#xff09;。 包括视频…

回溯法与迭代法详解:如何从手机数字键盘生成字母组合

在这篇文章中&#xff0c;我们将详细介绍如何基于手机数字键盘的映射&#xff0c;给定一个仅包含数字 2-9 的字符串&#xff0c;输出它能够表示的所有字母组合。这是一个经典的回溯算法问题&#xff0c;适合初学者理解和掌握。 问题描述 给定一个数字字符串&#xff0c;比如 …

TikTok流量不好是为什么?是网络没选对吗?

很多人发现他们的TikTok视频观看量不高&#xff0c;点赞和分享率也低&#xff0c;就会开始怀疑是不是网络选择不当导致了这一问题。虽然网络确实是导致流量不佳的一大原因之一&#xff0c;但也不能忽视其他因素&#xff0c;包括内容质量、时机选择、互动参与等方面。本文将揭示…

桌面运维转网络要做什么准备,高级网工学习路线分享_运维转网络工程师好转岗吗

如果你的船不进来&#xff0c;请游过去。 做过桌面运维的朋友都知道&#xff0c;这个岗位相当于做牛做马。我做桌面运维的时候要修监控门禁&#xff0c;消防报警广播音响&#xff0c;还要懂暖通空调下水管道疏通&#xff0c;电梯保养与维护&#xff0c;我听到有些同行还得会修桌…

数据采集崩溃恢复:保障业务稳定运行的关键技术特性

一、场景描述 在当今信息时代&#xff0c;数据已成为企业核心竞争力的重要组成部分。对于许多企业而言&#xff0c;数据的采集、处理和分析至关重要。然而&#xff0c;在数据采集和处理过程中&#xff0c;系统崩溃或故障是无法避免的现象。如何在数据采集过程中确保数据的完整…

计量校准公司对校准工程师,会有什么资质要求?

计量校准是指利用一些计量校准工具&#xff0c;对机器、仪器等进行测量和校准。来实现基本功能的正常使用。计量校准安排&#xff0c;是指根据委托方的要求&#xff0c;按照计量器具校准标准&#xff0c;向社会提供计量器具校准服务的安排。今天&#xff0c;我们就来看看计量校…

腾讯音乐:从 Elasticsearch 到 Apache Doris 内容库升级,统一搜索分析引擎,成本直降 80%

导读&#xff1a; 为满足更严苛数据分析的需求&#xff0c;腾讯音乐借助 Apache Doris 替代了 Elasticsearch 集群&#xff0c;统一了内容库数据平台的内容搜索和分析引擎。并基于 Doris 倒排索引和全文检索的能力&#xff0c;支持了复杂的自定义标签计算&#xff0c;实现秒级查…

24最新新手入门指南:Stable Diffusion!

前言 Stable Diffusion&#xff0c;一款新兴的开源AI绘画软件&#xff0c;正逐渐成为数字艺术家和爱好者的新宠。它的强大功能让用户能够轻松创造出令人印象深刻的数字艺术作品。 无论你是专业艺术家还是艺术新手&#xff0c;Stable Diffusion都为你提供了一个探索创造力的新…