C++与CUDA

内存管理

封装

利用标准库容器实现对GPU的内存管理

#include <iostream>
#include <cuda_runtime.h>
#include <vector>
#include <cstddef>
template<class T>
struct CUDA_Allocator {
using value_type = T; //分配器必须要有的
T *allocate(size_t size) {
T *dataPtr = nullptr;
cudaError_t err = cudaMallocManaged(&dataPtr, size * sizeof(T));
if (err != cudaSuccess) {
return nullptr;
}
return dataPtr;
}
void deallocate(T *ptr, size_t size = 0) {
cudaError_t err = cudaFree(ptr);
}
};
__global__ void kernel(int *arr, int arrLen) {
for (int i = blockDim.x * blockIdx.x + threadIdx.x; i < arrLen; i += blockDim.x * gridDim.x) {
arr[i] = i;
//printf("i=%d\n", i);
}
} int main() {
int size = 65523;
std::vector<int, CUDA_Allocator<int>> arr(size);
kernel<<<13, 28>>>(arr.data(), size);
cudaError_t err = cudaDeviceSynchronize();
if (err != cudaSuccess) {
printf("Error:%s\n", cudaGetErrorName(err));
return 0;
}
for (int i = 0; i < size; ++i) {
printf("arr[%d]=%d\n", i, arr[i]);
}
}

其中allocatedeallocate是必须实现的

这里不用默认的std::allocate,使用自己定义的分配器,使得内存分配在GPU上

vector是会自动初始化的,如果不想自动初始化的化,可以在分配器中自己写构造函数

关于分配器的更多介绍

函数调用

template<class Func>
__global__ void para_for(int n, Func func) {
for (int i = blockDim.x * blockIdx.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {
func(i);
}
}
//定义一个仿函数
struct MyFunctor {
__device__ void operator()(int i) {
printf("number %d\n", i);
}
}; int main() {
int size = 65513;
para_for<<<13,33>>>(size,MyFunctor{});
cudaError_t err = cudaDeviceSynchronize();
if (err != cudaSuccess) {
printf("Error:%s\n", cudaGetErrorName(err));
return 0;
}
}

同样的,lambda也是被支持的,但是要先在cmake中开启

target_compile_options(${PROJECT_NAME} PUBLIC $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)

lambda

lambda写法

  para_for<<<13, 33>>>(size, [] __device__(int i) { printf("number:%d\n", i); });

lambda捕获外部变量

一定要注意深拷贝和浅拷贝

如果这里直接捕获arr的话,是个深拷贝,这样是会出错的,因为拿到的arr是在CPU上的,而数据是在GPU上的,所以这里要浅拷贝指针,拿到指针的值,就是数据在GPU上的地址,这样就可以使用device函数对数据进行操作了

  std::vector<int, CUDA_Allocator<int>> arr(size);
int*arr_ptr=arr.data();
para_for<<<13, 33>>>(size, [=] __device__(int i) { arr_ptr[i] = i; });
cudaError_t err = cudaDeviceSynchronize();
if (err != cudaSuccess) {
printf("Error:%s\n", cudaGetErrorName(err));
return 0;
}
for (int i = 0; i < size; ++i) {
printf("arr[%d]=%d\n", i, arr[i]);
}

同时还可以这样捕获

  para_for<<<13, 33>>>(size, [arr=arr.data()] __device__(int i) { arr[i] = i; });

时间测试


#include <chrono>
#define TICK(x) auto bench_##x = std::chrono::steady_clock::now();
#define TOCK(x) std::cout << #x ": " << std::chrono::duration_cast<std::chrono::duration<double> >(std::chrono::steady_clock::now() - bench_##x).count() << "s" << std::endl; int main(){
int size = 65513; std::vector<float, CUDA_Allocator<float>> arr(size);
std::vector<float> cpu(size); TICK(cpu_sinf)
for (int i = 0; i < size; ++i) {
cpu[i] = sinf(i);
}
TOCK(cpu_sinf) TICK(gpu_sinf)
para_for<<<16, 64>>>(
size, [arr = arr.data()] __device__(int i) { arr[i] = sinf(i); });
cudaError_t err = cudaDeviceSynchronize();
TOCK(gpu_sinf)
if (err != cudaSuccess) {
printf("Error:%s\n", cudaGetErrorName(err));
return 0;
}
}

结果:



可以看到,求正弦GPU是要快于CPU的,这里差距还不明显,一般来说速度是由数量级上的差距的

学习链接

