Rust CUDA加速计算库ug-cuda的使用,高性能GPU并行计算与CUDA编程支持

Rust CUDA加速计算库ug-cuda的使用

ug-cuda是一个Rust库,提供了高性能GPU并行计算与CUDA编程支持。它允许Rust开发者利用NVIDIA GPU的强大计算能力进行加速计算。

安装

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

cargo add ug-cuda

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

ug-cuda = "0.4.0"

示例代码

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

use ug_cuda::{CudaDevice, CudaSlice, LaunchAsync};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化CUDA设备
    let device = CudaDevice::new(0)?;
    
    // 创建输入数据
    let host_input = vec![1.0f32, 2.0, 3.0, 4.0];
    
    // 将数据复制到GPU
    let dev_input = device.htod_sync_copy(&host_input)?;
    
    // 创建GPU输出缓冲区
    let mut dev_output = device.alloc_zeros::<f32>(host_input.len())?;
    
    // 定义CUDA内核(使用PTX汇编)
    let ptx = r#"
    .version 6.5
    .target sm_30
    .address_size 64
    
    .visible .entry kernel(
        .param .u64 ptr_in,
        .param .u64 ptr_out,
        .param .u32 len
    ) {
        .reg .f32 %f<4>;
        .reg .pred %p<2>;
        .reg .u32 %r<6>;
        .reg .u64 %rl<4>;
    
        ld.param.u64 %rl0, [ptr_in];
        ld.param.u64 %rl1, [ptr_out];
        ld.param.u32 %r0, [len];
        mov.u32 %r1, %tid.x;
        mov.u32 %r2, %ctaid.x;
        mov.u32 %r3, %ntid.x;
        mad.lo.s32 %r4, %r2, %r3, %r1;
        setp.ge.u32 %p0, %r4, %r0;
        @%p0 bra BB0_2;
    
        cvta.to.global.u64 %rl2, %rl0;
        cvta.to.global.u64 %rl3, %rl1;
        mul.wide.u32 %rl4, %r4, 4;
        add.s64 %rl5, %rl2, %rl4;
        ld.global.f32 %f1, [%rl5];
        add.s64 %rl6, %rl3, %rl4;
        mul.f32 %f2, %f1, %f1;
        st.global.f32 [%rl6], %f2;
    
    BB0_2:
        ret;
    }
    "#;
    
    // 加载内核
    let module = device.load极速计算示例:

