CUDA计算矩阵相乘
1.最简单的 kernel 函数
__global__ void MatrixMulKernel( float* Md, float* Nd, float* Pd, int Width)
{
int tx = threadIdx.x; // cloumn
int ty = threadIdx.y; // row
float Pvalue = 0;
for (int k = 0; k<Width; k++)
{
float Mdele = Md[ty*Width + k];
float Ndele = Nd[k*Width + tx];
Pvalue += Mdele * Ndele;
}
Pd[ty*Width + tx] = Pvalue;
}
2.适用更大矩阵
第一节中例子缺点是,假如使用更多的块时,每个块中会计算相同的矩阵。而且矩阵元素不能超过512个线程(块最大线程限制)。
改进方法是,假设每个块维度都是方阵形式,且其维度由变量 TILE_WIDTH 指定。矩阵 Pd 的每一维都划分为部分,每个部分包含 TILE_WIDTH 个元素。
#define TILE_WIDTH 4
#define Width 8
__global__ void MatrixMulKernel( float* Md, float* Nd, float* Pd, int Width)
{
int Col = blockId.x*TILE_WIDTH + threadIdx.x; // cloumn
int Row = blockId.y*TILE_WIDTH + threadIdx.y; // row
float Pvalue = 0;
for (int k = 0; k<Width; k++)
{
Pvalue += Md[Row*Width + k] * Nd[k*Width + Col];
}
Pd[ty*Width + tx] = Pvalue;
}
dim3 dimGrid(Width/TILE_WIDTH, Width/TILE_WIDTH);
dim3 dimBlock(TILE_WIDTH, TILE_WIDTH);
CUDA 硬件相关概念
针对 GT200而言
- 每个
SM有最多8个块 - 每个
SM有最多1024个线程
应当注意每个块中分配的线程数,以便能够充分利用SM
- 以32个线程为一个
warp,warp为线程调度单位
3.通过改变储存器提到访问效率
CGMA(Compute to Global Memory Access),尽量提高CGMA比值。
对前面来说,每个for循环内需要两次访问全局内存(Md[Row*Width + k], Nd[k*Width + Col]),两次浮点计算(加法与乘法)。因此 CGMA 为2:2 = 1。
G80 全局存储器带宽为 86.4 GB/s,计算峰值性能 367 Gflops。(每秒取 21.6G 个变量,由于CGMA=1,会进行 21.6G 次浮点计算)
若每个单精度浮点数为 4 字节,那么由于存储器限制,最大浮点操作不会超过 21.6 Gflops。
| 存储器类型 | 变量 | 周期 | 特点 | 访问速度 |
| --- | --- | --- | --- |
| 共享存储器 | 共享变量 | kernel函数 | 每个块中所有线程都可以访问,用于线程间协作高效方式 | 相当快,高度并行访问 |
| 常数存储器 | 常数变量 | 所有网格 | 相当快,并行访问 |
| 寄存器 | 自动变量 | 线程 | 寄存器具有储存容量限制 | 非常块
| 全局存储器 | 全局变量 | | 用于调用不同kernel函数时传递信息 | 慢 |
减少全局存储器流量策略
各个存储器特点:
- 全局存储器,容量大,访问慢
- 共享存储器,容量小,访问块
新算法要点:
- 将共享存储器上数据划分子集,每个子集满足共享存储器容量限制
- 通过线程协作将
M和N中的元素加载到共享存储器中,每个线程负责块中一个元素赋值(Mds[threadIdx.y][threadIdx.x],Nds[threadIdx.y][threadIdx.x]) - 通过加载到共享存储器,使得每个块访问全局内存的次数减小为原来的
TILE_WIDTH分之一(加载到共享内存时读取一次,每个块中使用TILE_WIDTH次)
__global__ void kernel_tile(float* M, float* N, float* P){
int i, k;
float Pvalue = 0;
__shared__ float Mds[tile_width][tile_width];
__shared__ float Nds[tile_width][tile_width];
int Row = threadIdx.y + blockIdx.y*tile_width;
int Col = threadIdx.x + blockIdx.x*tile_width;
for( i = 0; i< width/tile_width; i++ ){
Mds[threadIdx.y][threadIdx.x] = M[Row*width + i*tile_width + threadIdx.x];
Nds[threadIdx.y][threadIdx.x] = N[(threadIdx.y + i*tile_width)*width + Col];
__syncthreads();
for (k = 0; k<tile_width; k++){
Pvalue += Mds[threadIdx.y][k]*Nds[k][threadIdx.x];
}
__syncthreads();
}
P[Row*width + Col] = Pvalue;
}
存储器容量限制
G80 硬件中
- 每个
SM寄存器大小为 8 KB(8192 B) - 每个
SM共享内存大小为 16 KB - 若每个
SM中容纳线程数为 768,那么每个线程可用寄存器不超过 8 KB/768=10 Bytes(两个单精度变量占用 8 Bytes) - 若每个线程占用了多余 10 Bytes,那么就会减少
SM上线程数,且以块为单位减少 - 若每个
SM中容纳 8 个块,那么每个块不能使用超过 2 KB 的存储器
4.数据预取
在 CUDA 中,当某些线程在等待其存储器访问结果时,CUDA 线程模型可以通过允许其他 warp 继续运行,这样就能容许长时间的访问延时。
为了充分利用此特性,需要当使用当前数据元素时预取下一个数据元素,这样就可以正价在储存器访问和已访问的数据使用指令之间的独立指令的数目。
预取技术经常和分块技术结合,解决带宽限制和长时间延迟问题。
例如在第三节中矩阵乘法问题中,使用预取技术后函数流程变为