C++编程笔记(GPU并行编程-2)的更多相关文章

  1. 五 浅谈CPU 并行编程和 GPU 并行编程的区别

    前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...

  2. 第五篇:浅谈CPU 并行编程和 GPU 并行编程的区别

    前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...

  3. 三 GPU 并行编程的运算架构

    前言 GPU 是如何实现并行的?它实现的方式较之 CPU 的多线程又有什么分别?本文将做一个较为细致的分析. GPU 并行计算架构 GPU 并行编程的核心在于线程,一个线程就是程序中的一个单一指令流, ...

  4. 第三篇:GPU 并行编程的运算架构

    前言 GPU 是如何实现并行的?它实现的方式较之 CPU 的多线程又有什么分别? 本文将做一个较为细致的分析. GPU 并行计算架构 GPU 并行编程的核心在于线程,一个线程就是程序中的一个单一指令流 ...

  5. 四 GPU 并行编程的存储系统架构

    前言 在用 CUDA 对 GPU 进行并行编程的过程中,除了需要对线程架构要有深刻的认识外,也需要对存储系统架构有深入的了解. 这两个部分是 GPU 编程中最为基础,也是最为重要的部分,需要花时间去理 ...

  6. 第四篇:GPU 并行编程的存储系统架构

    前言 在用 CUDA 对 GPU 进行并行编程的过程中,除了需要对线程架构要有深刻的认识外,也需要对存储系统架构有深入的了解. 这两个部分是 GPU 编程中最为基础,也是最为重要的部分,需要花时间去理 ...

  7. 【并行计算-CUDA开发】GPU并行编程方法

    转载自:http://blog.sina.com.cn/s/blog_a43b3cf2010157ph.html 编写利用GPU加速的并行程序有多种方法,归纳起来有三种: 1.      利用现有的G ...

  8. 大数据学习笔记3 - 并行编程模型MapReduce

    分布式并行编程用于解决大规模数据的高效处理问题.分布式程序运行在大规模计算机集群上,集群中计算机并行执行大规模数据处理任务,从而获得海量计算能力. MapReduce是一种并行编程模型,用于大规模数据 ...

  9. C#并发编程之初识并行编程

    写在前面 之前微信公众号里有一位叫sara的朋友建议我写一下Parallel的相关内容,因为手中商城的重构工作量较大,一时之间无法抽出时间.近日,这套系统已有阶段性成果,所以准备写一下Parallel ...

  10. GPU并行编程小结

    http://peghoty.blog.163.com/blog/static/493464092013016113254852/ http://blog.csdn.net/augusdi/artic ...

随机推荐

  1. 在vm中安装centos7

    步骤: 1.打开VMware Worktation,点击"创建新的虚拟机": 2.一般选择"典型(推荐)",之后下一步. 3.选择"稍后安装操作系统& ...

  2. 第六章:Django 综合篇 - 12:聚合内容 RSS/Atom

    Django提供了一个高层次的聚合内容框架,让我们创建RSS/Atom变得简单,你需要做的只是编写一个简单的Python类. 一.范例 要创建一个feed,只需要编写一个Feed类,然后设置一条指向F ...

  3. Docker方式安装Jenkins并且插件更改国内源

    参考网站:https://www.jenkins.io/zh/doc/book/installing/#在docker中下载并运行jenkins 建议使用的Docker映像是jenkinsci/blu ...

  4. 齐博X1到底是个什么鬼?

    什么是齐博/齐博CMS之X1? 齐博X1是齐博软件基于thinkphp5开发的内容管理系统,拓展性非常强,后台一键升级,后台提供丰富的频道模块云市插件市场.风格市场.钩子市场,所有都是一键在线安装. ...

  5. [Go疑难杂症]为什么nil不等于nil

    现象 在日常开发中,可能一不小心就会掉进 Go 语言的某些陷阱里,而本文要介绍的 nil ≠ nil 问题,便是其中一个,初看起来会让人觉得很诡异,摸不着头脑. 先来看个例子: type Custom ...

  6. RDD(弹性分布式数据集)及常用算子

    RDD(弹性分布式数据集)及常用算子 RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是 Spark 中最基本的数据 处理模型.代码中是一个抽象类,它代表一个 ...

  7. JS 可编辑表格的实现(进阶)

    1.前言 在普通的可编辑表格的基础上,改进可编辑表格.数据来自外部的json(模拟服务端),通过json数据生成可编辑表格.根据实际情况,表格没有新增数据功能.表格的可编辑列,计算的列,每列的数据大小 ...

  8. xss学习笔记(萌新版)

    xss简介 xss攻击者构造恶意信息然后在用户的浏览器上执行,主要分为反射性xss,这种主要是某个页面存在有漏洞的参数,然后填上恶意参数把整个链接发给用户或者管理员,他们点击了带有恶意参数的链接就会执 ...

  9. 论文笔记 - PRISM: A Rich Class of Parameterized Submodular Information Measures for Guided Subset Selection

    Motivation 与 Active Learning 类似,Target Learning 致力于 挑选外卖更"感兴趣"的数据,即人为为更重要的数据添加 bias.例如我们当前 ...

  10. JVM运行时数据区域详解

    参考文章: <Java Se11 虚拟机规范> <深入理解Java虚拟机-JVM高级特性与最佳实践 第3版>- 周志明 本文基于Java Se 11讲解. 根据<Java ...