Rust – Cargo で CUDA ソースコードをまとめてビルドする

Rust 公式の cc-rs クレートを利用することで、CUDA のソースコードもひっくるめて cargo ビルドすることができます。

簡単なサンプルで利用方法を紹介します。

目次

事前準備

Cargo で CUDA をビルドするためには、Cuda Toolkit が別途インストールされている必要があります。
Ubuntu で簡易的にインストールするには、下記のコマンドで対応可能です。

$ sudo apt install nvidia-cuda-toolkit g++


より詳細には以下の記事にまとめてあります。

CUDA コードを含めた Cargo ビルド方法

プロジェクトの作成

まず、cargo new で新規プロジェクトを作成します。

$ cargo new sample-cu

CUDA ソースコードの準備

Cargo でビルドする CUDA のソースコードを用意しておきます。
外部から受け取ったリストの要素を2倍するコードです。

プロジェクト配下に src/mul2.cc として保存しておきます。

// src/mul2.cu

#include <cuda_runtime.h>

__global__ void mul2_dev(int *xs, size_t n)
{
    int i = blockDim.x * blockIdx.x + threadIdx.x;
    if (i < n)
    {
        xs[i] *= 2;
    }
}

extern "C" void mul2(int *xs, size_t n)
{
    size_t bytes = n * sizeof(int);

    int *dev_xs;
    cudaMalloc(&dev_xs, bytes);
    cudaMemcpy(dev_xs, xs, bytes, cudaMemcpyHostToDevice);

    dim3 block(1024);
    dim3 grid((n + block.x - 1) / block.x);
    mul2_dev<<<grid, block>>>(dev_xs, n);

    cudaMemcpy(xs, dev_xs, bytes, cudaMemcpyDeviceToHost);
    cudaFree(dev_xs);
    cudaDeviceReset();
}

Rust からは mul2 メソッドを呼びます。
関数名がマングルされないよう、extern "C" を与えておきます。

Cargo.toml にビルド用依存関係を記述

Cargo.toml に cc-rs への依存関係を追記します。
注意点として、[dependencies] ではなく、[build-dependencies] を新規追加してここに定義します。

# Cargo.toml

[package]
name = "sample"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[build-dependencies]
cc = "1.0"

build.rs の作成

ビルド用の main 関数を準備します。

この例では、src/mul2.cu を読み込んで、mul2 ライブラリを出力しろ、という命令になります。

// build.rs

fn main() {
    cc::Build::new()
        .cuda(true)
        .file("src/mul2.cu")
        .compile("mul2");
}

Rust の main.rs を作成

msin.rs を修正して、CUDA コードの mul2 関数を呼び出すようにします。
ここでは、0 から 99 の連続した整数のリストを生成し、これを CUDA の mul2 関数に渡しています。

// src/main.rs

extern "C" {
    fn mul2(xs: *mut i32, n: usize);
}

fn main() {
    let mut v = (0..100).collect::<Vec<_>>();
    unsafe { mul2(v.as_mut_ptr(), v.len()) };
    println!("{:?}", v);
}

ここまでのディレクトリツリー構造

ここまでで、sample-cu プロジェクトの配下は次のようなファイル構成になっているはずです。

$ tree .
.
├── Cargo.lock
├── Cargo.toml
├── build.rs
└── src
    ├── main.rs
    └── mul2.cu

ビルドして実行

cargo run によって、ビルドからランまで実行します。

$ cargo run
   Compiling sample-cu v0.1.0 (/home/gari/sandbox/sample-cu)
    Finished dev [unoptimized + debuginfo] target(s) in 1.21s
     Running `target/debug/sample-cu`
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198]

リストがすべて2倍されて返ってきているのが確認できます。

  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次