【CUDA开发】CUDA开发琐碎知识
## 一维矩阵的加
//实现一个一维1*16的小矩阵的加法。
//矩阵大小:1*16
//分配一个block,共有16个线程并发。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <cuda_runtime.h>
#include <cutil.h>
#define VEC_SIZE 16
//kernel function
__global__ void vecAdd(float* d_A,float* d_B,float* d_C)
{
int index=threadIdx.x;
d_C[index]=d_A[index]+d_B[index];
}
int main()
{
//得到分配空间的大小
size_t size=VEC_SIZE*sizeof(float);
//为本地分配内存
float* h_A=(float*)malloc(size);
float* h_B=(float*)malloc(size);
float* h_C=(float*)malloc(size);
//初始化
for (int i=0;i<VEC_SIZE;++i)
{
h_A[i]=1.0;
h_B[i]=2.0;
}
//将本地内存的中的数据复制到设备中
float* d_A;
cudaMalloc((void**)&d_A,size);
cudaMemcpy(d_A,h_A,size,cudaMemcpyHostToDevice);
float* d_B;
cudaMalloc((void**)&d_B,size);
cudaMemcpy(d_B,h_B,size,cudaMemcpyHostToDevice);
//分配存放结果的空间
float* d_C;
cudaMalloc((void**)&d_C,size);
//定义16个线程
dim3 dimblock(16);
vecAdd<<<1,dimblock>>>(d_A,d_B,d_C);
//讲计算结果复制回主存中
cudaMemcpy(h_C,d_C,size,cudaMemcpyDeviceToHost);
//输出计算结果
for (int j=0;j<VEC_SIZE;++j)
{
printf("%f/t",h_C[j]);
}
//释放主机和设备内存
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
free(h_A);
free(h_B);
free(h_C);
return 0;
}
名称 cudaMallocPitch – 向GPU分配存储器
概要 cudaError_t cudaMallocPitch( void** devPtr,size_t* pitch,size_t widthInBytes,size_t height )
说明 向设备分配至少widthInBytes*height字节的线性存储器,并以*devPtr的形式返回指向所分配存储器的指针。该函数可以填充所分配的存储器,以确保在地址从一行更新到另一行时,给定行的对应指针依然满足对齐要求。cudaMallocPitch()以*pitch的形式返回间距,即所分配存储器的宽度,以字节为单位。间距用作存储器分配的一个独立参数,用于在2D数组内计算地址。如果给定一个T类型数组元素的行和列,可按如下方法计算地址:
T* pElement = (T*)((char*)BaseAddress + Row * pitch) + Column;
对于2D数组的分配,建议程序员考虑使用cudaMallocPitch()来执行间距分配。由于硬件中存在间距对齐限制,如果应用程序将在设备存储器的不同区域之间执行2D存储器复制(无论是线性存储器还是CUDA数组),这种方法将非常有用。
例子:为EmuDebug
原来《CUDA编程指南》上给出的pitch的类型为int,在实际运行时与cudaMallocPitch()类型不匹配。
/************************************************************************/
/* This is a example of the CUDA program.
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime.h>
#include <cutil.h>
/************************************************************************/
/* myKernel */
/************************************************************************/
__global__ void myKernel(float* devPtr,int height,int width,int pitch)
{
for(int r=0;r {
float* row=(float*)((char*)devPtr+r*pitch);
for (int c=0;c {
float element=row[c];
printf("%f/n",element);//模拟运行
}
}
}
/************************************************************************/
/* Main CUDA */
/************************************************************************/
int main(int argc, char* argv[])
{
size_t width=10;
size_t height=10;
float* decPtr;
//pitch的值应该为size_t在整形的时,与函数参数不匹配
size_t pitch;
cudaMallocPitch((void**)&decPtr,&pitch,width*sizeof(float),height);
myKernel<<<1,1>>>(decPtr,10,10,pitch);
cudaFree(decPtr);
printf("%d/n",pitch);
//CUT_EXIT(argc, argv);
return 0;
}
## cudaMallocArray()的使用
名称:
cudaMemcpyToArray – 在主机和设备间复制数据
概要:
cudaError_t cudaMemcpyToArray(struct cudaArray* dstArray,size_t dstX,size_t dstY,const void* src,size_t count,enum cudaMemcpyKind kind)
cudaError_t cudaMemcpyToArrayAsync(struct cudaArray* dstArray,size_t dstX,size_t dstY,const void* src,size_t count,enum cudaMemcpyKind kind,cudaStream_t stream)
说明
从src指向的存储器区域内将count个字节复制到一个CUDA数组dstArray,该数组的左上角从(dstX,dstY)开始,其中kind是cudaMemcpyHostToHost、cudaMemcpyHost-ToDevice、cudaMemcpyDeviceToHost或cudaMemcpyDeviceToDevice之一,用于指定复制的方向。
cudaMemcpyToArrayAsync()是异步的,可选择传入非零流参数,从而将其关联到一个流。它仅对分页锁定的主存储器有效,如果传入指向可分页存储器的指针,那么将返回一个错误。
返回值
相关返回值:
cudaSuccess
cudaErrorInvalidValue
cudaErrorInvalidDevicePointer cudaErrorInvalidMemcpyDirection
注意,如果之前是异步启动,该函数可能返回错误码。
注:
在《CUDA编程指导》中对,cudaMallocArray()函数的使用,个人觉得有错误。
enum cudaMemcpyKind kind ,应该是cudaMemcpyHostToHost、cudaMemcpyHost-ToDevice、cudaMemcpyDeviceToHost或cudaMemcpyDeviceToDevice之一。
在指导中使用的是cudaMemcpyToArray(cuArray,0,0,h_data,&channelDesc),channelDese为cudaChannelFormatDesc类型,不是cudaMemcpyKind.
/*********************************************************************/
/* This is a example of the CUDA program.*/
/*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime.h>
#include <cutil.h>
/************************************************************************/
/* myKernel */
/************************************************************************/
/************************************************************************/
/* Main CUDA */
/************************************************************************/
int main(int argc, char* argv[])
{
const int width=10;
const int height=10;
//初始化h_array
int h_array[width][height];
for (int i=0;i<width;i++)
for (int j=0;j<height;++j)
h_array[i][j]=j+i*64;
}
}
//以机构提channelDesc描述CUDA数组中的组件数量和数据类型
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32,0,0,0,cudaChannelFormatKindUnsigned);
cudaArray* cuArray;
cudaMallocArray(&cuArray,&channelDesc,width,height);
size_t sizeMem=width*height*sizeof(int);
size_t potX=0;
size_t potY=0;
cudaMemcpyToArray(cuArray,potX,potY,h_array,sizeMem,cudaMemcpyDeviceToHost);
cudaFreeArray(cuArray);
return 0;
}
## CUDA统计时间
在CUDA中统计运算时间,大致有三种方法:
<1>使用cutil.h中的函数
unsigned int timer=0;
//创建计时器
cutCreateTimer(&timer);
//开始计时
cutStartTimer(timer);
{
//统计的代码段
…………
}
//停止计时
cutStopTimer(timer);
//获得从开始计时到停止之间的时间
cutGetTimerValue( timer);
//删除timer值
cutDeleteTimer( timer);
不知道在这种情况下,统计精度。
<2>time.h中的clock函数
clock_t start, finish;
float costtime;
start = clock();
{
//统计的代码段
…………
}
finish = clock();
//得到两次记录之间的时间差
costtime = (float)(finish - start) / CLOCKS_PER_SEC;
时钟计时单元的长度为1毫秒,那么计时的精度也为1毫秒。
<3>事件event
cudaEvent_t start,stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecend(start,0);
{
//统计的代码段
…………
}
cudaEventRecord(stop,0);
float costtime;
cudaEventElapsedTime(&costtime,start,stop);
cudaError_t cudaEventCreate( cudaEvent_t* event )---创建事件对象;
cudaError_t cudaEventRecord( cudaEvent_t event,CUstream
stream )--- 记录事件;
cudaError_t
cudaEventElapsedTime( float* time,cudaEvent_t start,cudaEvent_t
end )---计算两次事件之间相差的时间;
cudaError_t
cudaEventDestroy( cudaEvent_t event )---销毁事件对象。
计算两次事件之间相差的时间(以毫秒为单位,精度为0.5微秒)。如果尚未记录其中任何一个事件,此函数将返回cudaErrorInvalidValue。如果记录其中任何一个事件使用了非零流,则结果不确定。
## CUDA代码常用编写技巧
1. 声明 __shared__ 变量或数组:
__shared__ float sh_farr[ 256];
__shared__ int a;
2.结构体指针成员的分配设备内存:
typedef struct Teacher_t
...{
int a;
unsigned int *g_mem1;
float *g_mem2;
}Teacher;
void initMem( Teacher& t, const unsigned int mat_size)
...{
unsigned int mat_size_ui = sizeof(int) * mat_size;
unsigned int mat_size_f = sizeof(float) * mat_size;
CUDA_SAFE_CALL( cudaMalloc((void**)&t.g_mem1, mat_size_ui) );
CUDA_SAFE_CALL( cudaMalloc((void**)&t.g_mem1, mat_size_f) );
...
}
3.计时:
unsigned int timer = 0;
CUT_SAFE_CALL( cutCreateTimer( &timer));
CUT_SAFE_CALL( cutStartTimer( timer));
...{
...//kernel
}
CUT_SAFE_CALL( cutStopTimer( timer));
printf( "Total time: %f ms ", cutGetTimerValue( timer) );
CUT_SAFE_CALL( cutDeleteTimer( timer));
4. 获取输入命令行中包含的文件名:
/**/////////////////////////////////////////////////////////////////////////////////
//! Check if a particular filename has to be used for the file where the result
//! is stored
//! @param argc number of command line arguments (from main(argc, argv)
//! @param argv pointers to command line arguments (from main(argc, argv)
//! @param filename filename of result file, updated if user specified
//! filename
/**/////////////////////////////////////////////////////////////////////////////////
void
getResultFilename( int argc, char** argv, char*& filename)
...{
char* temp = NULL;
cutGetCmdLineArgumentstr( argc, (const char**) argv, "filename-result", &temp);
if( NULL != temp)
...{
filename = (char*) malloc( sizeof(char) * strlen( temp));
strcpy( filename, temp);
cutFree( temp);
}
printf( "Result filename: '%s' ", filename);
}
类似的:
/**/////////////////////////////////////////////////////////////////////////////////
//! Check if a specific precision of the eigenvalue has to be obtained
//! @param argc number of command line arguments (from main(argc, argv)
//! @param argv pointers to command line arguments (from main(argc, argv)
//! @param iters_timing numbers of iterations for timing, updated if a
//! specific number is specified on the command line
/**/////////////////////////////////////////////////////////////////////////////////
void
getPrecision( int argc, char** argv, float& precision)
...{
float temp = -1.0f;
cutGetCmdLineArgumentf( argc, (const char**) argv, "precision", &temp);
if( temp > 0.0f)
...{
precision = temp;
}
printf( "Precision: %f ", precision);
}
5.Host调用完kernel函数需要进行线程同步,而在kernel或global函数只需要在必要的地方__syncthreads();即可:
CUDA_SAFE_CALL( cudaThreadSynchronize());
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dvchn/archive/2008/02/25/2119590.aspx
【CUDA开发】CUDA开发琐碎知识的更多相关文章
- CUDA并行程序设计 开发环境搭建与远程调试
课题需要用到GPU加速.目前使用的台式电脑只有核心显卡,而实验室有一台服务器装有NVIDIA GTX980独显.因此,想搭建一个CUDA的开发环境,来实现在台式机上面开发cuda程序,程序在服务器而不 ...
- CUDA开发 - CUDA 版本
"CUDA runtime is insufficient with CUDA driver"CUDA 9.2: 396.xx CUDA 9.1: 387.xx CUDA 9.0: ...
- 前端开发:css基础知识之盒模型以及浮动布局。
前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西? 为什么这个浮动没有效果? 这个问题楼主已经回答了n遍.今天则是把 ...
- iOS开发学习概述及知识整理
设计师设计出来了一个不错的引导界面,然而当我看到设计稿的时候,我们的app也没几天就要上线了.这个界面模仿了Evernote iOS app的风格. 我以迅雷不及掩耳盗铃之势开始在Xcode上编程,用 ...
- SQL点滴17—使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识
原文:SQL点滴17-使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识 在开发过程中会遇到需要弄清楚这个数据库什么时候建的,这个数据库中有多少表,这个存储过程长的什么样子等等信息 ...
- 第二章 Odoo 12开发之开发环境准备
在更深入了解 Odoo 开发之前,我们应配置好开发环境并学习相关的基础管理任务.本文中,我们将学习创建 Odoo 应用所需用到的工具和环境配置.这里采用 Ubuntu 系统来作为开发服务器实例的主机, ...
- XE7 & IOS开发之开发账号(3):证书、AppID、设备、授权profile的申请使用,附Debug真机调试、Ad hoc下iPA文件生成演示(XCode5或以上版本推荐,有图有真相)
网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 注意,以下讨论都是以&q ...
- XE7 & IOS开发之开发账号(2):发布证书、发布授权profile的申请使用,附Ad hoc真机调试、生成ipa文件演示(XCode所有版本通用,有图有真相)
网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 注意,以下讨论都是以&q ...
- XE7 & IOS开发之开发账号(1):开发证书、AppID、设备、开发授权profile的申请使用,附Debug真机调试演示(XCode所有版本通用,有图有真相)
网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 注意,以下讨论都是以&q ...
- Spark集群 + Akka + Kafka + Scala 开发(3) : 开发一个Akka + Spark的应用
前言 在Spark集群 + Akka + Kafka + Scala 开发(1) : 配置开发环境中,我们已经部署好了一个Spark的开发环境. 在Spark集群 + Akka + Kafka + S ...
随机推荐
- RookeyFrame 加载 自定义JS
注意JS存放的位置:是在model文件夹下的某某文件夹!!! 线上添加的模块: 1.JS文件名:和表名一致 2.JS目录:Rookey.BusSys.Web\Scripts\model\TempMod ...
- 模板 - 字符串 - KMP算法
要先理解前缀函数的定义,前缀函数 \(\pi(i)\) 表示字符串 \(s[0,i]\) 的同时是其最长真前缀及最长真后缀的长度,简单来说就是这个 \(s[0,i]\) 首尾最长的重叠长度(不能完全重 ...
- vgg16中的函数
1.inspect.getfile(文件名)文件名一般与类名相同,返回文件目录包含文件名 import inspect class os测试: def __init__(self): path = i ...
- 2018-2019 20165226 Exp 8 Web基础
2018-2019 20165226 Exp 8 Web基础 目录 一.实验内容说明及基础问题回答 二.实验过程 1.Web前端:HTML 2.Web前端j:avascipt 3.Web后端:MySQ ...
- CentOS安装相应版本的内核源码
昨天接到同事给安排的新任务,测试系统性能:网上查了些资料,目测perf功能很强大,而且是内核源码自带的,编译安装即可使用:看了下自己的虚拟机,没有内核源码,好吧,装一个: 查看一下系统版本: #cat ...
- 机器不学习:CNN入门讲解-为什么要有最后一层全连接
哈哈哈,又到了讲段子的时间 准备好了吗? 今天要说的是CNN最后一层了,CNN入门就要讲完啦..... 先来一段官方的语言介绍全连接层(Fully Connected Layer) 全连接层常简称为 ...
- phpexcel 导出xsl乱码
在header前面加上 ob_end_clean(); ob_end_clean();//清除缓冲区,避免乱码 header('Content-Type: application/vnd.ms-exc ...
- android studio: 快捷键生成getter/setter方法时自动加m的问题
平时使用Android Studio 在写实体类的时候,习惯给实体类的成员变量前面加上一个"m" 修饰符表示这是一个成员变量,这也是搞java的一种约定俗成的写法,本来这是没有问题 ...
- Spring-AOP @AspectJ切点函数之@annotation()
@annotation()概述@annotation表示标注了某个注解的所有方法. 下面通过一个实例说明@annotation()的用法. AnnotationTestAspect定义了一个后置切面增 ...
- Centos7 卸载 Nginx 并重新安装 Nginx
1) 卸载nginx [root@locahost /]# yum remove nginx 2) 查看nginx是否还存在 [root@localhost /]# which nginx 3)重新 ...