CUDA编程-(2)其实写个矩阵相乘并不是那么难
程序代码及图解析:
#include <iostream>
#include "book.h"
__global__ void add( int a, int b, int *c ) {
*c = a + b;
}
int main( void ) {
int c;
int *dev_c;
HANDLE_ERROR( cudaMalloc( (void**)&dev_c, sizeof(int) ) );
add<<<1,1>>>( 2, 7, dev_c );
HANDLE_ERROR( cudaMemcpy( &c,
dev_c,
sizeof(int),
cudaMemcpyDeviceToHost ) );
printf( "2 + 7 = %d\n", c );
cudaFree( dev_c );
return 0;
}
函数原型:__host__cudaError_t cudaMemcpy (void *dst, const void *src, size_t count, cudaMemcpyKind kind)
作用:在设备端和主机端拷贝数据。
参数:dst 目的地址 src 源地址 count 拷贝字节大小kind 传输的类型
返回值:
cudaSuccess, cudaErrorInvalidValue, cudaErrorInvalidDevicePointer, cudaErrorInvalidMemcpyDirection
说明:
从源地址拷贝设定数量的字节数至目的地址,kind类型有四种,分别为:
cudaMemcpyHostToHost, cudaMemcpyHostToDevice, cudaMemcpyDeviceToHost, cudaMemcpyDeviceToDevice,
通过指定方向进行拷贝。存储器区域不可重叠。如若产生未定义拷贝方向的行为,dst和src将不匹配。
正文
前面的图是最简单的一个CUDA程序,它引出了Grid Block Thread概念。很多threads组成1维,2维or3维的thread block. 为了标记thread在block中的位置(index),我们可以用上面讲的threadIdx。threadIdx是一个维度<=3的vector。还可以用thread index(一个标量)表示这个位置。
thread的index与threadIdx的关系:
Thread index | |
1 | T |
2 | T.x + T.y * Dx |
3 | T.x+T.y*Dx+z*Dx*Dy |
其中T表示变量threadIdx。(Dx, Dy, Dz)为block的size(每一维有多少threads)。
因为一个block内的所有threads会在同一处理器内核上共享内存资源,所以block内有多少threads是有限制的。目前GPU限制每个 block最多有1024个threads。但是一个kernel可以在多个相同shape的block上执行,效果等效于在一个有N*#thread per block个thread的block上执行。
Block又被组织成grid。同样,grid中block也可以被组织成1维,2维or3维。一个grid中的block数量由系统中处理器个数或待处理的数据量决定。(来自这里)
下图中描述了Thread、Block、Grid内存的访问机制。
每个thread有自己的local-memory。每一个block有自己的共享内存、grid和grid之间可以同时访问全局内存。这里要注意:block和block之间不能访问同一个共享内存,他们只能访问自己的共享内存。
cudaGetDeviceCount( &count )查询服务器的CUDA信息.
#include <stdio.h>
#include <cuda_runtime.h>
int main()
{
int deviceCount;
cudaGetDeviceCount(&deviceCount);
int device;
for(device = 0; device < deviceCount; ++device)
{
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp,device);
printf("Device %d has compute capability %d.%d.\n",device,deviceProp.major,deviceProp.minor);
}
}
结果:
struct cudaDeviceProp {
char name[256]; //识别设备的ASCII字符串(例如,“GeForce GTX 280”)
size_t totalGlobalMem; //全局内存大小
size_t sharedMemPerBlock; //每个block内共享内存的大小
int regsPerBlock; //每个block32位寄存器的个数
int warpSize; // warp大小
size_t memPitch; //内存中允许的最大间距字节数
int maxThreadsPerBlock; //每个Block中最大的线程数是多少
int maxThreadsDim[3]; // 一个块中每个维度的最大线程数
int maxGridSize[3]; //一个网格的每个维度的块数量
size_t totalConstMem; //可用恒定内存量
int major; //该设备计算能力的主要修订版号
int minor; //设备计算能力的小修订版本号
int clockRate; //时钟速率
size_t textureAlignment; //该设备对纹理对齐的要求
int deviceOverlap; //一个布尔值,表示该装置是否能够同时进行cudamemcpy()和内核执行
int multiProcessorCount; //设备上的处理器的数量
int kernelExecTimeoutEnabled; //一个布尔值,该值表示在该设备上执行的内核是否有运行时的限制
int integrated; //返回一个布尔值,表示设备是否是一个集成的GPU(即部分的芯片组、没有独立显卡等)
int canMapHostMemory; //表示设备是否可以映射到CUDA设备主机内存地址空间的布尔值
int computeMode; //一个值,该值表示该设备的计算模式:默认值,专有的,或禁止的
int maxTexture1D; //一维纹理内存最大值
int maxTexture2D[2]; //二维纹理内存最大值
int maxTexture3D[3]; //三维纹理内存最大值
int maxTexture2DArray[3]; //二维纹理阵列支持的最大尺寸
int concurrentKernels; //一个布尔值,该值表示该设备是否支持在同一上下文中同时执行多个内核
}
矩阵相乘也非常简单,难在如何在这个基础上提高速率。比如:引入sharememory。
代码:
#include <stdio.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <time.h>
#include <stdlib.h> __global__ void MatrixMuiOnDevice(int *M,int *N, int *P, int width)
{
int x = threadIdx.x;
int y = threadIdx.y; //获取该线程的位置 float Pervalue = 0; for (int i = 0; i < width; i++)
{
float Mdlement = M[y * width + i];
float Ndlement = N[width * i + x]; Pervalue += Mdlement * Ndlement;
} P[y * width + x] = Pervalue;
}
int main()
{
int a[30][30],b[30][30],c[30][30];
int *M, *N, *P;
int width = 30;
int NUM = 900;
dim3 dimBlock(30,30);
cudaEvent_t start,stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop); cudaMalloc((void**)&M, 900*sizeof(int));
cudaMalloc((void**)&N, 900*sizeof(int));
cudaMalloc((void**)&P, 900*sizeof(int));
//初始化
for(int i = 0; i < 30; i++)
for(int j = 0; j < 30; j++)
{
a[i][j] = 2;
b[i][j] = 3;
} cudaMemcpy(M,a,NUM*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(N,b,NUM*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(c,P,NUM*sizeof(int),cudaMemcpyDeviceToHost);
cudaEventRecord(start,0);
MatrixMuiOnDevice<<<1,dimBlock>>>(M,N,P,width);
cudaThreadSynchronize();
cudaEventRecord(stop,0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime,start,stop); printf("%f\n",elapsedTime);
for(int i = 0; i < 30; i++)
for(int j = 0; j < 30; j++)
{
printf("%d \n",c[i][j]);
} cudaFree(M);
cudaFree(N);
cudaFree(P);
return 0;
}
share memory 改进。加入同步机制 __syncthreads(),即 等待之前的所有线程执行完毕后再接下去执行。
#include <stdio.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <time.h>
#include <stdlib.h> #define TILE_WIDTH 25 __global__ void MatrixMuiOnDevice(int *M,int *N, int *P, int width)
{ __shared__ float Mds[TILE_WIDTH][TILE_WIDTH];
__shared__ float Nds[TILE_WIDTH][TILE_WIDTH]; int bx = blockIdx.x;
int by = blockIdx.y;
int tx = threadIdx.x;
int ty = threadIdx.y;
int Col = bx * TILE_WIDTH + tx;
int Row = by * TILE_WIDTH + ty; //获取该线程的位置 int Pervalue = 0; for (int i = 0; i < width / TILE_WIDTH; i++)
{
Mds[ty][tx] = Md[Row * width+(i * TILE_WIDTH + tx)];
Nds[ty][tx] = Nd[Col + (i * TILE_WIDTH + ty) * width];
__syncthreads(); for (int k = 0; k < width / TILE_WIDTH; k++)
Pervalue += Mds[ty][k] * Nds[k][tx];
__syncthreads();
} P[Row * width + Col] = Pervalue;
} int main()
{
int WID = 100;
int a[WID][WID],b[WID][WID],c[WID][WID];
int *M, *N, *P;
int width = WID / 4 ;;
int NUM = WID*WID;
dim3 dimGrid(WID/width,WID/width);
dim3 dimBlock(width,width);
cudaEvent_t start,stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop); cudaMalloc((void**)&M, NUM*sizeof(int));
cudaMalloc((void**)&N, NUM*sizeof(int));
cudaMalloc((void**)&P, NUM*sizeof(int));
//初始化
for(int i = 0; i < 100; i++)
for(int j = 0; j < 100; j++)
{
a[i][j] = 2;
b[i][j] = 3;
} cudaMemcpy(M,a,NUM*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(N,b,NUM*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(c,P,NUM*sizeof(int),cudaMemcpyDeviceToHost);
cudaEventRecord(start,0);
MatrixMuiOnDevice<<<dim,dimBlock>>>(M,N,P,width);
cudaThreadSynchronize();
cudaEventRecord(stop,0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime,start,stop); printf("%f\n",elapsedTime); cudaFree(M);
cudaFree(N);
cudaFree(P);
return 0;
}
小结
第一个执行时间:
share memory执行时间:
注意,核函数内不是所有线程一起进去执行,这个概念模糊不清。我们需要理解成,所有的线程并行执行核函数里面的程序,即每一个线程都会执行该函数,所有线程执行完,即结束。这个简单的概念,我一开始想了很久。
注:转载请注明出处。
CUDA编程-(2)其实写个矩阵相乘并不是那么难的更多相关文章
- java 写一个 map reduce 矩阵相乘的案例
1.写一个工具类用来生成 map reduce 实验 所需 input 文件 下面两个是原始文件 matrix1.txt 1 2 -2 0 3 3 4 -3 -2 0 2 3 5 3 -1 2 -4 ...
- 编程计算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编程之快速入门
CUDA(Compute Unified Device Architecture)的中文全称为计算统一设备架构.做图像视觉领域的同学多多少少都会接触到CUDA,毕竟要做性能速度优化,CUDA是个很重要 ...
- CUDA编程之快速入门【转】
https://www.cnblogs.com/skyfsm/p/9673960.html CUDA(Compute Unified Device Architecture)的中文全称为计算统一设备架 ...
- 记一次CUDA编程任务
这个月6号开始,着手解决一个具有实际意义的计算任务.任务数据有9879896条,每条包含30个整数,任务是计算每两条数据之间的斯皮尔相关系数及其P值.原始数据只有500+MB,因此我并不认为这是个多么 ...
- CUDA学习笔记(一)——CUDA编程模型
转自:http://blog.sina.com.cn/s/blog_48b9e1f90100fm56.html CUDA的代码分成两部分,一部分在host(CPU)上运行,是普通的C代码:另一部分在d ...
- 利用Hadoop实现超大矩阵相乘之我见(一)
前记 最近,公司一位挺优秀的总务离职,欢送宴上,她对我说“你是一位挺优秀的程序员”,刚说完,立马道歉说“对不起,我说你是程序员是不是侮辱你了?”我挺诧异,程序员现在是很低端,很被人瞧不起的工作吗?或许 ...
- CUDA编程-(1)Tesla服务器Kepler架构和万年的HelloWorld
结合CUDA范例精解以及CUDA并行编程.由于正在学习CUDA,CUDA用的比较多,因此翻译一些个人认为重点的章节和句子,作为学习,程序将通过NVIDIA K40服务器得出结果.如果想通过本书进行CU ...
- CUDA编程(六)进一步并行
CUDA编程(六) 进一步并行 在之前我们使用Thread完毕了简单的并行加速,尽管我们的程序运行速度有了50甚至上百倍的提升,可是依据内存带宽来评估的话我们的程序还远远不够.在上一篇博客中给大家介绍 ...
随机推荐
- UVA 11300 Spreading the Wealth (数学推导 中位数)
Spreading the Wealth Problem A Communist regime is trying to redistribute wealth in a village. They ...
- gcc命令以及makefile文件
(一)makefile里涉及到的gcc命令 gcc -I./inc:指定头文件寻找目录 将按照 ./inc --> /usr/include --> /usr/local/include的 ...
- CSS定位机制
CSS中,存在3种定位机制:标准文档流(Normal flow) * 特点:从上到下,从左导游,输出文档内容 * 由块级元素和行级元素组成 浮动(Floats) * 能够实现横向多列布局 * 设置了浮 ...
- HTML5学习笔记----html5与传统html区别
一. HTML5语法的改变 该知识点所说变化指的是基于HTML4基础上所定义的改变,主要有如下: HTML5的文件扩展符(.html或.htm)与内容类型(text/html)保持不变. HTML5中 ...
- div+css3实现漂亮的多彩标签云,鼠标移动会有动画
div+css3实现漂亮的多彩标签云,鼠标移动会有动画 点击运行效果 <style> .dict { margin: 20px 0;clear:both ;text-align:left; ...
- notepad++ :正则表达式系统教程
前言&索引 前言 正则表达式是烦琐的,但是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感.只要认真去阅读这些资料,加上应用的时候进行一定的参考,掌握正则表达式不是问题. 索 ...
- JSON知多少-JSON数据结构
最近在开发微信平台,要使用JSON进行数据交换,之前用过JSON,但仅限于…… 在开发微信平台中,要使用JSON形式如下:代码片断1: { "button":[ { "t ...
- thinkphp给图片打水印不清晰
项目中打印条形码的函数,从thinkphp自带的water函数修改而来的. 贴上代码: /** * water2 * 改写thinkphp的water函数更强健的函数,增加了写入位置参数 去掉了alp ...
- nodejs中间层现实
初次接触nodejs,是一种非常神奇的东西,未来必火起来.个人觉得最大优势npm命令. 闲话少说,直入主题.这是一个博客项目,php最为服务端,提供数据给node:nodejs+express作为中间 ...
- C#开发攀爬集锦
工具使用 Files has invalid value "<<<<<<< .mine". Illegal characters in p ...