《GPU高性能编程CUDA实战》第四章 简单的线程块并行
▶ 本章介绍了线程块并行,并给出两个例子:长向量加法和绘制julia集。
● 长向量加法,中规中矩的GPU加法,包含申请内存和显存,赋值,显存传入,计算,显存传出,处理结果,清理内存和显存。用到了 tid += gridDim.x; 使得线程块可以读取多个下标,计算长于线程块数量的向量(例子中向量长度为32768,线程块数量为1024)
#include <stdio.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "D:\Code\CUDA\book\common\book.h" #define N (32 * 1024) __global__ void add(int *a, int *b, int *c)
{
int tid = blockIdx.x;
while (tid < N)
{
c[tid] = a[tid] + b[tid];
tid += gridDim.x;
}
return;
} int main(void)
{
int *a, *b, *c;
int *dev_a, *dev_b, *dev_c; // 申请内存和显存
a = (int*)malloc(N * sizeof(int));
b = (int*)malloc(N * sizeof(int));
c = (int*)malloc(N * sizeof(int));
cudaMalloc((void**)&dev_a, N * sizeof(int));
cudaMalloc((void**)&dev_b, N * sizeof(int));
cudaMalloc((void**)&dev_c, N * sizeof(int)); // 数组填充
for (int i = ; i < N; i++)
{
a[i] = i;
b[i] = * i;
} // 将内存中的a和b拷贝给显存中的dev_a和dev_b
cudaMemcpy(dev_a, a, N * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, N * sizeof(int), cudaMemcpyHostToDevice); // 调用核函数
add <<<, >>>(dev_a, dev_b, dev_c); // 将显存中的dev_c从显存拷贝回内存中的c
cudaMemcpy(c, dev_c, N * sizeof(int), cudaMemcpyDeviceToHost); // 检验结果
bool success = true;
for (int i = ; i<N; i++)
{
if ((a[i] + b[i]) != c[i])
{
printf("Error at i==%d:\n\t%d + %d != %d\n", i, a[i], b[i], c[i]);
success = false;
break;
}
}
if (success)
printf("We did it!\n"); // 释放内存和显存
free(a);
free(b);
free(c);
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c); getchar();
return ;
}
● 绘制Julia集:
#include <stdio.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "D:\Code\CUDA\book\common\book.h"
#include "D:\Code\CUDA\book\common\cpu_bitmap.h" #define DIM 1000 // 输出图形的边长
#define USE_CPU false // true使用CPU,false使用GPU struct DataBlock
{
unsigned char *dev_bitmap;
}; struct cuComplex// 自定义复数类型
{
float r;
float i;
__host__ __device__ cuComplex(float a, float b) : r(a), i(b) {}
__host__ __device__ float magnitude2(void)
{
return r * r + i * i;
}
__host__ __device__ cuComplex operator*(const cuComplex& a)
{
return cuComplex(r*a.r - i*a.i, i*a.r + r*a.i);
}
__host__ __device__ cuComplex operator+(const cuComplex& a)
{
return cuComplex(r + a.r, i + a.i);
}
}; __host__ __device__ int julia(int x, int y)// 判定一个点是否属于julia集
{
const float scale = 1.5;
float jx = scale * (float)(DIM / - x) / (DIM / );
float jy = scale * (float)(DIM / - y) / (DIM / ); cuComplex c(-0.8, 0.056);// 事先规定的偏移值
cuComplex a(jx, jy); int i = ;
for (i = ; i<; i++)
{
a = a * a + c;
if (a.magnitude2() > )
return ;
}
return ;
} void kernelCPU(unsigned char *ptr)// CPU中按循环遍历每个点进行判定
{
for (int y = ; y<DIM; y++)
{
for (int x = ; x<DIM; x++)
{
int offset = x + y * DIM;
int juliaValue = julia(x, y);
ptr[offset * + ] = * juliaValue;
ptr[offset * + ] = ;
ptr[offset * + ] = ;
ptr[offset * + ] = ;
}
}
return;
} __global__ void kernelGPU(unsigned char *ptr)// GPU中每个线程块判定一个点
{
int x = blockIdx.x;
int y = blockIdx.y;
int offset = x + y * gridDim.x; int juliaValue = julia(x, y);
ptr[offset * + ] = ;
ptr[offset * + ] = * juliaValue;
ptr[offset * + ] = ;
ptr[offset * + ] = ;
return;
} int main(void)
{
#if USE_CPU
CPUBitmap bitmap(DIM, DIM);
unsigned char *ptr = bitmap.get_ptr(); kernelCPU(ptr);
#else
DataBlock data;
CPUBitmap bitmap(DIM, DIM, &data);
unsigned char *dev_bitmap;
cudaMalloc((void**)&dev_bitmap, bitmap.image_size());
data.dev_bitmap = dev_bitmap; kernelGPU << < dim3(DIM, DIM), >> > (dev_bitmap); cudaMemcpy(bitmap.get_ptr(), dev_bitmap, bitmap.image_size(), cudaMemcpyDeviceToHost);
cudaFree(dev_bitmap);
#endif bitmap.display_and_exit();
printf("\n\tfinished!");
getchar();
return ;
}
▶ 在定义结构体的时候定义结构的运算 __host__ __device__ cuComplex(float a, float b) : r(a), i(b) {} ,表明初始化结构实例时可以传入两个浮点参数 a 和 b,并将它们分别当做该实例的两个分量。类似的情形在结构dim3中也有体现。
//在vector_types.h中预定义的结构dim3
struct __device_builtin__ dim3
{
unsigned int x, y, z;
#if defined(__cplusplus)
__host__ __device__ dim3(unsigned int vx = , unsigned int vy = , unsigned int vz = ) : x(vx), y(vy), z(vz) {}
__host__ __device__ dim3(uint3 v) : x(v.x), y(v.y), z(v.z) {}
__host__ __device__ operator uint3(void) { uint3 t; t.x = x; t.y = y; t.z = z; return t; }
#endif /* __cplusplus */
}; //然后在CUDA的代码中可以使用
dim3 threads = dim3(, );
dim3 blocks = dim3(n / threads.x, );
《GPU高性能编程CUDA实战》第四章 简单的线程块并行的更多相关文章
- 《GPU高性能编程CUDA实战》第九章 原子性
▶ 本章介绍了原子操作,给出了基于原子操作的直方图计算的例子. ● 章节代码 #include <stdio.h> #include "cuda_runtime.h" ...
- [问题解决]《GPU高性能编程CUDA实战》中第4章Julia实例“显示器驱动已停止响应,并且已恢复”问题的解决方法
以下问题的出现及解决都基于"WIN7+CUDA7.5". 问题描述:当我编译运行<GPU高性能编程CUDA实战>中第4章所给Julia实例代码时,出现了显示器闪动的现象 ...
- 《GPU高性能编程CUDA实战》第五章 线程并行
▶ 本章介绍了线程并行,并给出四个例子.长向量加法.波纹效果.点积和显示位图. ● 长向量加法(线程块并行 + 线程并行) #include <stdio.h> #include &quo ...
- 《GPU高性能编程CUDA实战中文》中第四章的julia实验
在整个过程中出现了各种问题,我先将我调试好的真个项目打包,提供下载. /* * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. ...
- 《GPU高性能编程CUDA实战》第十一章 多GPU系统的CUDA C
▶ 本章介绍了多设备胸膛下的 CUDA 编程,以及一些特殊存储类型对计算速度的影响 ● 显存和零拷贝内存的拷贝与计算对比 #include <stdio.h> #include " ...
- 《GPU高性能编程CUDA实战》第七章 纹理内存
▶ 本章介绍了纹理内存的使用,并给出了热传导的两个个例子.分别使用了一维和二维纹理单元. ● 热传导(使用一维纹理) #include <stdio.h> #include "c ...
- 《GPU高性能编程CUDA实战》第六章 常量内存
▶ 本章介绍了常量内存的使用,并给光线追踪的一个例子.介绍了结构cudaEvent_t及其在计时方面的使用. ● 章节代码,大意是有SPHERES个球分布在原点附近,其球心坐标在每个坐标轴方向上分量绝 ...
- 《GPU高性能编程CUDA实战》第三章 CUDA设备相关
▶ 这章介绍了与CUDA设备相关的参数,并给出了了若干用于查询参数的函数. ● 代码(已合并) #include <stdio.h> #include "cuda_runtime ...
- 《GPU高性能编程CUDA实战》附录四 其他头文件
▶ cpu_bitmap.h #ifndef __CPU_BITMAP_H__ #define __CPU_BITMAP_H__ #include "gl_helper.h" st ...
随机推荐
- Windows消息【一】 消息队列
看了MSDN后,以下是我个人的理解! 消息能够被分为「队列化消息」和「非队列化消息」. 队列化消息是指当程序发生某事件时,由Windows主动捕获并把消息放入系统消息队列中,而程序在运行时会初始化一个 ...
- WPF Demo13通知项属性+数据绑定(代码层)
<Window x:Class="BindingDemo1.MainWindow" xmlns="http://schemas.microsoft.com/winf ...
- VMware中四种网络连接模式的区别
安装好VMwareWorkstations之后,进行虚拟机网络配置时有四种网络连接方式,桥接.仅主机.NAT.LAN区段. 之所以有不同的模式,在我看来是为了满足不同的网络需求,总的来说:桥接.NAT ...
- Hadoop概念学习系列之谈hadoop/spark里分别是如何实现容错性?(四十二)
Hadoop使用数据复制来实现容错性(I/O高) Spark使用RDD数据存储模型来实现容错性. RDD是只读的.分区记录的集合.如果一个RDD的一个分区丢失,RDD含有如何重建这个分区的相关信息. ...
- ActionScript3.0实现动态地图效果
14年的一个项目需求,研究了一下AS脚本.AS2.0是之前面向关系的语言,AS3.0之后开始走上面向对象路线. 现在附上当时的代码,里边包含很多细节和算法,重要的代码也都有注释,如果需要可以仔细看一下 ...
- python "爬虫+有道词典"实现一个简单翻译程序
抓包软件使用的是Fiddler4 新版的查询接口 比较负责,引入了salt和sign http://fanyi.youdao.com/translate?smartresult=dict&sm ...
- R语言学习——根据信息熵建决策树KD3
R语言代码 决策树的构建 rm(list=ls()) setwd("C:/Users/Administrator/Desktop/R语言与数据挖掘作业/实验3-决策树分类") #s ...
- 解决hash冲突的三个方法(转)
https://www.cnblogs.com/wuchaodzxx/p/7396599.html 目录 开放定址法 线性探测再散列 二次探测再散列 伪随机探测再散列 再哈希法 链地址法 建立公共溢出 ...
- Schiff Move Free维骨力这个牌子的保健效果怎么样,是要给中老年人群服用的
Schiff Move Free维骨力这个牌子的保健效果怎么样,是要给中老年人群服用的.? https://www.zhihu.com/question/46399868 服move free还要补钙 ...
- T-SQL 有参数存储过程的创建与执行
use StudentManager go if exists(select * from sysobjects where name='usp_ScoreQuery2') drop procedur ...