C++ GPU编程(英伟达CUDA)

安装编译环境
https://developer.download.nvidia.com/compute/cuda/12.5.0/local_installers/cuda_12.5.0_555.85_windows.exe

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
#set(CMAKE_CUDA_ARCHITECTURES 52;70;75;86)
set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)

project(hellocuda LANGUAGES CXX CUDA)

add_executable(main main.cu hello.cu)

target_include_directories(main PUBLIC ../../include)
target_compile_options(main PUBLIC $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_options(main PUBLIC $<$<COMPILE_LANGUAGE:CUDA>:--expt-relaxed-constexpr>)
# --use_fast_math   sinf 替换成 __sinf
# --ftz=true 会把极小数(denormal)退化为0
# --prec-div=false 降低除法的精度换取速度。
# --prec-sqrt=false 降低开方的精度换取速度。
# --fmad 因为非常重要,所以默认就是开启的,会自动把 a * b + c 优化成乘加(FMA)指令。
# 开启 --use_fast_math 后会自动开启上述所有

 CudaAllocator.h

template <class T>
struct CudaAllocator {
    using value_type = T;

    T* allocate(size_t size) {
        T* ptr = nullptr;
        checkCudaErrors(cudaMallocManaged(&ptr, size * sizeof(T)));
        return ptr;
    }

    void deallocate(T* ptr, size_t size = 0) {
        checkCudaErrors(cudaFree(ptr));
    }

    template <class ...Args>
    void construct(T* p, Args &&...args) {
        if constexpr (!(sizeof...(Args) == 0 && std::is_pod_v<T>))
            ::new((void*)p) T(std::forward<Args>(args)...);
    }
};

 hello.cu

#include <cstdio>
#include <cuda_runtime.h>

__device__ void say_hello3() {  // 定义
    printf("Hello, world!\n");
}

 main.cu

#include <cstdio>
#include <cuda_runtime.h>
#include "helper_cuda.h"
#include <vector>
#include "CudaAllocator.h"
#include <thrust/universal_vector.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/generate.h>
#include <thrust/for_each.h>

__device__ void say_hello3();  // 声明

__device__ __inline__ void say_hello() {
    printf("Hello, world, world from GPU!\n");
}

__host__ void say_hello_host() {
    printf("Hello, world from CPU!\n");
}

__host__ __device__ void say_hello2() {
#ifdef __CUDA_ARCH__
    printf("Hello, world from GPU architecture %d!\n", __CUDA_ARCH__);
#else
    printf("Hello, world from CPU!\n");
#endif
}

__global__ void another() {
    int localVal = 1;
    printf("another: Thread %d of %d\n", threadIdx.x, blockDim.x);
}

__global__ void kernel() {
    unsigned int tid = blockDim.x * blockIdx.x + threadIdx.x;
    unsigned int tnum = blockDim.x * gridDim.x;
    printf("Flattened Thread %d of %d\n", tid, tnum);
    say_hello2();
    say_hello3();
    another << <1, tnum >> > ();  // 核函数调用核函数
    printf("kernel: called another with %d threads\n", tnum);
}

__global__ void kernel2() {
    printf("Block (%d,%d,%d) of (%d,%d,%d), Thread (%d,%d,%d) of (%d,%d,%d)\n",
        blockIdx.x, blockIdx.y, blockIdx.z,
        gridDim.x, gridDim.y, gridDim.z,
        threadIdx.x, threadIdx.y, threadIdx.z,
        blockDim.x, blockDim.y, blockDim.z);
}

// 默认host
constexpr const char* cuthead(const char* p) {
    return p + 1;
}

// 内存访问
__global__ void kernel_memory(int* pret) {
    *pret = 42;
}

// 数组并行处理
__global__ void kernel_array(int* arr, int n) {
    for (int i = blockDim.x * blockIdx.x + threadIdx.x;
        i < n; i += blockDim.x * gridDim.x) {
        arr[i] = i;
    }
}

// 并行处理模板
template <class Func>
__global__ void parallel_for(int n, Func func) {
    for (int i = blockDim.x * blockIdx.x + threadIdx.x;
        i < n; i += blockDim.x * gridDim.x) {
        func(i);
    }
}

// 自定义加减乘除
__device__ __inline__ int float_atomic_add(float* dst, float src) {
    int old = __float_as_int(*dst), expect;
    do {
        expect = old;
        old = atomicCAS((int*)dst, expect,
            __float_as_int(__int_as_float(expect) + src));
    } while (expect != old);
    return old;
}


// map
template <int blockSize, class T>
__global__ void parallel_sum_kernel(T* sum, T const* arr, int n) {
    __shared__ volatile int local_sum[blockSize];
    int j = threadIdx.x;
    int i = blockIdx.x;
    T temp_sum = 0;
    for (int t = i * blockSize + j; t < n; t += blockSize * gridDim.x) {
        temp_sum += arr[t];
    }
    local_sum[j] = temp_sum;
    __syncthreads();
    if constexpr (blockSize >= 1024) {
        if (j < 512)
            local_sum[j] += local_sum[j + 512];
        __syncthreads();
    }
    if constexpr (blockSize >= 512) {
        if (j < 256)
            local_sum[j] += local_sum[j + 256];
        __syncthreads();
    }
    if constexpr (blockSize >= 256) {
        if (j < 128)
            local_sum[j] += local_sum[j + 128];
        __syncthreads();
    }
    if constexpr (blockSize >= 128) {
        if (j < 64)
            local_sum[j] += local_sum[j + 64];
        __syncthreads();
    }
    if (j < 32) {
        if constexpr (blockSize >= 64)
            local_sum[j] += local_sum[j + 32];
        if constexpr (blockSize >= 32)
            local_sum[j] += local_sum[j + 16];
        if constexpr (blockSize >= 16)
            local_sum[j] += local_sum[j + 8];
        if constexpr (blockSize >= 8)
            local_sum[j] += local_sum[j + 4];
        if constexpr (blockSize >= 4)
            local_sum[j] += local_sum[j + 2];
        if (j == 0) {
            sum[i] = local_sum[0] + local_sum[1];
        }
    }
}

// reduce
template <int reduceScale = 4096, int blockSize = 256, int cutoffSize = reduceScale * 2, class T>
int parallel_sum(T const* arr, int n) {
    if (n > cutoffSize) {
        std::vector<int, CudaAllocator<int>> sum(n / reduceScale);
        parallel_sum_kernel<blockSize> << <n / reduceScale, blockSize >> > (sum.data(), arr, n);
        return parallel_sum(sum.data(), n / reduceScale);
    }
    else {
        checkCudaErrors(cudaDeviceSynchronize());
        T final_sum = 0;
        for (int i = 0; i < n; i++) {
            final_sum += arr[i];
        }
        return final_sum;
    }
}

// 共享内存
template <int blockSize, class T>
__global__ void parallel_transpose(T* out, T const* in, int nx, int ny) {
    int x = blockIdx.x * blockSize + threadIdx.x;
    int y = blockIdx.y * blockSize + threadIdx.y;
    if (x >= nx || y >= ny) return;
    __shared__ T tmp[blockSize * blockSize];
    int rx = blockIdx.y * blockSize + threadIdx.x;
    int ry = blockIdx.x * blockSize + threadIdx.y;
    tmp[threadIdx.y * blockSize + threadIdx.x] = in[ry * nx + rx];
    __syncthreads();
    out[y * nx + x] = tmp[threadIdx.x * blockSize + threadIdx.y];
}

void testArray() {
    int n = 65535;
    int* arr;
    checkCudaErrors(cudaMallocManaged(&arr, n * sizeof(int)));

    int nthreads = 128;
    int nblocks = (n + nthreads + 1) / nthreads;
    kernel_array << <nblocks, nthreads >> > (arr, n);

    checkCudaErrors(cudaDeviceSynchronize());
    for (int i = 0; i < n; i++) {
        printf("arr[%d]: %d\n", i, arr[i]);
    }

    cudaFree(arr);
}

void testVector() {
    int n = 65536;
    std::vector<int, CudaAllocator<int>> arr(n);

    parallel_for << <32, 128 >> > (n, [arr = arr.data()] __device__(int i) {
        arr[i] = i;
    });

    checkCudaErrors(cudaDeviceSynchronize());
    for (int i = 0; i < n; i++) {
        printf("arr[%d] = %d\n", i, arr[i]);
    }

}

void testMath() {
    int n = 1 << 25;
    std::vector<float, CudaAllocator<float>> gpu(n);
    std::vector<float> cpu(n);

    for (int i = 0; i < n; i++) {
        cpu[i] = sinf(i);
    }

    parallel_for << <n / 512, 128 >> > (n, [gpu = gpu.data()] __device__(int i) {
        gpu[i] = __sinf(i);
    });
    checkCudaErrors(cudaDeviceSynchronize());

    //for (int i = 0; i < n; i++) {
        //printf("diff %d = %f\n", i, gpu[i] - cpu[i]);
    //}
}

void testTrust() {
    int n = 65536;
    thrust::universal_vector<float> x(n);   // CPU或GPU
    thrust::host_vector<float> x_host(n);   // CPU
    thrust::device_vector<float> x_dev = x_host;    // GPU

    thrust::for_each(x_dev.begin(), x_dev.end(), [] __device__(float& x) {
        x += 100.f;
    });
}

void testAtomic() {
    // atomicAdd(dst, src) 
    // atomicSub
    // atomicOr
    // atomicAnd
    // atomicXor
    // atomicMax
    // atomicMin
    // atomicExch   old = *dst; *dst = src
    // atomicCAS    automic::exchange
}

void test_share() {
    int nx = 1 << 14, ny = 1 << 14;
    std::vector<int, CudaAllocator<int>> in(nx * ny);
    std::vector<int, CudaAllocator<int>> out(nx * ny);
    parallel_transpose<32> << <dim3(nx / 32, ny / 32, 1), dim3(32, 32, 1) >> >
        (out.data(), in.data(), nx, ny);
}

// host 可以调用 global;global 可以调用 device;device 可以调用 device
// 实际上 GPU 的板块相当于 CPU 的线程,GPU 的线程相当于 CPU 的SIMD
// 数学函数sqrtf,rsqrtf,cbrtf,rcbrtf,powf,sinf,cosf,sinpif,cospif,sincosf,sincospif,logf,log2f,log10f,expf,exp2f,exp10f,tanf,atanf,asinf,acosf,fmodf,fabsf,fminf,fmaxf
// 低精度,高性能 __sinf,__expf、__logf、__cosf、__powf, __fdividef(x, y) 
// old = atomicAdd(dst, src) 相当于 old = *dst; *dst += src 
int main() {
    // 三重尖括号里的,第一个参数表示板块数量,第二个参数决定着启动 kernel 时所用 GPU 的线程数量
    kernel<<<1, 1>>>(); // CPU调用GPU函数异步执行
    kernel2<<<dim3(2, 1, 1), dim3(2, 2, 2)>>>();
    cudaDeviceSynchronize(); // CPU等待GPU完成
    say_hello_host();

    int* pret;
    checkCudaErrors(cudaMallocManaged(&pret, sizeof(int)));
    kernel_memory << <1, 1 >> > (pret);
    checkCudaErrors(cudaDeviceSynchronize());
    printf("result: %d\n", *pret);
    cudaFree(pret);

    testArray();

    float sin10 = sinf(10.f);

    /// map-reduce
    int n = 1 << 24;
    std::vector<int, CudaAllocator<int>> arr(n);
    int final_sum = parallel_sum(arr.data(), n);
    return 0;
}

参考

cuda-samples/Common/helper_string.h at 5f97d7d0dff880bc6567faa4c5e62e389a6d6999 · NVIDIA/cuda-samples · GitHub

 https://github.com/NVIDIA/cuda-samples/blob/5f97d7d0dff880bc6567faa4c5e62e389a6d6999/Common/helper_cuda.h#L31

https://www.nvidia.cn/docs/IO/51635/NVIDIA_CUDA_Programming_Guide_1.1_chs.pdf

https://developer.download.nvidia.cn/CUDA/training/StreamsAndConcurrencyWebinar.pdf

CUDA Pro Tip: Write Flexible Kernels with Grid-Stride Loops | NVIDIA Technical Blog


创作不易,小小的支持一下吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/732523.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习前10节

1.机器学习的流程 (1)数据获取 &#xff08;2&#xff09;特征工程 &#xff08;3&#xff09;建立模型 &#xff08;4&#xff09;评估与应用 2.特征工程的作用 &#xff08;1&#xff09;数据特征决定了模型的上限 &#xff08;2&#xff09;预处理和特征提取是最核心的 &…

Java中对象的比较

1. 对象的比较 在Java中&#xff0c;基本类型的对象可以直接比较大小&#xff0c;而自定义类型却不能 class Card {public int rank; // 数值public String suit; // 花色public Card(int rank, String suit) {this.rank rank;this.suit suit;}}public class TestPriori…

C语言入门系列:可迁移的数据类型

文章目录 1&#xff0c;精确宽度类型(exact-width integer type)2&#xff0c;最小宽度类型&#xff08;minimum width type&#xff09;3&#xff0c;最快的最小宽度类型&#xff08;fast minimum width type&#xff09;4&#xff0c;可以保存指针的整数类型。5&#xff0c; …

基于深度学习的图像识别技术与应用是如何?

基于深度学习的图像识别技术与应用在当今社会中扮演着越来越重要的角色。以下是对该技术与应用的详细解析&#xff1a; 一、技术原理 深度学习是一种模拟人脑处理和解析数据的方式的技术和方法论。在图像识别领域&#xff0c;深度学习主要通过深度神经网络&#xff08;如卷积…

计算机网络 交换机的VLAN配置

一、理论知识 1.VLAN的定义 ①VLAN虚拟局域网&#xff0c;是一种通过将局域网内的设备逻辑地而不是物理地划分成一个个网段从而实现虚拟工作组的技术。 ②IEEE于1999年颁布了用以标准化VLAN实现方案的802.1Q协议标准草案。 ③VLAN技术允许网络管理者将一个物理的LAN逻辑地划…

【C++】平衡二叉树(AVL树)的实现

目录 一、AVL树的概念二、AVL树的实现1、AVL树的定义2. 平衡二叉树的插入2.1 按照二叉排序树的方式插入并更新平衡因子2.2 AVL树的旋转2.2.1 新节点插入较高左子树的左侧&#xff08;LL平衡旋转&#xff09;2.2.2 新节点插入较高右子树的右侧&#xff08;RR平衡旋转&#xff09…

python库BeeWare,一个如雷贯耳的可以创建原生应用程序的库

目录 BeeWare 包括以下主要组件和工具&#xff1a; 创建BeeWare虚拟环境 配置BeeWare 创建一个新的BeeWare项目&#xff08; Hello World! &#xff09; 尝试 Hello World 样例 BeeWare 是一个开源项目&#xff0c;旨在帮助开发者使用 Python 创建原生应用程序&#xff0c;…

系统架构师考点--数据库系统

大家好。今天我来总结一下数据库系统的相关考点。本考点一般情况下上午场考试占3-5分&#xff0c;下午场案例分析题也会出现。 一、数据库系统 数据&#xff1a;数据库中存储的基本对象&#xff0c;是描述事物的符号记录。数据的种类:文本、图形、图像、音频、视频、学生的档…

【机器学习】大模型驱动下的医疗诊断应用

摘要&#xff1a; 随着科技的不断发展&#xff0c;机器学习在医疗领域的应用日益广泛。特别是在大模型的驱动下&#xff0c;机器学习为医疗诊断带来了革命性的变化。本文详细探讨了机器学习在医疗诊断中的应用&#xff0c;包括疾病预测、图像识别、基因分析等方面&#xff0c;并…

天擎客户端卸载 自我保护异常

问题&#xff1a;客户端卸载失败提示“检测到自我保护状态异常&#xff0c;停止卸载” 下列操作&#xff0c;均在客户端进行&#xff0c;别改成服务端的了 进入天擎客户端主目录&#xff0c;默认路径为 C:\Program Files (x86)\Qianxin\Tianqing 将avsecbase.dll 重命名为 1…

移动端+PC端应用模式的智慧城管综合执法办案平台源码,案件在线办理、当事人信用管理、文书电子送达、沿街店铺分析

城市管理综合执法管理平台实现执法办案、业务全流程在线办理&#xff0c;依托移动端PC端的“两端”应用模式&#xff0c;保障能够通过信息化手段进行日常的执法办案工作&#xff0c;强化执法监督功能。提供了案件在线办理、当事人信用管理、文书电子送达、沿街店铺分析等功能&a…

【数据结构与算法】树的遍历,森林遍历 详解

树的先根遍历、后根遍历对应其二叉树的哪种遍历 树的先根遍历对应其二叉树的先序遍历&#xff08;根-左-右&#xff09;。树的后根遍历对应其二叉树的中序遍历&#xff08;左-根-右&#xff09;。 森林的先根遍历、中根遍历对应其二叉树的哪种遍历? 森林的先根遍历对应其二…

细说MCU输出两路PWM波形及改变占空比的实现方法

目录 一、硬件及工程 二、建立工程 三、代码修改 四、下载运行 五、改变PWM波形占空比 1、定义两个全局变量 2、启动定时器 3、重写TIM3中断回调函数 六、下载并运行 一、硬件及工程 文章依赖的硬件及工程配置参考本文作者的其他文章&#xff1a;细说ARM MCU的串口接…

代码随想录算法训练营第六十七天 | 字符串接龙、有向图的完全可达性、岛屿的周长

字符串接龙 文字讲解&#xff1a;110. 字符串接龙 | 代码随想录 解题思路 本题只需要求出最短路径的长度就可以了&#xff08;想到广搜&#xff09;&#xff0c;不用找出具体路径。 所以这道题要解决两个问题&#xff1a; 图中的线是如何连在一起的起点和终点的最短路径长…

java之url任意跳转漏洞

1 漏洞介绍 URLRedirect url重定向漏洞也称url任意跳转漏洞&#xff0c;网站信任了用户的输入导致恶意攻击&#xff0c;url重定向主要用来钓鱼&#xff0c;比如url跳转中最常见的跳转在登陆口&#xff0c;支付口&#xff0c;也就是一旦登陆将会跳转任意自己构造的网站&#xf…

【Pandas驯化-11】一文搞懂Pandas中的分组函数groupby与qcut、fillna使用

【Pandas驯化-11】一文搞懂Pandas中的分组函数groupby与qcut、fillna使用 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获…

Linux常用命令(16)—awk命令(有相关截图)

写在前面&#xff1a; 最近在学习Linux命令&#xff0c;记录一下学习Linux常用命令的过程&#xff0c;方便以后复习。仅供参考&#xff0c;若有不当的地方&#xff0c;恳请指正。如果对你有帮助&#xff0c;欢迎点赞&#xff0c;关注&#xff0c;收藏&#xff0c;评论&#xf…

蓝桥杯 经典算法题 合并排序数组

题目&#xff1a; 题解&#xff1a; leetcode上也有这道题一模一样。和归并排序的小过程基本一模一样&#xff0c;只不过因为题目要求只能将arr2中元素合并到arr1中&#xff0c;一种可行的方法是按元素从大到小&#xff0c;顺序从每个序列尾部开始操作&#xff0c;第一填的位置…

杀疯了!PerfXCloud-AI大模型夏日狂欢来袭,向基石用户赠送 ∞ 亿Token!

【澎峰科技重磅消息】 在全球范围内大模型正逐渐成为强大的创新驱动力。在这个充满激情的夏日&#xff0c;PerfXCloud为开发者和企业带来了前所未有的福利&#xff1a; 1. 零成本亲密、深度体验大模型&#xff0c;提供大量示范案例。 2. 向基石用户赠送∞亿Token的激励计划。…

终于找到了免费的云服务器

今天朋友推荐了一个免费的云服务器&#xff1a;“阿贝云” 我最喜欢的是它的"免费虚拟主机"“免费云服务器”&#xff0c;省了我好多钱&#xff0c;我的使用感受是用起来经济实惠省心&#xff0c;不要钱的东西谁不喜欢呢&#xff0c;对于普通开发者来说&#xff0c;…