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_aar...
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
デバッグの話 / Debugging for Beginners
kaityo256
PRO
9
1k
ビット演算の話 / Let's play with bit operations
kaityo256
PRO
4
280
GNU Makeの使い方 / How to use GNU Make
kaityo256
PRO
15
4.9k
制限ボルツマンマシンの話 / Introduction of RBM
kaityo256
PRO
3
890
論文の読み方 / How to survey
kaityo256
PRO
220
160k
リンゴゲームと貧富の差 / Origin of the disparity of wealth
kaityo256
PRO
13
14k
渡辺研Slackの使い方 / Slack Local Rule
kaityo256
PRO
9
8.6k
時間の矢について / Time's arrow
kaityo256
PRO
12
17k
t-SNEをざっくりと理解 / Overview of t-SNE
kaityo256
PRO
2
1.4k
Other Decks in Programming
See All in Programming
17年周年のWebアプリケーションにTanStack Queryを導入する / Implementing TanStack Query in a 17th Anniversary Web Application
saitolume
0
250
これが俺の”自分戦略” プロセスを楽しんでいこう! - Developers CAREER Boost 2024
niftycorp
PRO
0
190
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
120
PHPで学ぶプログラミングの教訓 / Lessons in Programming Learned through PHP
nrslib
2
210
42 best practices for Symfony, a decade later
tucksaun
1
180
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
740
快速入門可觀測性
blueswen
0
350
Jakarta EE meets AI
ivargrimstad
0
240
tidymodelsによるtidyな生存時間解析 / Japan.R2024
dropout009
1
770
良いユニットテストを書こう
mototakatsu
5
2.1k
Effective Signals in Angular 19+: Rules and Helpers @ngbe2024
manfredsteyer
PRO
0
130
バグを見つけた?それAppleに直してもらおう!
uetyo
0
180
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
95
17k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
127
18k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
The Invisible Side of Design
smashingmag
298
50k
Making Projects Easy
brettharned
116
5.9k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
28
900
Producing Creativity
orderedlist
PRO
341
39k
Code Review Best Practice
trishagee
65
17k
Docker and Python
trallard
42
3.1k
KATA
mclloyd
29
14k
A better future with KSS
kneath
238
17k
StorybookのUI Testing Handbookを読んだ
zakiyama
27
5.3k
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をとる