```rust
use ug_cuda::{CudaDevice, CudaSlice, LaunchAsync, LaunchConfig};

// 向量平方计算内核
const SQUARE_KERNEL: &str = r#"
.version 6.5
.target sm_30
.address_size 64

.visible .entry square_kernel(
    .param .u64 input_ptr,
    .param .u64 output_ptr,
    .param .u32 length
) {
    .reg .f32 %f<4>;
    .reg .pred %p<2>;
    .reg .u32 %r<6>;
    .reg .u64 %rl<4>;

    ld.param.u64 %rl0, [input_ptr];
    ld.param.u64 %rl1, [output_ptr];
    ld.param.u32 %r0, [length];
    
    // 计算线程索引
    mov.u32 %r1, %tid.x;
    mov.u32 %r2, %ctaid.x;
    mov.u32 %r3, %ntid.x;
    mad.lo.s32 %r4, %r2, %r3, %r1;
    
    // 边界检查
    setp.ge.u32 %p0, %r4, %r0;
    @%p0 bra EXIT;
    
    // 计算地址并加载数据
    cvta.to.global.u64 %rl2, %rl0;
    cvta.to.global.u64 %rl3, %rl1;
    mul.wide.u32 %rl4, %r4, 4;
    add.s64 %rl5, %rl2, %rl4;
    ld.global.f32 %f1, [%rl5];
    
    // 计算平方并存储
    add.s64 %rl6, %rl3, %rl4;
    mul.f32 %f2, %f1, %f1;
    st.global.f32 [%rl6], %f2;

EXIT:
    ret;
}
"#;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化CUDA设备(使用第一个GPU)
    let device = CudaDevice::new(0)?;
    
    // 准备测试数据: 1到10的浮点数
    let host_input: Vec<f32> = (1..=10).map(|x| x as f32).collect();
    
    // 将数据复制到GPU显存
    let dev_input = device.htod_sync_copy(&host_input)?;
    
    // 分配GPU输出缓冲区(初始化为0)
    let mut dev_output = device.alloc_zeros::<f32>(host_input.len())?;
    
    // 加载PTX内核
    let module = device.load_ptx(SQUARE_KERNEL.into(), "square_module", "square_kernel")?;
    let kernel = module.function("square_kernel")?;
    
    // 配置内核启动参数
    let blocks = (host_input.len() as u32 + 255) / 256;  // 每个块256个线程
    let config = LaunchConfig {
        grid_dim: (blocks, 1, 1),
        block_dim: (256, 1, 1),
        shared_mem_bytes: 0,
    };
    
    // 异步启动内核
    unsafe {
        LaunchAsync::launch(
            &kernel,
            config,
            (&dev_input, &mut dev_output, host_input.len() as u32),
        )?
    }
    
    // 同步等待计算完成
    device.synchronize()?;
    
    // 将结果从GPU复制回CPU
    let mut host_output = vec![0.0f32; host_input.len()];
    device.dtoh_sync_copy_into(&dev_output, &mut host_output)?;
    
    // 打印输入输出对比
    println!("输入数据: {:?}", host_input);
    println!("平方结果: {:?}", host_output);
    
    Ok(())
}

功能特性

  1. CUDA设备管理:轻松初始化和管理CUDA设备
  2. 内存管理:在主机和设备间高效传输数据
  3. 内核执行:支持加载和执行CUDA PTX内核
  4. 异步操作:提供异步操作支持以提高性能
  5. 错误处理:全面的错误处理机制

许可证

ug-cuda采用MIT或Apache-2.0双重许可证。


1 回复

Rust CUDA加速计算库ug-cuda使用指南

概述

ug-cuda是一个Rust库,提供了对CUDA加速计算的支持,让开发者能够在Rust中利用GPU进行高性能并行计算。它封装了CUDA的底层API,提供了更符合Rust习惯的安全接口。

主要特性

  • 安全的CUDA内存管理
  • 设备管理接口
  • 内核函数启动
  • 流和事件管理
  • 与Rust生态系统的良好集成

安装方法

在Cargo.toml中添加依赖:

[dependencies]
ug-cuda = "0.1"

需要安装CUDA工具包(至少CUDA 10.0)和兼容的NVIDIA显卡驱动。

完整示例代码

1. 初始化CUDA环境

use ug_cuda::driver::{initialize, Device};

fn main() {
    // 初始化CUDA驱动
    initialize().unwrap();
    
    // 获取设备数量
    let device_count = Device::count().unwrap();
    println!("找到 {} 个CUDA设备", device_count);
    
    // 获取第一个设备
    let device = Device::get(0).unwrap();
    println!("使用设备: {}", device.name().unwrap());
}

2. 内存管理示例

use ug_cuda::memory::{DeviceBox, DeviceCopy};

fn main() {
    // 在设备上分配内存
    let mut dev_vec = DeviceBox::new(&[1.0f32, 2.0, 3.0]).unwrap();
    
    // 从设备内存复制回主机
    let mut host_data = [0.0f32; 3];
    dev_vec.copy_to(&mut host_data).unwrap();
    
    println!("从设备获取的数据: {:?}", host_data);
}

3. 完整向量加法示例

3.1 编写CUDA内核(kernel.cu)

extern "C" __global__ void add_vectors(const float* a, const float* b, float* c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n) {
        c[i] = a[i] + b[i];
    }
}

需要先编译为PTX文件:

nvcc --ptx -o kernel.ptx kernel.cu

3.2 Rust主程序

use ug_cuda::{driver::LaunchAsync, module::Module, memory::DeviceBox};

fn main() {
    // 初始化CUDA环境
    ug_cuda::driver::initialize().unwrap();
    
    // 加载编译好的CUDA模块
    let module = match Module::from_file("kernel.ptx") {
        Ok(m) => m,
        Err(e) => {
            eprintln!("无法加载PTX文件: {}", e);
            return;
        }
    };
    
    // 获取内核函数
    let kernel = match module.function("add_vectors") {
        Ok(k) => k,
        Err(e) => {
            eprintln!("找不到内核函数: {}", e);
            return;
        }
    };
    
    // 准备数据
    let a = [1.0f32, 2.0, 3.0];
    let b = [4.0f32, 5.0, 6.0];
    let mut c = [0.0f32; 3];
    
    // 分配设备内存
    let d_a = DeviceBox::new(&a).unwrap();
    let d_b = DeviceBox::new(&b).unwrap();
    let mut d_c = DeviceBox::new(&c).unwrap();
    
    // 启动内核
    unsafe {
        if let Err(e) = kernel.launch(
            &[(&d_a, &d_b, &mut d_c, &3)],
            1,  // gridDim
            3,  // blockDim
            0,  // sharedMemBytes
            None // stream
        ) {
            eprintln!("内核执行失败: {}", e);
            return;
        }
    }
    
    // 复制结果回主机
    if let Err(e) = d_c.copy_to(&mut c) {
        eprintln!("数据复制失败: {}", e);
        return;
    }
    
    println!("计算结果: {:?}", c); // 输出: [5.0, 7.0, 9.0]
}

4. 异步操作完整示例

use ug_cuda::{driver::{Stream, initialize}, memory::{DeviceBox, DeviceCopy}};

fn main() {
    // 初始化CUDA
    initialize().unwrap();
    
    // 创建CUDA流
    let stream = Stream::new().unwrap();
    
    // 准备数据
    let host_data = [1u32, 2, 3, 4];
    let mut dev_data = DeviceBox::new_uninit().unwrap();
    
    // 异步内存复制
    if let Err(e) = dev_data.copy_from_async(&host_data, &stream) {
        eprintln!("异步复制失败: {}", e);
        return;
    }
    
    // 等待流完成
    if let Err(e) = stream.synchronize() {
        eprintln!("流同步失败: {}", e);
        return;
    }
    
    println!("异步操作完成");
}

5. 性能计时完整示例

use ug_cuda::driver::{Event, initialize};

fn main() {
    // 初始化CUDA
    initialize().unwrap();
    
    // 创建事件
    let start = Event::new().unwrap();
    let stop = Event::new().unwrap();
    
    // 记录开始时间
    if let Err(e) = start.record(None) {
        eprintln!("无法记录开始事件: {}", e);
        return;
    }
    
    // 模拟需要计时的操作
    for _ in 0..1000 {
        // 一些计算...
    }
    
    // 记录结束时间
    if let Err(e) = stop.record(None) {
        eprintln!("无法记录结束事件: {}", e);
        return;
    }
    
    // 等待事件完成
    if let Err(e) = stop.synchronize() {
        eprintln!("事件同步失败: {}", e);
        return;
    }
    
    // 计算耗时
    match start.elapsed(&stop) {
        Ok(time) => println!("操作耗时: {} 毫秒", time),
        Err(e) => eprintln!("无法计算耗时: {}", e),
    }
}

性能提示

  1. 尽量减少主机与设备间的数据传输
  2. 使用合适的block和grid大小
  3. 利用共享内存减少全局内存访问
  4. 使用异步操作和流来重叠计算与数据传输

注意事项

  • ug-cuda仍在活跃开发中,API可能会有变动
  • 需要正确安装CUDA工具链
  • 内核代码需要单独编译为PTX文件
  • 错误处理很重要,CUDA操作可能会失败

通过ug-cuda,Rust开发者可以安全高效地利用GPU的计算能力,同时享受Rust的内存安全保证。

回到顶部