本当は怖いHPC

HPC屋の趣味&実益ブログ

流体力学の勉強(1)

ゆえあって流体力学の勉強をしています. 大学では粒子法の分散プログラム作成の自動化などをやっていたりしたのですが,肝心のシミュレーションの具体的な中身についてはわからないままだという気がかりがずっとあったので,思い切って勉強することにしました.

目標は,

  • とりあえず基礎的な流体力学の数値シミュレーションを自分でかけるようになること
  • 最近出版されたデータ同化(Data Assimilation)の本の内容を(少なくとも)追えるようになること
  • 粒子法のアルゴリズムを理解できるようになること

です.

とりあえずは教科書として以下の2冊を利用しています.後日書きますが,理論面として購入した前者の教科書は全体的にわかりにくい気がしているので,また別の本を導入するかもしれません.

演習で学ぶ「流体の力学」入門 第2版

演習で学ぶ「流体の力学」入門 第2版

Pythonで学ぶ流体力学の数値計算法

Pythonで学ぶ流体力学の数値計算法

x86-64のCalling Convention

x86-64(AMD64)のCalling Conventionについてメモ.ネット上に資料はたくさんありますが,断片的だったり,一覧性が低かったり,互いに矛盾しているように見えたりしたので自分でまとめることにしました.

(と言っておきながら,Agner Fogさんの資料*1のp.10 Register Usage に全部書いてあったので,それを読めば良いと思います)

Calling Conventionとは

関数を呼び出すとき,機械語レベルでは,レジスタをどう使うかが重要になります.スタックは関数ごとに独立してメモリを利用できますが,レジスタは共有資源なので関数の呼び出し元(caller)と呼び出し先(callee)で協調して利用する必要があります.

ポイントとしては,

  • 引数をどうやって渡すか
  • 戻り値をどうやって返すか
  • それ以外のレジスタをどう使うか(レジスタがVolatileかどうか)

があります.

前述のようにレジスタは共有資源なので,利用方法について合意する必要があります.「Volatileかどうか」とは,その取り決めのことです. 以下の2通りのやり方があります(C言語の volatile とは関係ない).

  • Caller-save (= volatile or scratch) :callee が自由に使って良い(破壊して良い).よって,必要であればCallerが自分で内容を保存しておく責任がある
  • Callee-save (=non-volatile):callee側が使って良いが,callerから見て呼び出し前と呼び出し後で値が同じである必要がある.言い換えると,calleeが現状復帰する責任がある

呼び出し規約の種類

x86-64で用いられる呼び出し規約は大きく分けて2種類あります.

  • System V AMD64 ABI - 主に Solaris, Linux, FreeBSD, macOS で用いられる.
  • Microsoft x64 calling convention - Windowsで用いられる.(vectorcall というのもあるが,これはMS-x64の拡張)

呼び出し規約の詳細

MS-x86とSysVの共通事項

  • ある個数の引数まではレジスタで渡す,レジスタに載らない引数はスタックで渡す.スタックに詰む順番は右から左 (RTL)

System V AMD64 ABI

  • 関数呼び出し
    • 整数 or ポインタ RDI, RSI, RDX, RCX, R8, R9
    • 不動小数点 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7
  • 戻り値
    • 整数64ビットまでRAX
    • 整数128ビットまでRAX & RDX
    • 不動小数点 XMM0 and XMM1
  • caller/callee-save
    • RBX, RSP, RBP, and R12–R15 : non-volatile (= callee save)
    • RAX, RCX, RDX, RSI, RDI, R8-R11 XMM0-XMM15, YMM0-YMM15, ZMM0-ZMM31: volatile (= caller save)
  • システムコールでは RCX の代わりに R10 を使用

Microsoft x64 calling convention

  • 関数呼び出
    • 整数 RCX, RDX, R8, R9
    • 不動小数点 XMM0, XMM1, XMM2, XMM3
  • 戻り値 = RAX or XMM0
  • caller/callee-save
    • RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, XMM6, XMM7 : non-volatile (= callee save)
    • RAX, RCX, RDX, R8-R11, XMM0-XMM5, (YMM, ZMMレジスタ,ただしXMM6-XMM15の下位128ビット以外) volatile (=caller-save)

参考文献

  • Wikipedia X86 Calling Conventions*2
  • Calling conventions for different C++ compilers and operating systems *3

UCX1.8リリース

UCX1.8がリリースされました。

全体的には堅実で地味なリリースですが、個人的に興味あるものをいくつか取り上げるとすると

  • ROCm環境サポートの充実
  • CUDA向けのさらなる最適化
  • RDMA memory registration

でしょうか。それぞれを簡単に紹介します:

ROCmは、AMD製GPUにおけるGPGPUプログラミング環境です。要するにAMD版CUDAです(厳密には、ROCmがCUDA Runtimeとドライバ群相当、HIPがCUDAプログラミングモデル+コンパイラ相当だと思います)。NVIDIAに比べるとソフトウェア環境で大幅な遅れを取っているAMDですが、ソフトウェアエコシステム一式をオープンソースで開発中です。RDMAを中心としたネットワークライブラリは、UCXを基本としてサポートされていくようです。

RDMAのMemory Registrationの高速化は、地味に嬉しいケースがあると思います。そもそもRDMA通信におけるRegistrationとは、CPUのホストメモリをRDMAように用いるための事前処理のことです。これは地味に時間がかかる処理で、以前に私が関わったPFNにおける試作Allreduceライブラリでは、事前にメモリプールを作ってRegistrationを前処理しておくことでオーバーヘッドを回避しました。この処理がマルチスレッドで実装できれば嬉しいかもしれません。

【広告】