CUDA11-VS2015安装-工具链测试-Helloworld程序

文章目录

1.下载工具链

下载cuda_11.0.2_451.48_win10,如下图所示:

2.安装

按默认指引安装。

3.新建cuda运行时控制台程序

4.默认代码分析

cpp 复制代码
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);

__global__ void addKernel(int *c, const int *a, const int *b)
{
    int i = threadIdx.x;
    c[i] = a[i] + b[i];
}

int main()
{
    const int arraySize = 5;
    const int a[arraySize] = { 1, 2, 3, 4, 5 };
    const int b[arraySize] = { 10, 20, 30, 40, 50 };
    int c[arraySize] = { 0 };

    // Add vectors in parallel.
    cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "addWithCuda failed!");
        return 1;
    }

    printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",
        c[0], c[1], c[2], c[3], c[4]);

    // cudaDeviceReset must be called before exiting in order for profiling and
    // tracing tools such as Nsight and Visual Profiler to show complete traces.
    cudaStatus = cudaDeviceReset();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaDeviceReset failed!");
        return 1;
    }

    return 0;
}

// Helper function for using CUDA to add vectors in parallel.
cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)
{
    int *dev_a = 0;
    int *dev_b = 0;
    int *dev_c = 0;
    cudaError_t cudaStatus;

    // Choose which GPU to run on, change this on a multi-GPU system.
    cudaStatus = cudaSetDevice(0);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
        goto Error;
    }

    // Allocate GPU buffers for three vectors (two input, one output)    .
    cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    // Copy input vectors from host memory to GPU buffers.
    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    // Launch a kernel on the GPU with one thread for each element.
    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);

    // Check for any errors launching the kernel
    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
        goto Error;
    }
    
    // cudaDeviceSynchronize waits for the kernel to finish, and returns
    // any errors encountered during the launch.
    cudaStatus = cudaDeviceSynchronize();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
        goto Error;
    }

    // Copy output vector from GPU buffer to host memory.
    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

Error:
    cudaFree(dev_c);
    cudaFree(dev_a);
    cudaFree(dev_b);
    
    return cudaStatus;
}

这是一个标准的CUDA向量加法示例代码。我来详细分析其结构和关键点:

4.1.代码整体功能

实现两个整型向量的并行加法:c[i] = a[i] + b[i]

4.2.核心组件分析

a. Kernel函数(第8-11行)

cuda 复制代码
__global__ void addKernel(int *c, const int *a, const int *b)
{
    int i = threadIdx.x;  // 获取线程在block中的索引
    c[i] = a[i] + b[i];
}
  • __global__:表示在GPU上执行,从CPU调用
  • 使用threadIdx.x作为数组索引,限制:只能处理单个block内的线程数(通常≤1024)

b. 主函数流程

  • 定义输入数组a、b和输出数组c(大小5)
  • 调用addWithCuda执行GPU计算
  • 打印结果
  • 重置设备

c. 辅助函数 addWithCuda (第51-121行)

主要步骤:
  1. 设备选择cudaSetDevice(0)
  2. 内存分配cudaMalloc分配GPU显存
  3. 数据传输cudaMemcpy将数据从主机复制到设备
  4. 内核启动addKernel<<<1, size>>>
    • 1个block
    • size个线程(这里是5)
  5. 同步等待cudaDeviceSynchronize()
  6. 结果回传cudaMemcpy将结果从设备复制回主机
  7. 资源释放cudaFree

4.4.关键问题与改进建议

⚠️ 主要缺陷

cuda 复制代码
int i = threadIdx.x;  // 仅适用于小数据量

问题 :当arraySize > 1024时会失败(单个block线程数限制)

✅ 改进版本

cuda 复制代码
__global__ void addKernel(int *c, const int *a, const int *b, int size)
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < size) {
        c[i] = a[i] + b[i];
    }
}

// 调用方式
int blockSize = 256;
int gridSize = (size + blockSize - 1) / blockSize;
addKernel<<<gridSize, blockSize>>>(dev_c, dev_a, dev_b, size);

4.5.错误处理机制

  • 使用goto Error统一错误处理
  • 每个CUDA API调用都检查返回值
  • 内核启动后检查cudaGetLastError()
  • 使用cudaDeviceSynchronize()捕获执行错误

4.6.性能观察点

  1. 数据传输开销:小数据量(5个整数)时,GPU并行优势不明显
  2. 未使用流:所有操作在默认流中顺序执行
  3. 内存访问模式:合并访问良好(连续线程访问连续地址)

4.7.代码规范

  • 使用cudaError_t类型检查错误
  • 资源清理使用goto集中处理
  • 包含必要的头文件和注释

这个代码是学习CUDA编程的良好起点,完整展示了GPU编程的典型流程:分配内存 → 传输数据 → 启动内核 → 同步 → 回传结果 → 释放资源。

相关推荐
ShineWinsu6 小时前
对于C++:C++11中lambda、function、bind的解析
c++·面试·笔试·开发·lambda·bind·function
码匠许师傅6 小时前
【C++ 面试真题】聊聊 C++ 的拷贝构造与拷贝赋值
java·c++·面试
旖旎夜光7 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
汉字萌萌哒7 小时前
2024CSP-J入门级C++真题详解
开发语言·c++
hy.z_7778 小时前
【C++】13. 继承
c++
汉字萌萌哒8 小时前
2019CCF-CSP入门级C++试题解析
java·开发语言·c++
2401_890603409 小时前
C++ 继承
c++
果果燕10 小时前
C++ 学习笔记(二):类与对象—— 构造函数与析构函数
开发语言·c++
老洋葱Mr_Onion10 小时前
【C++】信息学奥赛CSP通关之路——CSP-J/S第一轮原创全真模拟试卷集(2026)卷四全卷解析
开发语言·c++
布莱克60510 小时前
理解 C/C++ 中的 void* 指针
c语言·c++