Rust CUDA加速插件库sp1-cuda的使用,高性能并行计算与GPU加速开发

Rust CUDA加速插件库sp1-cuda的使用,高性能并行计算与GPU加速开发

SP1

SP1是最快、功能最完整的零知识虚拟机(zkVM),可以证明任意Rust(或任何LLVM编译语言)程序的执行。SP1通过使开发者能够用普通的Rust代码编写ZKP程序,使ZK技术对任何开发者都变得可及。

开始使用

开发者现在可以使用Rust(支持std)编写程序,包括复杂的大型程序如ZK Tendermint轻客户端或使用Reth的类型1 zkEVM,生成证明并验证它们。大多数Rust crate应该都被支持,并且可以被你的程序无缝使用。

要开始使用,请确保你已经安装了Rust。

安全

SP1已经通过了Veridise、Cantina和KALOS的审计,并推荐用于生产环境。

支持的Rust版本(MSRV)

当前支持的最低Rust版本是1.79。

安装

在你的项目目录中运行以下Cargo命令:

cargo add sp1-cuda

或者在Cargo.toml中添加以下行:

sp1-cuda = "5.2.1"

完整示例代码

以下是一个使用sp1-cuda进行GPU加速计算的完整示例:

use sp1_cuda::prelude::*;

fn main() {
    // 初始化CUDA环境
    let env = CudaEnv::new().expect("Failed to initialize CUDA environment");

    // 准备输入数据
    let input: Vec<f32> = (0..1024).map(|x| x as f32).collect();

    // 创建CUDA缓冲区
    let mut buffer = env.create_buffer::<f32>(1024).expect("Failed to create buffer");

    // 将数据复制到GPU
    buffer.copy_from_host(&input).expect("Failed to copy data to GPU");

    // 执行CUDA内核
    let kernel = env.load_kernel("my_kernel", include_str!("my_kernel.cu")).unwrap();
    kernel.launch(&[&buffer], 1024, 1).expect("Failed to launch kernel");

    // 将结果复制回主机
    let mut output = vec![0.0; 1024];
    buffer.copy_to_host(&mut output).expect("Failed to copy data from GPU");

    println!("Result: {:?}", &output[..10]);
}

对应的CUDA内核代码(my_kernel.cu):

extern "C" __global__ void my_kernel(float* data) {
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    if (idx < 1024) {
        data[idx] = data[idx] * data[idx];  // 简单平方计算
    }
}

完整示例demo

以下是一个更复杂的示例,展示如何使用sp1-cuda进行矩阵乘法:

use sp1_cuda::prelude::*;

fn main() {
    // 初始化CUDA环境
    let env = CudaEnv::new().expect("Failed to initialize CUDA environment");

    // 准备矩阵数据 (16x16矩阵)
    let matrix_size = 16;
    let a: Vec<f32> = (0..matrix_size * matrix_size).map(|x| x as f32).collect();
    let b: Vec<f32> = (0..matrix_size * matrix_size).map(|x| (x + 1) as f32).collect();
    let mut c = vec![0.0; matrix_size * matrix_size];

    // 创建CUDA缓冲区
    let buf_a = env.create_buffer::<f32>(a.len()).expect("Failed to create buffer A");
    let buf_b = env.create_buffer::<f32>(b.len()).expect("Failed to create buffer B");
    let buf_c = env.create_buffer::<f32>(c.len()).expect("Failed to create buffer C");

    // 将数据复制到GPU
    buf_a.copy_from_host(&a).expect("Failed to copy matrix A to GPU");
    buf_b.copy_from_host(&b).expect("Failed to copy matrix B to GPU");

    // 加载并执行矩阵乘法内核
    let kernel = env.load_kernel(
        "matrix_mul", 
        include_str!("matrix_mul.cu")
    ).unwrap();
    
    // 启动内核,16x16线程块
    kernel.launch(&[&buf_a, &buf_b, &buf_c], matrix_size, matrix_size)
        .expect("Failed to launch matrix multiplication kernel");

    // 将结果复制回主机
    buf_c.copy_to_host(&mut c).expect("Failed to copy result from GPU");

    println!("Matrix multiplication result (first row): {:?}", &c[..matrix_size]);
}

对应的CUDA内核代码(matrix_mul.cu):

