Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Dockerで体験する富岳のアーキテクチャ「AArch64」ハンズオン / Xbyak_aarch64 handson
Search
kaityo256
PRO
November 25, 2021
Programming
4
1.1k
Dockerで体験する富岳のアーキテクチャ「AArch64」ハンズオン / Xbyak_aarch64 handson
Dockerで体験する富岳のアーキテクチャ「AArch64」ハンズオン資料
https://github.com/kaityo256/xbyak_aarch64_handson
kaityo256
PRO
November 25, 2021
Tweet
Share
More Decks by kaityo256
See All by kaityo256
GNU Makeの使い方 / How to use GNU Make
kaityo256
PRO
13
4.4k
制限ボルツマンマシンの話 / Introduction of RBM
kaityo256
PRO
3
440
論文の読み方 / How to survey
kaityo256
PRO
195
140k
リンゴゲームと貧富の差 / Origin of the disparity of wealth
kaityo256
PRO
12
13k
渡辺研Slackの使い方 / Slack Local Rule
kaityo256
PRO
8
7.7k
時間の矢について / Time's arrow
kaityo256
PRO
12
17k
t-SNEをざっくりと理解 / Overview of t-SNE
kaityo256
PRO
2
630
未定義動作でFizz Buzz / Undefined Fizz Buzz
kaityo256
PRO
1
770
卒論の書き方 / Happy Writing
kaityo256
PRO
30
19k
Other Decks in Programming
See All in Programming
TypeScript 関数型スタイルでバックエンド開発のリアル
naoya
49
16k
Using "modern" Ruby to build a better, faster Homebrew
mikemcquaid
2
300
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
1
130
JS RPCを理解する
yusukebe
5
300
スタックトレース始めてみた
kuro_kurorrr
5
1.2k
GitLab CI/CD で C#/WPFアプリケーションのテストとインストーラーのビルド・デプロイを自動化する
hacarus
0
620
Findy - エンジニア向け会社紹介 / Findy Letter for Engineers
findyinc
2
74k
slow types ってなんだろう?
karad
0
210
TypeScript Custom GitHub Action Development Tips
peaceiris
5
830
TypeScriptとGraphQLで実現する 型安全なAPI実装 / TSKaigi 2024
hokaccha
5
2.9k
An adventure of Happy Eyeballs
coe401_
1
290
欠陥を早期に発見するための Software Engineer in Test とその重要性 / What is Software Engineer in Test and How they works
orgachem
PRO
18
2.5k
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
23
1.7k
Making Projects Easy
brettharned
109
5.5k
The Straight Up "How To Draw Better" Workshop
denniskardys
228
130k
For a Future-Friendly Web
brad_frost
172
9k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
9
1.3k
Gamification - CAS2011
davidbonilla
77
4.6k
Faster Mobile Websites
deanohume
300
30k
Designing with Data
zakiwarfel
96
4.8k
Intergalactic Javascript Robots from Outer Space
tanoku
266
26k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
34
8.9k
What's in a price? How to price your products and services
michaelherold
238
11k
KATA
mclloyd
16
12k
Transcript
1 38 Dockerで体験する富岳のアーキテクチャ 「AArch64」ハンズオン 第13回 HPC-Phys 勉強会 慶應義塾大学理工学部物理情報工学科 渡辺宙志 https://github.com/kaityo256/xbyak_aarch64_handson
ハンズオン資料
2 38 • 事前準備編 • Dockerイメージのビルド • SVEとXbyakの説明 • ハンズオン編
• 動作確認 • 組み込み関数編 • Xbyak編
3 38 ハンズオン資料「ハンズオン編」「Dockerイメージのビルド」 git clone https://github.com/kaityo256/xbyak_aarch64_handson.git cd xbyak_aarch64_handson 適当な場所でリポジトリをクローン Dockerイメージをビルド(3~5分くらい)
cd docker make
4 38 適当な場所(~/github)でリポジトリをクローン ハンズオン資料「富岳実機での動作」 cd github git clone --recursive https://github.com/kaityo256/xbyak_aarch64_handson.git
インタラクティブキューに入ってXbyakのビルド cd xbyak_aarch64_handson # ここでインタラクティブキューに入る cd xbyak_aarch64/ make 環境変数の設定 export XBYAK_PATH=~/github/xbyak_aarch64_handson/xbyak_aarch64 export CPLUS_INCLUDE_PATH=$XBYAK_PATH export LIBRARY_PATH=$XBYAK_PATH/lib 組み込み関数はFCC、Xbyakは g++ filename.cpp -lxbyak_aarch64でビルドできる
5 38 ノード数:158976 ネットワーク: Tofu (24,23,24,2,3,2) 1CPU/1ノード 4CMG + 2アシスタントコア/1CPU
12 core/ 1CMG ISA: Armv8.2-A + SVE
6 38 ノード数:158976 ネットワーク: Tofu (24,23,24,2,3,2) 1CPU/1ノード 4CMG + 2アシスタントコア/1CPU
12 core/ 1CMG ISA: Armv8.2-A + SVE プログラマから見た この辺はMPI この辺はOpenMP ここをどうするか?
7 38 ARM x86 命令セット総称 AArch32 (A32) AArch64 (A64) IA-32
AMD64, Intel64 拡張命令セット MMX, SSE,AVX, AVX2, AVX-512 NEON SVE マイクロ アーキテクチャ A64fx Skylake ↑が実装する 命令セット ARMv8.2-A + SVE Intel64+MMX+SSE+... +AVE-512+... gccに渡す オプション -march=armv8-a+sve -mave2, -mavx512f, ... or -march=skylake
8 38 ※ 演算にはレイテンシがあるが、パイプライン処理により「理想的には」 1サイクルに1演算できる(スループット) 性能 動作 周波数 コア数 同時命令
発行数 SIMD = x x x 富岳の場合(倍精度) 2GHz 48 4 8 (2 x 積和) x x x = 3072GF
9 38 性能 動作 周波数 コア数 同時命令 発行数 SIMD =
x x x ここを上げたい ここはもう無理 ここも多分無理 ここを増やす (メニーコア) ここを増やす (幅広SIMD)
10 38 x86の場合 xmm ymm zmm 128 bit 256 bit
512 bit 順調に倍々ゲームで増えてきた
11 38 zmm ymm xmm SIMD幅が伸びても下位を同じ名前でアクセスできるようにする 後方互換性を保つ 古いコードは、広くなったSIMD幅を 活かせない また全部書き直し・・・
12 38 SIMD幅が伸びるたびにコードを 書き直し。なんとかならないかな… SIMD幅を固定しない命令セットに すればよいのでは? SVE
13 38 Scalable 幅を固定しない Vector SIMDの Extension 追加命令セット 特徴:Predicate-centric Approach
命令ごとにどの要素を使うかをマスク処理できる
14 38 11個のデータを4つずつ処理したい 普通にやると3個余る 余りをスカラループで回す →ベクトル2回転+スカラー3回転 ベクトル処理 ベクトル処理 スカラー処理 ※11回転が5回転に
15 38 プレディケートレジスタにより、どの要素をロードするか指定 ベクトル3回転で済む ※11回転が3回転に
16 38 スケーラブルなSIMD幅 スケーラブルなコードを書いておけば、将来SIMD幅が増 えたハードウェアで実行した時に、その恩恵を受けること ができる・・・という夢を見たのさ Predicate-centric Approach ほぼ全ての命令にプレディケートレジスタを指定でき、 どの要素にどんな命令を実行するか細かく指定できる
17 38 コンパイラに任せる ディレクティブを指定する 組み込み関数で書く Xbyakで書く フルアセンブリで組む 高レイヤ (楽だが細かい調整が難しい) 低レイヤ
(細かく調整できるが大変)
18 38 アセンブリと一体一対応した関数を使う 組み込み関数 アセンブリ svcntb svptrue_b8 svld1_f64 cntb ptrue
p0.b, ALL ld1d 概ね「sv + アセンブリ名 + 型」という命名規則
19 38 svfloat64_t レジスタにfloat64_tが詰まっているとして扱う コンパイル時に要素数が確定しない 512ビットレジスタなら8要素 std::vector<float64_t> a; svbool_t tp
= svptrue_b64(); svfloat64_t va = svld1_f64(tp, a.data()); svbool_t プレディケートレジスタを表す型 コンパイル時にビット長が確定しない こんな感じに使う
20 38 Pros • 関数の呼び出し規約を気にしなくて良い • アドレッシングを気にしなくて良い • レジスタ割り当てを気にしなくて良い •
コンパイラによる最適化が期待できる Cons • 組み込み関数以外の場所は制御できない • コンパイラが余計なことをする場合がある
21 38 Xbyak (カイビャック)はJITアセンブラ 関数単位でアセンブリで書く 作者は光成(herumi)さん 実行する命令を関数単位で実行時に作る Intelの機械学習ライブラリoneDNNなどが利用 https://github.com/herumi/xbyak x86向け
https://github.com/fujitsu/xbyak_aarch64 Aarch64向け
22 38 struct Code : Xbyak_aarch64::CodeGenerator { Code() { mov(w0,
1); ret(); } }; int main() { Code c; auto f = c.getCode<int (*)()>(); c.ready(); printf("%d¥n",f()); } Xbyak_aarch64::CodeGeneratorを継承し、コンストラクタに アセンブリに対応したコードを並べておく テンプレートに関数のシグネチャを指定して関数へのポインタを取得 その関数を呼び出す
23 38 実行時にメモリを確保して、そこに実行時に命令を並べる struct Code : Xbyak_aarch64::CodeGenerator { Code() {
mov(w0, 1); ret(); } }; f: mov w0, 1 ret int main() { Code c; auto f = c.getCode<int (*)()>(); c.ready(); printf("%d¥n",f()); } その領域に実行権限をつけ、先頭アドレスを 呼び出すことで関数として使う ※x86では不要だが、ARMでは実行前にready()を呼ぶ必要がある
24 38 Pros • 実行時の情報を使ったコード生成ができる • キャッシュサイズやCPUの種類 • コンパイル時に決まらない実行時定数 •
書いた通りに動く • 生アセンブリより書きやすい Cons • 関数の呼び出し規約やアドレッシング等の アセンブリの知識必須 • ローカル変数を自分で管理する必要がある • レジスタ割り当てをする必要がある
25 38 先ほどmakeしたディレクトリでmake runすれば Dockerの中に入ることができる $ make run [user@291e9d9cad93 ~]$
xbyak_aarch64_handson/sampleにサンプルコードがある • intrinsic/01_sve_length • xbyak/01_test 以下でそれぞれ動作テストをする
26 38 プレディケートレジスタ (PR) SVEのレジスタは128ビット x N プレディケートレジスタは最低8ビット単位 → レジスタ長は16ビット
x N 512ビットならN=4なので、PRは64ビット 1. どの型に使うかにより、立てるビットが異なる 2. 立てるパターンを指定できる 3. レジスタ長を変えて実行してみる 確認すること
27 38 svptrue_b8() svptrue_pat_b8(SV_ALL) 組み込み関数 アセンブリ 64bit svptrue_b16() svptrue_pat_b16(SV_ALL) 組み込み関数
アセンブリ 0101010101010101010101010101010101010101010101010101010101010101 1111111111111111111111111111111111111111111111111111111111111111 svptrue_b32 svptrue_b64 ptrue p0.s, ALL ptrue p0.d, ALL ptrue p0.h, ALL ptrue p0.b, ALL
28 38 レジスタへのロード 確認すること 1. 指定の先頭アドレスからまとめてレジスタにロードできる 2. 一回の命令で複数要素まとめて演算できる 3. 演算にマスク処理ができる
4. inactiveな要素に対して 1. ゼロクリアする (zeroing predication) 2. 第一引数透過 (merging predication) svfloat64_t型へのロードや加算を試してみる
29 38 double a[] = {0, 1, 2, 3, 4,
5, 6, 7}; svfloat64_t va = svld1_f64(svptrue_b64(), a); 0 1 2 3 4 5 6 7 メモリ SVレジスタ 0 1 2 3 4 5 6 7 プレディケート レジスタ
30 38 0 1 2 3 4 5 6 7
1 1 1 1 1 1 1 1 + 1 2 3 4 5 6 7 8 そのまま全部足す va vb
31 38 0 1 2 3 4 5 6 7
1 1 1 1 1 1 1 1 + 1 2 0 0 0 0 0 0 Inactiveな場所はゼロクリア (zeroing predication) va vb svadd_f64_z(svptrue_pat_b64(SV_VL2), va, vb)
32 38 0 1 2 3 4 5 6 7
1 1 1 1 1 1 1 1 + 1 2 Inactiveな場所は透過 (merging predication) va vb svadd_f64_m(svptrue_pat_b64(SV_VL2), va, vb) 2 3 4 5 6 7
33 38 ABI (Application Binary Interface)が定めるものの一つ 関数を呼び出す時、引数をどうやって渡すか、返り値を どう返すかを定める int f(int
i){ return i + 1; } struct Code : Xbyak_aarch64::CodeGenerator { Code() { add(w0, w0, 1); ret(); } }; こんな関数を作りたい Xbyakではこう書く 整数の第一引数がレジスタw0に渡され、返り値を w0に入れてretすることを知っている必要がある
34 38 Xbyakのコードは動的に作られるため、実行時までアセンブリがわからない → 実行時のコードをダンプし、逆アセンブルすることでデバッグする #include <cstdio> #include <xbyak_aarch64/xbyak_aarch64.h> struct
Code : Xbyak_aarch64::CodeGenerator { Code() { mov(w0, 1); ret(); } void dump(const char *filename) { FILE *fp = fopen(filename, "wb"); fwrite(getCode(), 1, getSize(), fp); } }; ファイル名を受け取り 機械語バイナリを保存
35 38 int main() { Code c; auto f =
c.getCode<int (*)(int)>(); c.ready(); c.dump("xbyak.dump"); printf("%d¥n",f(10)); } ここでダンプをxbyak.dump という名前で保存 実行するとxbyak.dumpができるので、objdumpで逆アセンブル $ aarch64-linux-gnu-objdump -D -maarch64 -b binary -d xbyak.dump 0000000000000000 <.data>: 0: 52800020 mov w0, #0x1 // #1 4: d65f03c0 ret 長いので xdump にaliasをはってある
36 38 1 2 3 4 5 15 与えられた配列の要素が 3の倍数なら-1
5の倍数なら-2 15の倍数なら-3 で上書きする ・・・ 1 2 -1 4 -2 -3 ・・・ 16 16
37 38 1 2 3 4 5 15 ・・・ 16
0 0 3 3 3 15 ・・・ 15 3で割って3をかける 等しい場所にフラグを立てる ・・・
38 38 1 2 -1 4 5 -1 ・・・ 16
・・・ -1 -1 -1 -1 -1 -1 -1 ・・・ 作成したマスクを使って書き戻し(store) 5の倍数も同様 15の倍数は、3の倍数マスクと5の倍数マスクのANDをとる