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

【CUDA】Nsight profile驱动的CUDA优化

前置准备

  • 安装NVIDIA Nsight Compute。 安装好后选择使用管理员权限启动
  • 下载官方 Demo 代码
  • 官方博客
  • Shuffle warp

1. 任务介绍及CPU版本

1.1 任务介绍

在这里插入图片描述
任务理解:

  • 有一个 L x M 的矩阵 M 1 M_1 M1 对其每行取平均值 得到 V 1 ∈ R L × 1 V_1 \in \mathbb{R}^{L \times 1} V1RL×1 的列向量
  • 有一个 L x L 的矩阵 M 2 M_2 M2 V 1 V_1 V1做矩阵乘法,最后得到 V 2 ∈ R L × 1 V_2 \in \mathbb{R}^{L \times 1} V2RL×1 的列向量

1.2 CPU版本实现

/**input: input 矩阵,维度为(N, L, M) N为Batchoutput: ouput 矩阵,维度为(N, L)matrix: matrix 维度为(L, L)
*/
template <typename T>
void cpu_version1(T *input, T *output, T *matrix, int L, int M, int N){
#pragma omp parallel forfor (int k = 0; k < N; k++){      // repeat the following, N timesstd::vector<T> v1(L);           // vector length of Lfor (int i = 0; i < M; i++)     // compute average vector over M input vectorsfor (int j = 0; j < L; j++)v1[j] += input[k*M*L+j*M+i];for (int j = 0; j < L; j++)v1[j] /= M;for (int i = 0; i < L; i++)     // matrix-vector multiplyfor (int j = 0; j < L; j++)output[i*N+k] += matrix[i*L+j]*v1[j];}
}

1.3 计时逻辑

#include <time.h>
#ifdef __linux__
#define USECPSEC 1000000ULL
#include <sys/time.h>
unsigned long long dtime_usec(unsigned long long start){timeval tv;gettimeofday(&tv, 0);return ((tv.tv_sec*USECPSEC)+tv.tv_usec)-start;
}
#elif defined(WIN32)
#include <windows.h>
double dtime_usec(double start) {LARGE_INTEGER frequency;        // ticks per secondLARGE_INTEGER t1;               // ticksdouble elapsedTime;// get ticks per secondQueryPerformanceFrequency(&frequency);// get current timeQueryPerformanceCounter(&t1);// compute the elapsed time in micro-second resolution(毫秒)elapsedTime = (t1.QuadPart - start) * 1000000.0 / frequency.QuadPart;return elapsedTime;
}
#endif

1.4 main函数

typedef double ft;int main(){ft *d_input, *h_input, *d_output, *h_outputc, *h_outputg, *d_matrix, *h_matrix;int L = my_L; int M = my_M; int N = my_N;// host allocationsh_input   = new ft[N*L*M];h_matrix  = new ft[L*L];h_outputg = new ft[N*L];h_outputc = new ft[N*L];// data initializationfor (int i = 0; i < N*L*M; i++) h_input[i] = (rand()&1)+1;  // 1 or 2for (int i = 0; i < L*L; i++) h_matrix[i]  = (rand()&1)+1;  // 1 or 2// create result to test for correctnessLARGE_INTEGER st;double dt;QueryPerformanceCounter(&st);  // 获取起始时间点cpu_version1(h_input, h_outputc, h_matrix, L, M, N);dt = dtime_usec(st.QuadPart);std::cout << "CPU execution time: \t" << dt / 1000.0f << "ms" << std::endl;// device allocationscudaMalloc(&d_input, N*L*M*sizeof(ft));cudaMalloc(&d_output,  N*L*sizeof(ft));cudaMalloc(&d_matrix,  L*L*sizeof(ft));cudaCheckErrors("cudaMalloc failure");// copy input data from host to devicecudaMemcpy(d_input,  h_input,  N*L*M*sizeof(ft), cudaMemcpyHostToDevice);cudaMemcpy(d_matrix, h_matrix,   L*L*sizeof(ft), cudaMemcpyHostToDevice);cudaMemset(d_output, 0, N*L*sizeof(ft));cudaCheckErrors("cudaMemcpy/Memset failure");// run on device and measure execution timeQueryPerformanceCounter(&st);  // 获取起始时间点gpu_version1<<<1, L>>>(d_input, d_output, d_matrix, L, M, N);cudaCheckErrors("kernel launch failure");cudaDeviceSynchronize();cudaCheckErrors("kernel execution failure");dt = dtime_usec(st.QuadPart);cudaMemcpy(h_outputg, d_output, N*L*sizeof(ft), cudaMemcpyDeviceToHost);cudaCheckErrors("cudaMemcpy failure");for (int i = 0; i < N*L; i++) if (h_outputg[i] != h_outputc[i]) {std::cout << "Mismatch at " << i << " was: " << h_outputg[i] << " should be: " << h_outputc[i] << std::endl; return 0;}std::cout << "Kernel execution time: \t" << dt / 1000.0f << "ms" << std::endl;return 0;
}