extern "C" __global__ void matrix_mul(float* a, float* b, float* c) {
    int row = blockIdx.y * blockDim.y + threadIdx.y;
    int col = blockIdx.x * blockDim.x + threadIdx.x;
    int size = 16;
    
    if (row < size && col < size) {
        float sum = 0.0f;
        for (int k = 0; k < size; k++) {
            sum += a[row * size + k] * b[k * size + col];
        }
        c[row * size + col] = sum;
    }
}

这个示例演示了如何使用sp1-cuda执行更复杂的GPU计算任务,如矩阵乘法。通过合理的线程块划分,可以高效地利用GPU的并行计算能力。


1 回复

Rust CUDA加速插件库sp1-cuda的使用指南

概述

sp1-cuda是一个Rust库,用于在Rust程序中实现高性能并行计算和GPU加速开发。它提供了与CUDA交互的接口,使开发者能够利用NVIDIA GPU的强大计算能力。

主要特性

  • 提供Rust友好的CUDA接口
  • 支持高性能并行计算
  • 简化GPU加速开发流程
  • 内存管理优化
  • 支持CUDA核心功能

安装方法

在Cargo.toml中添加依赖:

[dependencies]
sp1-cuda = "0.1"  # 请使用最新版本号

基本使用方法

1. 初始化CUDA环境

use sp1_cuda::CudaDevice;

fn main() {
    // 初始化CUDA设备
    let device = CudaDevice::new(0).expect("Failed to initialize CUDA device");
    println!("Using device: {}", device.name());
}

2. 简单的向量加法示例

use sp1_cuda::{CudaDevice, CudaSlice};

fn vector_add() {
    let device = CudaDevice::new(0).unwrap();
    
    // 创建输入向量
    let a_host = vec![1.0f32, 2.0, 3.0, 4.0];
    let b_host = vec![5.0f32, 6.0, 7.0, 8.0];
    
    // 分配设备内存
    let a_dev = device.htod_sync_copy(&a_host).unwrap();
    let b_dev = device.htod_sync_copy(&b_host).unwrap();
    let mut c_dev = device.alloc_zeros::<f32>(4).unwrap();
    
    // 执行向量加法内核
    device.launch_kernel(
        1,  // 网格大小
        4,  // 块大小
        0,  // 共享内存大小
        None, // 流
        &|a: &CudaSlice<f32>, b: &CudaSlice<f极,c: &mut CudaSlice<f32>| {
            let idx = thread::index();
            if idx < 4 {
                c[idx] = a[idx] + b[idx];
            }
        },
        &[&a_dev, &b_dev, &mut c_dev]
    ).unwrap();
    
    // 将结果复制回主机
    let mut c_host = vec![0.0f32; 4];
    device.dtoh_sync_copy(&c_dev, &mut c_host).unwrap();
    
    println!("Result: {:?}", c_host);  // 输出: [6.0, 8.0, 10.0, 12.0]
}

3. 矩阵乘法示例

use sp1_cuda::{CudaDevice, CudaSlice};

fn matrix_multiply() {
    let device = CudaDevice::new(0).unwrap();
    let dim = 32;
    
    // 创建矩阵
    let a_host = vec![1.0f32; dim * dim];
    let b_host = vec![2.0f32; dim * dim];
    
    // 分配设备内存
    let a_dev = device.htod_sync_copy(&a_host).unwrap();
    let b_dev = device.htod_sync_copy(&b_host).unwrap();
    let mut c_dev = device.alloc_zeros::极,dim * dim).unwrap();
    
    // 执行矩阵乘法内核
    device.launch_kernel(
        (dim as u32 + 15) / 16,  // 网格x
        (dim as u32 + 15) / 16,  // 网格y
        16,  // 块x
        16,  // 块y
        0,   // 共享内存
        None, // 流
        &|a: &CudaSlice<f32>, b: &CudaSlice<f32>, c: &mut CudaSlice<f32>, dim: usize| {
            let row = block::y() * 16 + thread::y();
            let col = block::x() * 16 + thread::x();
            
            if row < dim && col < dim {
                let mut sum = 0.0;
                for k in 0..dim {
                    sum += a[row * dim + k] * b[k * dim + col];
                }
                c[row * dim + col] = sum;
            }
        },
        &[&a_dev, &b_dev, &mut c_dev, &dim]
    ).unwrap();
    
    // 将结果复制回主机
    let mut c_host = vec![0.0f32; dim * dim];
    device.dtoh_sync_copy(&c_dev, &mut c_host).unwrap();
    
    println!("First element: {}", c_host[0]);  // 输出: 64.0 (32 * 2)
}

高级功能

1. 使用共享内存

