栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

cuda编程笔记

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

cuda编程笔记

基本操作

一个Grid中含有多个Block,一个Block中含有多个thread

gridDim.x表示网格的块数量
blockIdx.x表示当前块的索引
blockDim.x表示一个块中的线程数量
threadIdx.x表示当前块中线程的索引
<<>>
启动核函数时,核函数代码由每个已配置的线程块中的每个线程执行;

#include 

// cuda函数专用标志符,且不能有返回值
__global__ void gpu(int* a, int N) {
	// 计算当前的线程标志(线程会从0开到总的可用线程数)
	int i = blockIdx.x * blockDim.x + threadIdx.x;
	// 如果还没开够N个线程,就继续开线程运算
	if (i < N) {
		a[i]=i*2;
	}
}

void check(int* a, int N) {
	for (int i = 0; i < N; i++) {
		if (a[i] != i * 2) {
			printf("errorn");
			return;
		}
	}
	printf("okn");
}


int main() {
	// 数组的长度
	const int N = 100;
	// 需要的内存空间
	size_t size = N * sizeof(int);
	int* a;
	// 分配内存空间,cpu和gpu都可以使用
	cudaMallocManaged(&a, size);
	
	// 每个block都有256个线程
	size_t threads = 256;
	// 计算需要多少个block,向上取整
	size_t blocks = (N + threads - 1) / threads;
	// 使用cuda计算
	gpu<<>>(a, N);
	// 等待同步
	cudaDeviceSynchronize();
	// 检查结果是否正确
	check(a, N);
	// 释放内存
	cudaFree(a);
	return 1;
}
跨步循环

当数据量大于总的分配线程数时,需要将数据切分成块来运行,也就是跨步循环运行;

#include 

// cuda函数专用标志符,且不能有返回值
__global__ void gpu(int* a, int N) {
	// 记录当前线程标记(线程会从0开到总的可用线程数)
	int threadi = blockIdx.x * blockDim.x + threadIdx.x;
	// 计算总的可用线程数
	int stride = gridDim.x * blockDim.x;
	// 跨步循环,一个线程跨步处理多个数据
	for (size_t i = threadi; i < N; i += stride) {
		a[i] = i * 2;
	}
}

void check(int* a, int N) {
	for (int i = 0; i < N; i++) {
		if (a[i] != i * 2) {
			printf("errorn");
			return;
		}
	}
	printf("okn");
}


int main() {
	// 数组的长度
	const int N = 1000;
	// 需要的内存空间
	size_t size = N * sizeof(int);
	int* a;
	// 分配内存空间,cpu和gpu都可以使用
	cudaMallocManaged(&a, size);
	
	// 每个block都有256个线程
	size_t threads = 256;
	// 只开辟一个block
	size_t blocks = 1;
	// 使用cuda计算
	gpu<<>>(a, N);
	// 等待同步
	cudaDeviceSynchronize();
	// 检查结果是否正确
	check(a, N);
	// 释放内存
	cudaFree(a);
	return 1;
}
矩阵加法、显存分配

用二维矩阵的方式来定义blocks和threads,在cpu上用完数据,如果不提前开辟显存空间,会发生缺页错误,因此在cpu用完数据之后,在gpu使用之前,提前 开辟显存,将数据预先存储到显存中。

#include 
#include 


#define N 64

__global__ void gpu(int *a, int *b, int *c_gpu) {
	// 在一维上表示出线程的位置
	int r = blockDim.x * blockIdx.x + threadIdx.x;
	int c = blockDim.y * blockIdx.y + threadIdx.y;
	if (r < N && c < N) {
		c_gpu[r * N + c] = a[r * N + c] + b[r * N + c];
	}
}

void cpu(int* a, int* b, int* c_cpu) {
	for (int r = 0; r < N; r++) {
		for (int c = 0; c < N; c++) {
			c_cpu[r * N + c] = a[r * N + c] + b[r * N + c];
		}
	}
}

void check(int* c_cpu, int* c_gpu) {
	for (int r = 0; r < N; r++) {
		for (int c = 0; c < N; c++) {
			if (c_cpu[r * N + c] != c_gpu[r * N + c]) {
				printf("error");
				return ;
			}
		}
	}
	printf("ok");
}

int main() {
	int* a, * b, * c_cpu, * c_gpu;
	size_t size = N * N * sizeof(int);
	cudaMallocManaged(&a, size);
	cudaMallocManaged(&b, size);
	cudaMallocManaged(&c_cpu, size);
	cudaMallocManaged(&c_gpu, size);
	
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			a[i * N + j] = 1;
			b[i * N + j] = 2;
			c_cpu[i * N + j] = 0;
			c_gpu[i * N + j] = 0;
		}
	}
	// 获取设备id
	int id;
	cudaGetDevice(&id);
	// 提前在显存上开辟空间
	cudaMemPrefetchAsync(a, size, id);
	cudaMemPrefetchAsync(b, size, id);

	// 定义线程的维度(为了简洁)
	dim3 threads(16, 16, 1);
	// 计算需要开多少个blocks
	dim3 blocks((N + threads.x - 1) / threads.x, (N + threads.x - 1) / threads.x, 1);
	cpu(a, b, c_cpu);
	gpu << > > (a, b, c_gpu);
	cudaDeviceSynchronize();
	check(c_cpu, c_gpu);

	cudaFree(a);
	cudaFree(b);
	cudaFree(c_cpu);
	cudaFree(c_gpu);

	return 1;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/588662.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号