2. GPU version1

2.1 实现

template<typename T>
__global__ void gpu_version1(const T * __restrict__ input, T * __restrict__ output, const T * __restrict__ matrix,const int L,const int M, const int N
)
{___shared__ T smem[L];int idx = threadIdx.x;// 以此处理N个Batchfor(int k = 0; k < N; i++){T v = 0;for(int i = 0; i < M; ++i){v += input[K * M * L + M * idx + i]}v /= M;for(int row = 0; row < L; ++row) {smem[idx] = v * M[idx * L + row];// 对矩阵乘法求和for(int s = blockDim.x >> 1; s > 0; s >>=1){__syncthreads();if (idx < s) smem[threadIdx.x] += smem[threadIdx.x + s];}if (!threadIdx.x) ouput[i*N + row] = smem[0];}}
}const int L = 512; // maximum 1024
const int M = 512;
const int N = 1024;
// 调用核函数
gpu_version1<<<1, L>>>(d_input, d_output, d_matrix, L, M, N);

2.2 时间对比

CPU execution time:     2764.96ms
Kernel execution time:  1508.34ms

2.3 Nsight 分析

在这里插入图片描述

可以看到,这里This kernel grid is too small to fill the available resources on this device, resulting in only 0.0 full waves across all SMs.这里说我们的 grid size 设置得太小了,没有充分利用SM。下一版我们增大 Graid size

3. 增加GridSize

3.1 实现

分析上一个核函数调用:

gpu_version1<<<1, L>>>(d_input, d_output, d_matrix, L, M, N);

这里grid size是1,这里可以考虑把这个设置为 Batch size 即 N

gpu_version1<<<N, L>>>(d_input, d_output, d_matrix, L, M, N);

对应得核函数修改, 其实就是 把k 替换成了 blockIdx.x

template <typename T>
__global__ void gpu_version2(const T* __restrict__ input, T* __restrict__ output, const T* __restrict__ matrix, const int L, const int M, const int N) {// parallelize threadIdx.x over vector length, and blockIdx.x across k (N)__shared__ T smem[my_L];int idx = threadIdx.x;int k = blockIdx.x;T v1 = 0;for (int i = 0; i < M; i++)v1 += input[k * M * L + idx * M + i];v1 /= M;for (int i = 0; i < L; i++) {__syncthreads();smem[threadIdx.x] = v1 * matrix[i * L + idx];for (int s = blockDim.x >> 1; s > 0; s >>= 1) {__syncthreads();if (threadIdx.x < s) smem[threadIdx.x] += smem[threadIdx.x + s];}if (!threadIdx.x) output[k + i * N] = smem[0];}
}

3.2 时间对比

CPU execution time:     	3219.04ms
Kernel execution timev1:  	1508.34ms
Kernel execution timev2:  	91.4291ms

可以看到相对v1 提高了15倍 +

3.3 Nsight 分析

3.3.1 概览

相比上一个版本,SM和memory的利用率明显提高了。

在这里插入图片描述

3.3.2 Memoy Workload Analysis