use sp1_cuda::{CudaDevice, CudaSlice};

fn shared_memory_example() {
    let device = CudaDevice::new(0).unwrap();
    let size = 256;
    
    // 创建输入数据
    let input = vec![1.0f32; size];
    let input_dev = device.htod_sync_copy(&input).unwrap();
    let mut output_dev = device.alloc_zeros::<f32>(size).unwrap();
    
    // 使用共享内存的归约操作
    device.launch_kernel(
        (size as u32 + 255) / 256,  // 网格大小
        256,  // 块大小
        256 * std::mem::size_of::<f32>(),  // 共享内存大小
        None, // 流
        &|input: &CudaSlice<f32>, output: &mut CudaSlice<f32>, size: usize| {
            let shared = shared_array![f32; 256];
            let tid = thread::index();
            let i = block::index() * 256 + tid;
            
            if i < size {
                shared[tid] = input[i];
            } else {
                shared[tid] = 0.0;
            }
            
            sync_threads();
            
            // 归约操作
            let mut offset = 128;
            while offset > 0 {
                if tid < offset {
                    shared[tid] += shared[tid + offset];
                }
                sync_threads();
                offset >>= 1;
            }
            
            if tid == 0 {
                output[block::index()] = shared[0];
            }
        },
        &[&input_dev, &mut output_dev, &size]
    ).unwrap();
    
    // 获取结果
    let mut output = vec![0.0f32; (size + 255) / 256];
    device.dtoh_sync_copy(&output_dev, &mut output).unwrap();
    
    println!("Reduction results: {:?}", output);
}

2. 异步操作

use sp1_cuda::{CudaDevice, CudaSlice, CudaStream};

fn async_example() {
    let device = CudaDevice::new(0).unwrap();
    let stream = CudaStream::new(&device).unwrap();
    
    let size = 1024;
    let a_host = vec![1.0f32; size];
    let b_host = vec![2.0f32; size];
    let mut c_host = vec![0.0f32; size];
    
    // 异步内存分配和拷贝
    let a_dev = device.htod_async_copy(&a_host, &stream).unwrap();
    let b_dev = device.htod_async_copy(&b_host, &stream).unwrap();
    let mut c_dev = device.alloc_async::<f32>(size, &stream).unwrap();
    
    // 异步内核执行
    device.launch_kernel_async(
        (size as u32 + 255) / 256,
        256,
        0,
        Some(&stream),
        &|a: &CudaSlice<f32>, b: &CudaSlice<f32>, c: &mut CudaSlice<f32>| {
            let i = thread::index();
            if i < size {
                c[i] = a[i] + b[i];
            }
        },
        &[&a_dev, &b_dev, &mut c_dev]
    ).unwrap();
    
    // 异步结果拷贝回主机
    device.dtoh_async_copy(&c_dev, &mut c_host, &stream).unwrap();
    
    // 等待所有操作完成
    stream.synchronize().unwrap();
    
    println!("First 5 elements: {:?}", &c_host[..5]);  // 输出: [3.0, 3.0, 3.0, 3.0, 3.0]
}

性能优化建议

  1. 最大化并行性:确保每个CUDA核心都有工作可做
  2. 优化内存访问:使用合并内存访问模式
  3. 合理使用共享内存:减少全局内存访问
  4. 避免线程发散:尽量让同一warp中的线程执行相同路径
  5. 使用异步操作:重叠计算和数据传输

注意事项

  1. 需要安装NVIDIA CUDA工具包
  2. 确保系统有兼容的NVIDIA GPU
  3. 大内存分配可能需要检查错误
  4. 内核启动配置需要根据硬件特性优化

sp1-cuda为Rust开发者提供了强大的GPU计算能力,特别适合需要高性能并行计算的场景。通过合理使用,可以获得比纯CPU实现数十倍甚至数百倍的性能提升。

完整示例代码

下面是一个完整的sp1-cuda使用示例,结合了向量加法和矩阵乘法:

use sp1_cuda::{CudaDevice, CudaSlice, CudaStream};

fn main() {
    // 1. 初始化CUDA环境
    let device = CudaDevice::new(0).expect("Failed to initialize CUDA device");
    println!("Using device: {}", device.name());

    // 2. 向量加法示例
    vector_add_example(&device);

    // 3. 矩阵乘法示例
    matrix_multiply_example(&device);

    // 4. 高级功能示例
    advanced_features_example(&device);
}