对应程序为
__global__ void kernel_prefetch(float* M, float* N, float* P){
int i;
float Pvalue = 0;
float Mc, Nc;
int Row = threadIdx.y + tile_width*blockIdx.y;
int Col = threadIdx.x + tile_width*blockIdx.x;
__shared__ float Mds[tile_width][tile_width];
__shared__ float Nds[tile_width][tile_width];
Mc = M[Row*width + threadIdx.x];
Nc = N[Col + threadIdx.y*width];
for (i = 1; i<width/tile_width+1; i++){
Mds[threadIdx.y][threadIdx.x] = Mc;
Nds[threadIdx.y][threadIdx.x] = Nc;
__syncthreads();
Mc = M[Row*width + threadIdx.x + i*tile_width];
Nc = N[Col + (threadIdx.y + i*tile_width)*width];
for (int k = 0; k<tile_width; k++){
Pvalue += Mds[threadIdx.y][k]*Nds[k][threadIdx.x];
}
__syncthreads();
}
P[Col + Row*width] = Pvalue;
}
Mc,Nc 为增加的两个储存在寄存器内的变量。
CUDA计算矩阵相乘的更多相关文章
- STL模板之_map,stack(计算矩阵相乘的次数)
#include <map>#include <stack>#include <iostream>using namespace std; struct Node ...
- Java实现矩阵相乘问题
1 问题描述 1.1实验题目 设M1和M2是两个n×n的矩阵,设计算法计算M1×M2 的乘积. 1.2实验目的 (1)提高应用蛮力法设计算法的技能: (2)深刻理解并掌握分治法的设计思想: (3)理解 ...
- CUDA编程-(2)其实写个矩阵相乘并不是那么难
程序代码及图解析: #include <iostream> #include "book.h" __global__ void add( int a, int b, i ...
- 编程计算2×3阶矩阵A和3×2阶矩阵B之积C。 矩阵相乘的基本方法是: 矩阵A的第i行的所有元素同矩阵B第j列的元素对应相乘, 并把相乘的结果相加,最终得到的值就是矩阵C的第i行第j列的值。 要求: (1)从键盘分别输入矩阵A和B, 输出乘积矩阵C (2) **输入提示信息为: 输入矩阵A之前提示:"Input 2*3 matrix a:\n" 输入矩阵B之前提示
编程计算2×3阶矩阵A和3×2阶矩阵B之积C. 矩阵相乘的基本方法是: 矩阵A的第i行的所有元素同矩阵B第j列的元素对应相乘, 并把相乘的结果相加,最终得到的值就是矩阵C的第i行第j列的值. 要求: ...
- cuda计算的分块
gpu的架构分为streaming multiprocessors 每个streaming multiprocessors(SM)又能分步骤执行很多threads,单个SM内部能同时执行的thread ...
- 利用Hadoop实现超大矩阵相乘之我见(二)
前文 在<利用Hadoop实现超大矩阵相乘之我见(一)>中我们所介绍的方法有着“计算过程中文件占用存储空间大”这个缺陷,本文中我们着重解决这个问题. 矩阵相乘计算思想 传统的矩阵相乘方法为 ...
- 利用Hadoop实现超大矩阵相乘之我见(一)
前记 最近,公司一位挺优秀的总务离职,欢送宴上,她对我说“你是一位挺优秀的程序员”,刚说完,立马道歉说“对不起,我说你是程序员是不是侮辱你了?”我挺诧异,程序员现在是很低端,很被人瞧不起的工作吗?或许 ...
- POJ 2246 Matrix Chain Multiplication(结构体+栈+模拟+矩阵相乘)
题意:给出矩阵相乘的表达式,让你计算需要的相乘次数,如果不能相乘,则输出error. 思路: 参考的网站连接:http://blog.csdn.net/wangjian8006/article/det ...
- MapReduce实现矩阵相乘
矩阵相乘能够查看百度百科的解释http://baike.baidu.com/view/2455255.htm?fr=aladdin 有a和b两个矩阵 a: 1 2 ...
随机推荐
- 【二食堂】Beta - 事后分析
事后分析 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? Beta阶段我们首先要对文本标注方式进行优化,其次时添加好友系统,实现邀请好友共同标注的功能. ...
- [软工顶级理解组] Beta阶段项目展示
目录 团队成员 软件介绍 项目简介 预期典型用户 功能描述 预期目标用户数 用户反馈 团队管理 分工协作 项目管理 取舍平衡 代码管理 程序测试 代码规范 文档撰写 继续开发指导性 用户沟通 需求分析 ...
- netty入门实现简单的echo程序
最近看以往在程序中编写的代码,发现有一个功能是使用socket通讯来实现的,而那个时候使用的是基于bio的阻塞io来实现的,最近在看netty,发现可以使用netty来使用nio的方式来实现,此博客记 ...
- java中的软,弱,虚引用介绍与特性分析
java的弱,虚,软引用介绍 1.弱,虚,软引用的介绍 对于绝大部分的对象而言,在程序中是存在着一个引用变量引用该对象,这是常见的引用方式,也就是常说的 强引用,对于强引用引用的对象,系统JVM是不会 ...
- [LGP2758]编辑距离
目录 题目 题目描述 输入格式 输出格式 输入输出样例 题目分析 状态转移方程 初始状态 结束状态 Code 题目 题目描述 设A和B是两个字符串.我们要用最少的字符操作次数,将字符串A转换为字符串B ...
- Python课程笔记(七)
今天学习神奇的海龟,非常有意思,还有很多图片想去绘制,分享一个turtle绘图网站: https://www.python123.io/index/turtles/latest , 要是可以分享出源码 ...
- Tarjan算法离线 求 LCA(最近公共祖先)
本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig ...
- 用C++实现的数独解题程序 SudokuSolver 2.7 及实例分析
引言:一个 bug 的发现 在 MobaXterm 上看到有内置的 Sudoku 游戏,于是拿 SudokuSolver 求解,随机出题,一上来是个 medium 级别的题: 073 000 060 ...
- Filter学习笔记
博客园的编辑器太丑了,所以我换用了别的Markdown编辑器,并用图片形式上传.
- pip 安装使用 ImportError: No module named setuptools 解决方法
安装过程详见这篇博客: http://www.ttlsa.com/python/how-to-install-and-use-pip-ttlsa/ 安装后运行到:python setup.py ins ...