The memory access pattern for global loads in L1TEX might not be optimal. On average, this kernel accesses 8.0 bytes per thread per memory request; but the address pattern, possibly caused by the stride between threads, results in 20.0 sectors per request, or 20.032 = 639.3 bytes of cache data transfers per request. The optimal thread address pattern for 8.0 byte accesses would result in 8.032 = 256.0 bytes of cache data transfers per request, to maximize L1TEX cache performance. Check the  Source Counters section for uncoalesced global loads.
在 L1TEX中,全局加载的内存访问模式可能不是最优的。平均来说,这个kernel 每个线程每次内存请内存会访问8 字节,但是当前的地址模式,可能由于线程之间的跨度导致每次请求了20个 sectors, 每次请求的缓存传输为 20 * 32 = 649.3 字节。对于8字节的访问,最优的线程地址模式使用的缓存传输数据为 8 * 32 = 256字节,为了最大化L1TEX缓存性能,检查没有 coalesed (合并)访问的全局加载。

为什么会导致这么高 ? 可以通过 source页面

在这里插入图片描述
可以发现高亮的这一句进行了大量的L2 Cache访问操作,为什么这一句会导致访问不合并呢?
是因为每次for循环都隔了 idx * M 个数据,导致缓存失效,如何解决这个问题呢?看下一节

相关文章:

【CUDA】Nsight profile驱动的CUDA优化

前置准备 安装NVIDIA Nsight Compute。 安装好后选择使用管理员权限启动下载官方 Demo 代码官方博客Shuffle warp 1. 任务介绍及CPU版本 1.1 任务介绍 任务理解&#xff1a; 有一个 L x M 的矩阵 M 1 M_1 M1​ 对其每行取平均值 得到 V 1 ∈ R L 1 V_1 \in \mathbb{R}^{…...

字符串的拼接

字符串拼接方式1 之前的算术运算符&#xff0c;只是用来数值类型进行数学运算的&#xff0c;而string不存在算术运算符不能计算&#xff0c;但是可以通过号来进行字符串拼接。 string str "123"; //用进行拼接 str str "456"; Console.WriteLine(str)…...

HIVE3.1.3+ZK+Kerberos+Ranger2.4.0高可用集群部署

目录 一、集群规划 二、介质下载 三、基础环境准备 1、解压文件 2、配置环境变量 四、配置zookeeper 1、创建主体 2、修改zoo.cfg 3、新增jaas.conf 4、新增java.env 5、重启ZK 6、验证ZK 五、配置元数据库 六、安装HIVE 1、创建Hiver的kerberso主体 2…...

Android ANR Trace日志阅读分析技巧

什么是Trace日志 Trace日志是指ANR目录下的一份txt文件 adb pull /data/anr/traces.txt Trace日志有什么用 分析应用ANR无响应的问题&#xff0c; Trace怎么用 Cmd line: com.xx ABI: arm Build type: optimized Zygote loaded classes3682 post zygote classes3750 Intern…...

前端Ajax、Axios和Fetch的用法和区别笔记

前端 JavaScript 开发中&#xff0c;进行 HTTP 请求的三种主要方式是 Ajax、Axios 和 Fetch。这三种方式各有优缺点&#xff0c;并且适用于不同的场景。在合适的业务场景下使用&#xff0c;以下是它们的区别和使用举例。 1. Ajax Ajax&#xff08;Asynchronous JavaScript an…...

Android的Framework(TODO)

&#xff08;TODO&#xff09;...

牛客小白月赛94 EF题解

题目描述 注&#xff1a;此版本为本题的hard&#xff08;困难版&#xff09;&#xff0c;与easy&#xff08;简单版&#xff09;唯一的不同之处只有数据范围。 小苯有一个容量为 k 的背包&#xff0c;现在有 n 个物品&#xff0c;每个物品有一个体积 v 和价值 w&#xff0…...

大数据开发面试题【Flink篇】

148、flink架构 flink是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算 特点&#xff1a; 高吞吐和低延迟&#xff1a;每秒数百万个事件&#xff0c;毫秒级延迟 结果的准确性&#xff1a;提供了事件时间和处理时间语义&#xff0c;提供结果的一致…...

Java技术深度解析:高级面试问题与精粹答案(二)

Java 面试问题及答案 1. 什么是Java的垃圾回收机制&#xff1f;它是如何工作的&#xff1f; 答案&#xff1a; Java的垃圾回收机制&#xff08;Garbage Collection&#xff0c;GC&#xff09;是Java运行时环境&#xff08;JRE&#xff09;中的一个功能&#xff0c;用于自动管…...

算数运算符

