CUDA C Programming Guide 在线教程学习笔记 Part 3

? 表面内存使用

● 创建 cuda 数组时使用标志 cudaArraySurfaceLoadStore 来创建表面内存,可以用表面对象(surface object)或表面引用(surface reference)来对其进行读写。

● 使用 Surface Object API

■ 涉及的结构定义、接口函数。

1 // vector_types.h
2 struct __device_builtin__ __align__(4) uchar4
3 {
4     unsigned char x, y, z, w;
5 };
6
7 // surface_types.h
8 typedef __device_builtin__ unsigned long long cudaSurfaceObject_t;

■ 完整的测试代码,使用表面内存进行简单的读写。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <malloc.h>
 4 #include <cuda_runtime_api.h>
 5 #include "device_launch_parameters.h"
 6
 7 #define CEIL(x,y) (((x) + (y) - 1) / (y) + 1)
 8
 9 __global__ void myKernel(cudaSurfaceObject_t inputSurfObj, cudaSurfaceObject_t outputSurfObj, int width, int height)
10 {
11     unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
12     unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y;
13     if (idx < width && idy < height)
14     {
15         uchar4 data;
16         // 简单的表面内存读写,使用了字节地址,而不是简单的线程编号
17         surf2Dread(&data, inputSurfObj, sizeof(float) * idx, idy);
18         surf2Dwrite(data, outputSurfObj, sizeof(float) * idx, idy);
19     }
20     cudaBindSurfaceToArray();
21 }
22
23 int main()
24 {
25     // 基本数据
26     int i;
27     float *h_data, *d_data;
28     int width = 32;
29     int height = 32;
30
31     int size = sizeof(float)*width*height;
32     h_data = (float *)malloc(size);
33     cudaMalloc((void **)&d_data, size);
34
35     for (i = 0; i < width*height; i++)
36         h_data[i] = (float)i;
37
38     printf("\n\n");
39     for (i = 0; i < width*height; i++)
40     {
41         printf("%6.1f ", h_data[i]);
42         if ((i + 1) % width == 0)
43             printf("\n");
44     }
45
46     // 申请 cuda 数组
47     cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned);
48     cudaArray* cuInputArray;
49     cudaMallocArray(&cuInputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
50     cudaArray* cuOutputArray;
51     cudaMallocArray(&cuOutputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
52     cudaMemcpyToArray(cuInputArray, 0, 0, h_data, size,cudaMemcpyHostToDevice);
53
54     // 指定表面内存
55     struct cudaResourceDesc resDesc;
56     memset(&resDesc, 0, sizeof(resDesc));
57     resDesc.resType = cudaResourceTypeArray;
58
59     // 创建表面对象
60     resDesc.res.array.array = cuInputArray;
61     cudaSurfaceObject_t inputSurfObj = 0;
62     cudaCreateSurfaceObject(&inputSurfObj, &resDesc);
63     resDesc.res.array.array = cuOutputArray;
64     cudaSurfaceObject_t outputSurfObj = 0;
65     cudaCreateSurfaceObject(&outputSurfObj, &resDesc);
66
67     // 运行核函数
68     dim3 dimBlock(16, 16);
69     dim3 dimGrid(CEIL(width, dimBlock.x), CEIL(height, dimBlock.y));
70     myKernel << <dimGrid, dimBlock >> > (inputSurfObj, outputSurfObj, width, height);
71
72     // 结果回收和检查结果
73     memset(h_data,0,size);// 刷掉原来的 h_data,再用 cuOutputArray 的数据写入
74     cudaMemcpyFromArray(h_data, cuOutputArray, 0, 0, size, cudaMemcpyDeviceToHost);
75
76     printf("\n\n");
77     for (i = 0; i < width*height; i++)
78     {
79         printf("%6.1f ", h_data[i]);
80         if ((i + 1) % width == 0)
81             printf("\n");
82     }
83
84     // 回收工作
85     cudaDestroySurfaceObject(inputSurfObj);
86     cudaDestroySurfaceObject(outputSurfObj);
87     cudaFreeArray(cuInputArray);
88     cudaFreeArray(cuOutputArray);
89
90     getchar();
91     return 0;
92 }

● 使用 Surface Reference API。

■ 表面引用的一些只读属性需要在声明的时候指定,以便编译时提前确定,只能在全局作用域内静态指定,不能作为参数传递给函数。使用 surface 指定纹理引用属性,Datatype 为数据类型,Type 为纹理引用类型,有 7 种,默认 cudaSurfaceType1D。

 1 surface<void, Type> surfRef;
 2
 3 // cuda_texture_types.h
 4 template<class T, int dim = 1>
 5 struct __device_builtin_surface_type__ surface : public surfaceReference
 6 {
 7 #if !defined(__CUDACC_RTC__)
 8     __host__ surface(void)
 9     {
10         channelDesc = cudaCreateChannelDesc<T>();
11     }
12
13     __host__ surface(struct cudaChannelFormatDesc desc)
14     {
15         channelDesc = desc;
16     }
17 #endif /* !__CUDACC_RTC__ */
18 };
19
20 //surface_types.h
21 #define cudaSurfaceType1D              0x01
22 #define cudaSurfaceType2D              0x02
23 #define cudaSurfaceType3D              0x03
24 #define cudaSurfaceTypeCubemap         0x0C
25 #define cudaSurfaceType1DLayered       0xF1
26 #define cudaSurfaceType2DLayered       0xF2
27 #define cudaSurfaceTypeCubemapLayered  0xFC
28
29 // 访问边界模式
30 enum __device_builtin__ cudaSurfaceBoundaryMode
31 {
32     cudaBoundaryModeZero = 0,    // 0 边界模式
33     cudaBoundaryModeClamp = 1,   // 挤压模式
34     cudaBoundaryModeTrap = 2     // 陷阱模式
35 };
36
37 // ?表面格式模式
38 enum __device_builtin__  cudaSurfaceFormatMode
39 {
40     cudaFormatModeForced = 0,   // 强制模式
41     cudaFormatModeAuto = 1      // 自动模式
42 };
43
44 // 表面引用的通道描述
45 struct __device_builtin__ surfaceReference
46 {
47     struct cudaChannelFormatDesc channelDesc;
48 };
49
50 // cuda_runtime_api.h
51 extern __host__ cudaError_t CUDARTAPI cudaBindSurfaceToArray(const struct surfaceReference *surfref, cudaArray_const_t array, const struct cudaChannelFormatDesc *desc);

■ 表面引用使用字节地址来定位访问(而不是像纹理那样使用 fetch 函数),如以上代码中 surf1Dread(surfRef, sizeof(float) * idx) 或是 surf1Dread(surfRef, sizeof(float) * idx) 。

■ 表面引用必须用函数 cudaBindSurfaceToArray() 绑定到 cuda 数组上才能使用,要求表面引用的维度、数据类型与该数组匹配,否则操作时未定义的,使用完后不需要特殊函数来解除绑定。

■ 将表面引用绑定到 cuda 数组上的范例代码。

 1 // 准备工作
 2 surface<void, Type>surfRef;
 3
 4 ...
 5
 6 int width, height;
 7 size_t pitch;
 8 float *d_data;
 9 cudaMallocPitch((void **)&d_data, &pitch, sizeof(float)*width, height);
10
11 // 第一种方法,低层 API
12 surfaceReference* surfRefPtr;
13 cudaGetSurfaceReference(&surfRefPtr, "surfRef");
14 cudaChannelFormatDesc channelDesc;
15 cudaGetChannelDesc(&channelDesc, cuArray);
16 cudaBindSurfaceToArray(surfRef, cuArray, &channelDesc);
17
18 // 第二种方法,高层 API
19 cudaBindSurfaceToArray(surfRef, cuArray);

■ 完整的应用样例代码。与前面表面对象代码的功能相同。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <malloc.h>
 4 #include <cuda_runtime_api.h>
 5 #include "device_launch_parameters.h"
 6
 7 #define CEIL(x,y) (((x) + (y) - 1) / (y) + 1)
 8
 9 // 声明表面引用
10 surface<void, 2> inputSurfRef;
11 surface<void, 2> outputSurfRef;
12
13 __global__ void myKernel(int width, int height)
14 {
15     unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
16     unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y;
17     if (idx < width && idy < height)
18     {
19         uchar4 data;
20         // 简单的表面内存读写,使用了字节地址,而不是简单的线程编号
21         surf2Dread(&data, inputSurfRef, sizeof(float) * idx, idy);
22         surf2Dwrite(data, outputSurfRef, sizeof(float) * idx, idy);
23     }
24 }
25
26 int main()
27 {
28     // 基本数据
29     int i;
30     float *h_data, *d_data;
31     int width = 32;
32     int height = 32;
33
34     int size = sizeof(float)*width*height;
35     h_data = (float *)malloc(size);
36     cudaMalloc((void **)&d_data, size);
37
38     for (i = 0; i < width*height; i++)
39         h_data[i] = (float)i;
40
41     printf("\n\n");
42     for (i = 0; i < width*height; i++)
43     {
44         printf("%6.1f ", h_data[i]);
45         if ((i + 1) % width == 0)
46             printf("\n");
47     }
48
49     // 申请 cuda 数组
50     cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned);
51     cudaArray* cuInputArray;
52     cudaMallocArray(&cuInputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
53     cudaArray* cuOutputArray;
54     cudaMallocArray(&cuOutputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
55     cudaMemcpyToArray(cuInputArray, 0, 0, h_data, size,cudaMemcpyHostToDevice);
56
57     // 绑定表面引用,注意与表面对象的使用不一样
58     cudaBindSurfaceToArray(inputSurfRef, cuInputArray);
59     cudaBindSurfaceToArray(outputSurfRef, cuOutputArray);
60
61     // 运行核函数
62     dim3 dimBlock(16, 16);
63     dim3 dimGrid(CEIL(width, dimBlock.x), CEIL(height, dimBlock.y));
64     myKernel << <dimGrid, dimBlock >> > (width, height);
65
66     // 结果回收和检查结果
67     memset(h_data,0,size);// 刷掉原来的 h_data,再用 cuOutputArray 的数据写入
68     cudaMemcpyFromArray(h_data, cuOutputArray, 0, 0, size, cudaMemcpyDeviceToHost);
69
70     printf("\n\n");
71     for (i = 0; i < width*height; i++)
72     {
73         printf("%6.1f ", h_data[i]);
74         if ((i + 1) % width == 0)
75             printf("\n");
76     }
77
78     // 回收工作
79     cudaFreeArray(cuInputArray);
80     cudaFreeArray(cuOutputArray);
81
82     getchar();
83     return 0;
84 }

? 立方体表面 Cubemap Surface 。 (想象成一个正方体的外表面)

● 一种特殊的二维分层表面。函数 surfCubemapread() 和函数 surfCubemapwrite() 来对其进行读写,使用一个整数下标和两个浮点数有序组来定义层号和表面坐标。

? 分层立方体表面 Cubemap Layered Surfaces 。(想象成一个多层的正方体的各外表面)

● 一种特殊的二维分层表面。函数 surfCubemapread() 和函数 surfCubemapwrite() 来对齐进行读写。使用一个整数下标和两个浮点数有序组来定义层号和表面坐标。

● 分层立方体贴图纹理只能使用函数 cudaMAlloc3DArray() 加上 cudaArrayLayered 和 cudaArrayCubemap 标志来声明,使用函数 texCubemapLayered() 来进行访问滤波只在同一层内部进行,不会跨层执行。

? cuda 数组。

● cuda 优化的数组类型,可以有一维或二维或三维,每个元素可以有 1 个或 2 个或 4 个分量,各分量可以是 1 B 或 2 B 或 4 B 尺寸的有符号或无符号整数,或 2 B 或 4 B 尺寸的浮点数。cuda 数组只能用纹理访问函数来访问,或表面函数来进行读写。

● 纹理内存和表面内存都是可缓存的,且不能保证缓存和内存的一致性。同一个核函数中,用纹理访问或表面访问来读取“已经全局写入或表面写入的内存”是未定义的。

时间: 2024-08-26 01:19:18

CUDA C Programming Guide 在线教程学习笔记 Part 3的相关文章

CUDA C Programming Guide 在线教程学习笔记 Part 2

? 纹理内存使用 ● 纹理内存使用有两套 API,称为 Object API 和 Reference API .纹理对象(texture object)在运行时被 Object API 创建,同时指定了纹理单元.纹理引用(Tezture Reference)在编译时被 Reference API 创建,但是在运行时才指定纹理单元,并将纹理引用绑定到纹理单元上面去. ● 不同的纹理引用可能绑定到相同或内存上有重叠的的纹理单元上,纹理单元可能是 CUDA 线性内存或CUDA array 的任意部分.

CUDA C Programming Guide 在线教程学习笔记 Part 5

附录 A,CUDA计算设备 附录 B,C语言扩展 ? 函数的标识符 ● __device__,__global__ 和 __host__ ● 宏 __CUDA_ARCH__ 可用于区分代码的运行位置. 1 __host__ __device__ void fun() 2 { 3 # if __CUDA_ARCH__ >=600 4 // 代码运行于计算能力 6.x 设备 5 #elif __CUDA_ARCH__ >= 500 6 // 代码运行于计算能力 5.x 设备 7 #elif __C

CUDA C Programming Guide 在线教程学习笔记 Part 6

? 纹理内存读取函数 1 /****************************************************************/ 2 3 // Texture Object API 4 5 /****************************************************************/ 6 7 template<class T> 8 T tex1Dfetch(cudaTextureObject_t texObj, int x);

CUDA C Best Practices Guide 在线教程学习笔记 Part 1

0. APOD过程 ● 评估.分析代码运行时间的组成,对瓶颈进行并行化设计.了解需求和约束条件,确定应用程序的加速性能改善的上限. ● 并行化.根据原来的代码,采用一些手段进行并行化,例如使用现有库,或加入一些预处理指令等.同时需要代码重构来暴露它们固有的并行性. ● 优化.并行化完成后,需要通过优化来提高性能.优化可以应用于各个级别,从数据传输到计算到浮点操作序列的微调.分析工具对这一过程非常有用,可以建议开发人员优化工作的下一个策略. ● 部署.将结果与原始期望进行比较.回想一下,初始评估步

廖雪峰Git教程学习笔记

廖雪峰git简单教程学习笔记 教程地址:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b0001.可以这样设计目录,在d:\reposisoty\ 在这个目录下面有很多的仓库.mkdir learngitcd learngit>>git init          #这样就把learngit 初始化成了一个仓库>>git status        #说明当前仓库的状态并

[简明python教程]学习笔记之编写简单备份脚本

[[email protected] 0503]# cat backup_ver3.py #!/usr/bin/python #filename:backup_ver3.py import os import time #source source=['/root/a.sh','/root/b.sh','/root/c.sh'] #source='/root/c.sh' #backup dir target_dir='/tmp/' today=target_dir+time.strftime('

[简明python教程]学习笔记2014-05-05

今天学习了python的输入输出.异常处理和python标准库 1.文件 通过创建一个file类的对象去处理文件,方法有read.readline.write.close等 [[email protected] 0505]# cat using_file.py #!/usr/bin/python #filename:using_file.py poem='''Programing is fun when the work is done use Python! ''' f=file('poem.

Webpack新手入门教程(学习笔记)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 30.0px Helvetica; color: #000000 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px "PingFang TC Semibold"; color: #000000 } p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0

SQL语句教程学习笔记之一

转自http://www.1keydata.com/cn/sql/ 无论您是一位 SQL 的新手,或是一位只是需要对 SQL 复习一下的资料仓储业界老将, 您就来对地方了.这个 SQL 教材网站列出常用的 SQL 指令.包含以下几个部分: SQL 指令: SQL 如何被用来储存.读取.以及处理数据库之中的资料. 表格处理: SQL 如何被用来处理数据库中的表格. SQL语法: 这一页列出所有在这个教材中被提到的 SQL 语法. 对于每一个指令,我们将会先列出及解释这个指令的语法,然后我们会用一个