🌊

Haskell のGPU演算環境をセットアップする

2023/06/18に公開

概要

以下の書籍を購入ました。途中でaccelerate-cudaのインストールを求められたのですが、これは現在accelerate-llvm-ptxに置き換わっています。
https://www.amazon.co.jp/gp/product/4873116899/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1

このセットアップ方法が少々面倒だったので書き残しておきます。

※英語版ですが以下で上記テキストの内容が公開されています。
https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch06.html

ソフト環境

名前 バージョン
OS Ubuntu 20.04
docker 24.0.2, build cb74dfc
docker compose v2.18.1
cuda 11.6
nvidia-docker 2.13.0

そんなことしなくても、、、

この記事書いた1年後に気づいたのですが、cudaを10.2に戻して以下コマンドを実行すればdocker無しで使えるようになりました。なのでcudaバージョン戻せる方は戻したほうが快適です。もちろんllvmとかはインストールする必要があります。後々別の記事を書きますか、、、

cabal install accelerate-llvm-ptx
cabal install --lib accelerate-llvm-ptx

cuda 10.2に戻す方法は以下に書きました。
https://zenn.dev/link/comments/941eb28d81af23

ハード環境

名前 バージョン
CPU AMD Ryzen 9 3900XT 12-Core
GPU RTX3080
RAM 76GB

手順

以下をgit cloneします
https://github.com/yosukeueda33/haskell-gpu-env

cloneしたフォルダ内で以下を実行します。

sudo docker compose build
sudo docker compose up -d

これにより出来たコンテナに以下でアクセスします。

sudo docker exec -it haskell_gpu-haskell-cuda-1 bash

以降はコンテナ内での操作です。
以下を実行します。

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda-11.6/nvvm/lib64"

以下を/app/mntgit cloneします。
https://github.com/AccelerateHS/accelerate-llvm

上記の/app/mnt/accelerate-llvmフォルダ内で以下を実行してください。

ln -s stack-9.0.yaml stack.yaml
stack setup
stack install

これによりGPUが使用可能となります。

確認

/app/mnt/accelerate-llvmでstack ghciを実行し、以下がエラーなくimportできると思います。

import Data.Array.Accelerate.LLVM.PTX

本当はコンテナのどこでもimportできるようにしたいですがやり方を見いだせていません、、、

以下の本のサンプルを実行してみます。
https://www.amazon.co.jp/gp/product/4873116899/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1

サンプルは以下にあります。
https://github.com/simonmar/parconc-examples

上記のサンプル内のGPUを使った最短経路問題を解くコードであるfwaccel-gpu.hsとAccelerateCompat.hsを/app/mnt/accelerate-llvmに移動し、fwaccel-gpu.hsを以下を参考に編集してください。

# diff fwaccel-gpu_org.hs fwaccel-gpu.hs
9c9,10
< import Data.Array.Accelerate.CUDA
---
> -- import Data.Array.Accelerate.CUDA
> import Data.Array.Accelerate.LLVM.PTX
77c78
< test = toList (shortestPaths testGraph) == toList expectedResult
---
> test = toList (shortestPaths testGraph) Prelude.== toList expectedResult
81c82
<   where k = length xs
---
>   where k = Prelude.length xs
86c87
<    (n:_) <- fmap (fmap read) getArgs
---
>    (n:_) <- Prelude.fmap (Prelude.fmap read) getArgs

コンパイル、実行してみます。

stack exec -- ghc -O2 fwaccel-gpu.hs -threaded
./fwaccel-gpu 2000 +RTS -s

以下の様に出力されました。

root@a0dff553f17f:/app/mnt/accelerate-llvm# ./fwaccel-gpu 2000 +RTS -s
Scalar Z [-1526072448]
   1,700,044,264 bytes allocated in the heap
   1,084,219,424 bytes copied during GC
     211,265,000 bytes maximum residency (11 sample(s))
       1,227,288 bytes maximum slop
             439 MiB total memory in use (0 MB lost due to fragmentation)

                                     Tot time (elapsed)  Avg pause  Max pause
  Gen  0      1673 colls,     0 par    0.722s   0.724s     0.0004s    0.0012s
  Gen  1        11 colls,     0 par    0.591s   0.592s     0.0538s    0.2041s

  TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)

  SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)

  INIT    time    0.001s  (  0.001s elapsed)
  MUT     time    0.659s  (  0.672s elapsed)
  GC      time    1.314s  (  1.316s elapsed)
  EXIT    time    0.001s  (  0.001s elapsed)
  Total   time    1.974s  (  1.990s elapsed)

  Alloc rate    2,580,233,428 bytes per MUT second

  Productivity  33.4% of total user, 33.8% of total elapsed

並行でホストマシンにてnvidia-smiを実行してみて使用率からGPU演算がなされていることが確認できました。

Discussion