fn vector_add_example(device: &CudaDevice) {
    println!("\n向量加法示例:");
    
    let a_host = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];
    let b_host = vec![5.0f32, 6.0, 7.0, 8.0, 9.0];
    let size = a_host.len();
    
    // 分配设备内存
    let a_dev = device.htod_sync_copy(&a_host).unwrap();
    let b_dev = device.htod_sync_copy(&b_host).unwrap();
    let mut c_dev = device.alloc_zeros::<f32>(size).unwrap();
    
    // 执行向量加法内核
    device.launch_kernel(
        (size as u32 + 255) / 256,
        256,
        0,
        None,
        &|a: &CudaSlice<f32>, b: &CudaSlice<f32>, c: &mut CudaSlice<f32>, size: usize| {
            let idx = thread::index();
            if idx < size {
                c[idx] = a[idx] + b[idx];
            }
        },
        &[&a_dev, &b_dev, &mut c_dev, &size]
    ).unwrap();
    
    // 获取结果
    let mut c_host = vec![0.0f32; size];
    device.dtoh_sync_copy(&c_dev, &mut c_host).unwrap();
    
    println!("向量加法结果: {:?}", c_host);
}

fn matrix_multiply_example(device: &CudaDevice) {
    println!("\n矩阵乘法示例:");
    
    let dim = 16; // 16x16矩阵
    let a_host = vec![2.0f32; dim * dim];
    let b_host = vec![3.0f32; dim * dim];
    
    // 分配设备内存
    let a_dev = device.htod_sync_copy(&a_host).unwrap();
    let b_dev = device.htod_sync_copy(&b_host).unwrap();
    let mut c_dev = device.alloc_zeros::<f32>(dim * dim).unwrap();
    
    // 执行矩阵乘法内核
    device.launch_kernel(
        (dim as u32 + 15) / 16,
        (dim as u32 + 15) / 16,
        16,
        16,
        0,
        None,
        &|a: &CudaSlice<f32>, b: &CudaSlice<f32>, c: &mut CudaSlice<f32>, dim: usize| {
            let row = block::y() * 16 + thread::y();
            let col = block::x() * 16 + thread::x();
            
            if row < dim && col < dim {
                let mut sum = 0.0;
                for k in 0..dim {
                    sum += a[row * dim + k] * b[k * dim + col];
                }
                c[row * dim + col] = sum;
            }
        },
        &[&a_dev, &b_dev, &mut c_dev, &dim]
    ).unwrap();
    
    // 获取结果
    let mut c_host = vec![0.0f32; dim * dim];
    device.dtoh_sync_copy(&c_dev, &mut c_host).unwrap();
    
    println!("矩阵左上角4x4结果:");
    for i in 0..4 {
        for j in 0..4 {
            print!("{:5.1} ", c_host[i * dim + j]);
        }
        println!();
    }
}

fn advanced_features_example(device: &CudaDevice) {
    println!("\n高级功能示例 - 异步操作和共享内存:");
    
    let stream = CudaStream::new(device).unwrap();
    let size = 512;
    
    // 异步内存分配和拷贝
    let a_host = vec![1.0f32; size];
    let b_host = vec![2.0f32; size];
    let mut c_host = vec![0.0f32; size];
    
    let a_dev = device.htod_async_copy(&a_host, &stream).unwrap();
    let b_dev = device.htod_async_copy(&b_host, &stream).unwrap();
    let mut c_dev = device.alloc_async::<f32>(size, &stream).unwrap();
    
    // 异步执行向量加法内核
    device.launch_kernel_async(
        (size as u32 + 255) / 256,
        256,
        0,
        Some(&stream),
        &|a: &CudaSlice<f32>, b: &CudaSlice<f32>, c: &mut CudaSlice<f32>| {
            let idx = thread::index();
            if idx < size {
                c[idx] = a[idx] + b[idx];
            }
        },
        &[&a_dev, &b_dev, &mut c_dev]
    ).unwrap();
    
    // 异步结果拷贝回主机
    device.dtoh_async_copy(&c_dev, &mut c_host, &stream).unwrap();
    
    // 等待所有操作完成
    stream.synchronize().unwrap();
    
    println!("异步操作结果前5个元素: {:?}", &c_host[..5]);
}

这个完整示例展示了:

  1. CUDA设备初始化
  2. 基本的向量加法操作
  3. 矩阵乘法实现
  4. 高级功能如异步操作的使用

您可以根据实际需求修改参数和内核函数来实现不同的GPU加速计算任务。

回到顶部