算术运算符是用于数值类型变量计算的运算符。 它的返回结果是数值。 赋值符号 关键知识点&#xff1a;先看右侧&#xff0c;再看左侧&#xff0c;把右侧的值赋值给左侧的变量。 附上代码&#xff1a; string myName "唐唐"; int myAge 18; float myHeight 177.5…...

闲话 .NET(3):.NET Framework 的缺点

前言 2016 年&#xff0c;微软正式推出 .NET Core 1.0&#xff0c;并在 2019 年全面停止 .NET Framework 的更新。 .NET Core 并不是 .NET Framework 的升级版&#xff0c;而是一个从头开始开发的全新平台&#xff0c;一个跟 .NET Framework 截然不同的开源技术框架。 微软为…...

WPF实现简单的3D图形

简述 Windows 演示基础 &#xff08;WPF&#xff09; 提供了一种功能&#xff0c;用于根据应用程序要求绘制、转换 3D 图形并为其添加动画效果。它不支持完整的3D游戏开发&#xff0c;但在某种程度上&#xff0c;您可以创建3D图形。 通过组合 2D 和 3D 图形&#xff0c;您还可以…...

设计模式之创建型模式---原型模式(ProtoType)

文章目录 概述类图原型模式优缺点优点缺点 代码实现 概述 在有些系统中&#xff0c;往往会存在大量相同或者是相似的对象&#xff0c;比如一个围棋或者象棋程序中的旗子&#xff0c;这些旗子外形都差不多&#xff0c;只是演示或者是上面刻的内容不一样&#xff0c;若此时使用传…...

git命令新建远程仓库

今天记录一下使用git命令新建远程分支的操作&#xff0c;因为公司的代码管理仓库界面没找到新建分支的操作界面&#xff0c;无奈只能通过git命令来新建分支。 1、新建本地分支 首先&#xff0c;你的至少应该已经有了一个master分支&#xff0c;然后你再master分支下面执行下面…...

Defog发布Llama-3-SQLCoder-8B,文本转SQL模型,性能比肩GPT-4,准确率超90%,消费级硬件可运行

前言 在计算语言学领域&#xff0c;将自然语言转化为可执行的SQL查询是一个重要的研究方向。这对于让那些没有编程或SQL语法知识的用户也能轻松访问数据库信息至关重要。Defog团队近日发布了基于Llama-3的SQLCoder-8B模型&#xff0c;它在文本转SQL模型领域取得了显著突破&…...

防刷发送短信验证码接口的五种简单好用方法绝对够用

防刷发送短信验证码接口的五种简单好用方法&#xff0c;绝对够用 前端增加图形验证码&#xff0c;点击发送按钮后增加60s倒计时&#xff0c;60s后才可以再次点击 后端对接口次数校验&#xff0c;60s内同一电话号码只能发送一次 // 生成基于电话号码的重试锁定键 String repeat…...

ubuntu中idea创建spark项目步骤

1.前置条件 ubuntu中已经安装idea,jdk,scala,spark 2.打开idea&#xff0c;新建&#xff0c;选择Maven项目 3.在IDEA中&#xff0c;File-Setting-Plugin&#xff0c;下载Scala插件 4.File-project structure&#xff0c;导入插件 4.1在全局库中&#xff0c;选择导入刚才的sca…...

回文链表(快慢指针解法之在推进过程中反转)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd;抱怨深处黑暗&#xff0c;不如提灯前行…...

深度剖析:为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解

目录 依赖注入简介 Autowired 注解的优缺点 Spring 和 IDEA 不推荐使用 Autowired 的原因 构造器注入的优势 Autowired 注解的局限性 可读性和可测试性的问题 推荐的替代方案 构造器注入 Setter 注入 Java Config Bean 注解 项目示例&#xff1a;Autowired vs 构造器…...

【接口自动化_05课_Pytest接口自动化简单封装与Logging应用】

一、关键字驱动--设计框架的常用的思路 封装的作用&#xff1a;在编程中&#xff0c;封装一个方法&#xff08;函数&#xff09;主要有以下几个作用&#xff1a;1. **代码重用**&#xff1a;通过封装重复使用的代码到一个方法中&#xff0c;你可以在多个地方调用这个方法而不是…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...