这是一个使用 CUDA 进行编程的实际例子,对比 CPU 和 GPU 在执行矩阵乘法时的性能差异。
运行效果
(base) root@gpu-1095cf160ec353b4e35a9-1-zqa76jnvthlx:~/data/CUDA/first# ./gpu_matrix_mult
GPU 执行时间: 0.000475046 秒
(base) root@gpu-1095cf160ec353b4e35a9-1-zqa76jnvthlx:~/data/CUDA/first# ./cpu_matrix_mult
CPU 执行时间: 14.3784 秒
程序实例
示例:矩阵乘法
矩阵乘法是一个非常适合用 GPU 加速的计算密集型任务。我们将实现一个简单的矩阵乘法,分别在 CPU 和 GPU 上运行,并比较它们的执行时间。
1. CPU 实现 (C++)
#include <iostream>
#include <vector>
#include <chrono>
// CPU 矩阵乘法
std::vector<float> cpuMatrixMult(const std::vector<float>& a, const std::vector<float>& b, int n) {
std::vector<float> c(n * n, 0.0f);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
c[i * n + j] += a[i * n + k] * b[k * n + j];
}
}
}
return c;
}
int main() {
int n = 1024; // 矩阵大小
std::vector<float> a(n * n, 1.0f);
std::vector<float> b(n * n, 1.0f);
// 计时开始
auto start = std::chrono::high_resolution_clock::now();
std::vector<float> c = cpuMatrixMult(a, b, n);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = end - start;
std::cout << "CPU 执行时间: " << duration.count() << " 秒" << std::endl;
return 0;
}
编译和运行 CPU 代码:
g++ cpu_matrix_mult.cpp -o cpu_matrix_mult
./cpu_matrix_mult
2. GPU 实现 (CUDA)
#include <iostream>
#include <vector>
#include <chrono>
#include <cuda_runtime.h>
// CUDA 核函数
__global__ void gpuMatrixMultKernel(const float* a, const float* b, float* c, int n) {
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row < n && col < n) {
float sum = 0.0f;
for (int k = 0; k < n; ++k) {
sum += a[row * n + k] * b[k * n + col];
}
c[row * n + col] = sum;
}
}
// GPU 矩阵乘法
std::vector<float> gpuMatrixMult(const std::vector<float>& a, const std::vector<float>& b, int n) {
std::vector<float> c(n * n, 0.0f);
float *dev_a, *dev_b, *dev_c;
// 分配 GPU 内存
cudaMalloc((void**)&dev_a, n * n * sizeof(float));
cudaMalloc((void**)&dev_b, n * n * sizeof(float));
cudaMalloc((void**)&dev_c, n * n * sizeof(float));
// 将数据从 CPU 复制到 GPU
cudaMemcpy(dev_a, a.data(), n * n * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b.data(), n * n * sizeof(float), cudaMemcpyHostToDevice);
// 定义线程块和网格大小
int blockSize = 32;
dim3 blockDim(blockSize, blockSize);
dim3 gridDim((n + blockSize - 1) / blockSize, (n + blockSize - 1) / blockSize);
// 计时开始
auto start = std::chrono::high_resolution_clock::now();
// 调用 CUDA 核函数
gpuMatrixMultKernel<<<gridDim, blockDim>>>(dev_a, dev_b, dev_c, n);
// 等待 GPU 完成
cudaDeviceSynchronize();
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = end - start;
// 将结果从 GPU 复制回 CPU
cudaMemcpy(c.data(), dev_c, n * n * sizeof(float), cudaMemcpyDeviceToHost);
// 释放 GPU 内存
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
std::cout << "GPU 执行时间: " << duration.count() << " 秒" << std::endl;
return c;
}
int main() {
int n = 1024; // 矩阵大小
std::vector<float> a(n * n, 1.0f);
std::vector<float> b(n * n, 1.0f);
gpuMatrixMult(a, b, n);
return 0;
}
编译和运行 CUDA 代码:
- 安装 CUDA Toolkit: 确保你已经安装了 CUDA Toolkit,并且设置了正确的环境变量。
编译:
nvcc gpu_matrix_mult.cu -o gpu_matrix_mult
运行:
./gpu_matrix_mult
3. 性能对比分析
通常情况下,你会发现 GPU 的执行时间远小于 CPU 的执行时间,尤其是在矩阵大小 n
较大时。这是因为 GPU 具有大量的并行处理单元,可以同时处理矩阵中的多个元素。
影响性能的因素:
- 矩阵大小: 矩阵越大,GPU 的优势越明显。
- GPU 架构: 不同的 GPU 架构具有不同的性能。
- 线程块大小: 合适的线程块大小可以提高 GPU 的利用率。
- 内存传输: CPU 和 GPU 之间的数据传输会影响整体性能。
总结
这个例子展示了如何使用 CUDA 加速矩阵乘法。通过将计算任务转移到 GPU 上,可以显著提高程序的性能。请注意,实际的加速效果取决于你的硬件和具体的实现方式。 5
希望这个例子能帮助你入门 CUDA 编程!