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を前処理しておくことでオーバーヘッドを回避しました。この処理がマルチスレッドで実装できれば嬉しいかもしれません。
DockerfileのARGとFROMの順序と変数のスコープ
Dockerfileの中のFROM
とARG
コマンドの位置関係について、ちょっとハマることがあったのでまとめておきます。
このあたりは、英語でも日本語でも直接的にはっきり書いてあるドキュメントがほとんどないので調べるのに時間がかかりました。
なお、実験は MacOS上の Docker version 19.03.8, build afacb8b
で行っています
問題
まず、以下の例を見てみます。
# Dockerfile ARG UBUNTU_VER FROM ubuntu:${UBUNTU_VER} RUN echo UBUNTU_VER=$UBUNTU_VER
$ docker build . --build-arg UBUNTU_VER=18.04 --no-cache Sending build context to Docker daemon 2.048kB Step 1/3 : ARG UBUNTU_VER Step 2/3 : FROM ubuntu:${UBUNTU_VER} ---> 4e5021d210f6 Step 3/3 : RUN echo UBUNTU_VER=$UBUNTU_VER ---> Running in b1db86ff5314 UBUNTU_VER= Removing intermediate container b1db86ff5314 ---> 212d057cc765 Successfully built 212d057cc765
冒頭に ARG
で定義した UBUNTU_VER
という変数を、コマンドラインから --build-arg
を使って代入しています。ここで、FROM
の行では正しく値が設定されて ubuntu:18.04
というイメージが使われているのに対し、3行目の RUN
コマンドの行では値が代入されていません。
どういうことでしょうか? ARG
は、FROMより前に書いてはいけないのでしょうか?しかし、FROM
コマンドで変数を使うためには、FROM
より前にARG
を書く必要があります。そもそも、FROM
では変数を使うことができているのに、その後のRUNでは空(未定義)なのはなぜでしょうか?
理由の説明
これには理由があります。まず、 FROM
コマンドは、新しいステージ(build stage)を作成し、その次の行から スコープ を形成します。普通のプログラムで言う変数のスコープと同じです。また FROM
より前に出現する ARG
は、グローバルスコープ(globally-scoped ARG
)となります。同様に、普通の関数でいうグローバル変数のようなものです。
次に、グローバルスコープの ARG
は、それぞれの FROM
スコープへは自動的には引き継がれません。スコープ毎に ARG
コマンドを使って宣言する必要があります。また、その際にデフォルト値を変更することもできます。
ということで、それを実験するために以下のようなDockerfileをビルドしてみます。
# Dockerfile # グローバルスコープのARG ARG VER=18.04 FROM ubuntu:${VER} as base1 # (1) ローカルスコープARG宣言無し RUN echo 1 VER=${VER} FROM ubuntu:${VER} as base2 # (2) ローカルスコープのARG宣言(デフォルト値なし) ARG VER RUN echo 2 VER=${VER} FROM ubuntu:${VER} as base3 # (3) ローカルスコープのARG宣言(デフォルト値あり) ARG VER="In 3rd FROM" RUN echo 3 VER=${VER} FROM ubuntu:${VER} as base4 # (4) ローカルスコープのARG宣言(再びデフォルト値なし) ARG VER RUN echo 4 VER=${VER}
このDockerfileをビルドすると、下のようになります。(不要な部分を省略済)
Sending build context to Docker daemon 3.584kB Step 1/12 : ARG VER=18.04 Step 2/12 : FROM ubuntu:${VER} as base1 # <-- (0) ---> 4e5021d210f6 Step 3/12 : RUN echo 1 VER=${VER} ---> Running in a954660d91fd 1 VER= # <-- (1) Step 6/12 : RUN echo 2 VER=${VER} ---> Running in a8ac09e221dc 2 VER=18.04 # <-- (2) Step 9/12 : RUN echo 3 VER=${VER} ---> Running in 79466895adae 3 VER=In 3rd FROM # <-- (3) Step 12/12 : RUN echo 4 VER=${VER} ---> Running in 5ebfe419e434 4 VER=18.04 # <-- (4) Successfully built c32c9a07c503
ここで起こっていることを整理してみます。
- まず、Dockerfileの冒頭でグローバルスコープの
VER
を定義します。これにより、FROM
コマンドで変数VER
が使えるようになります(出力の(0)
)。以降のすべてのFROM
コマンドでVER
が使えます。 - 次に、
FROM
で作成されたスコープの中で変数宣言なしでVER
を使ってみると、中身は空です(出力の(1)
)。 - 新しく作った別のスコープで、デフォルト値無しで
VER
を宣言します。すると、VER
変数が有効になり、値はグローバルスコープの定義を引き継ぎます(出力の(2)
)。 - さらに新しく作った別のスコープでデフォルト値付きで変数宣言をすると、
VER
は宣言された値に設定されます(出力の `(3))。 - また新しくスコープを作り、再び「デフォルト値なしの
ARG
宣言」をしてみると、値はグローバルスコープのものになります。つまり、直前のスコープで設定した値は破棄されます。
まとめ
Dockerfileの中で FROM
コマンドは新しいスコープを作り、その中で宣言された ARG
は、そのローカルスコープの中のみで有効です。最初の FROM
より前に宣言した ARG
はグローバルスコープとなり、 FROM
コマンド自体の中で使うことができますが、ローカルスコープの中では継承されません。ローカルスコープの中で変数を使いたい場合は、グローバルスコープの宣言があったとしても、再度 ARG
で宣言する必要があります。また、ローカルスコープで設定した値は、他のローカルスコープには引き継がれません。
参考文献
C++ conceptsを試してみた (1)
C++20 から導入されるConceptsを試してみました。
cpp_akira さんがConceptの解説を書かれている[1]ので、自分なりに咀嚼して試してみます。
ビルド方法
現時点(2019年10月)で、Conceptを利用したプログラムをビルドするには、g++9以降が必要です。gccとclangのC++機能実装状況 (gcc[2], clang[3])によれば、
- gccは実装済みPRが提案されている
- clangは未対応
のようです。MacのHomebrewでインストールされたg++はパッチ適用済みのようですので、これを使います。
実際に、Mac上でConceptを使ったビルドをしてみます。 -std=c++2a
および -fconcepts
のフラグが必要です。
$ g++ -std=c++2a -fconcepts main.cpp
Conceptを使って型の制約を記述する
テンプレート引数の型がメンバ関数を持っている
// https://wandbox.org/permlink/njPaUxLdeDuXa81N // コンセプト Drawable を定義 template <class T> concept Drawable = requires(T& x) { x.draw(); }; // テンプレート引数のクラスが特定のメンバ関数を持っていることを規定する template <Drawable T> void f(T& x) { x.draw(); }
ただし、現時点では <concepts>
ヘッダのincludeを含め、すべての機能が動くわけではないようです。
例:
// [1]より引用 // https://wandbox.org/permlink/G1SAoPNBVIwPYvVk #include <concepts> template <class T, class U> concept EqualityComparable = requires (T a, U b) { {a == b} -> std::convertible_to<bool>; // 式の戻り値型も制約できる (直接の戻り値型は指定できない) };
引き続き、詳細な文法等の調査をしていこうと思います。
参考文献/リンク
- [1] コンセプト - cpprefjp C++日本語リファレンス
- [2] C++ Standards Support in GCC - GNU Project - Free Software Foundation (FSF)
- [3] Clang - C++17, C++14, C++11 and C++98 Status
変更履歴
- 誤字修正 thanks to @takeda25 さん