【JMH】Windows環境で実行するコアを指定してベンチマークのスコアを安定させたかった話

TL;DR

  • JMHベンチマークスコアが安定しなかった
    • (正確に特定はしていないが)全体の実行に5時間かかる内容であるため、途中でバックグラウンド処理が走った結果が原因と推定
  • start /affinity ${マスク} ${呼び出すプログラムと引数}とすることで、ベンチマークを実行するコアを限定することで、少なくともベンチマーク中のCPU使用率は安定すると思われる

本文

背景と課題

最近ProjectMapK/FastKFunctionとして、KFunction(Kotlinのリフレクションにおける関数)を高速呼び出しするライブラリを作成しています。

github.com qiita.com

このライブラリのウリは高速性であり、その証明のためにJMHベンチマークを作成しました。
一方、このベンチマークで触っていない部分の結果までそれなりにブレることがしばしば有りました。

このベンチマークは実行に5時間以上かかるため、気軽に何度も実行できません。
また、そもそもそうやって結果がブレるのであればベンチマークの信頼性も揺らいでしまいます。

ということで、何とかこの結果を安定させられないものか検討していました。

対策

Windowsでは、start /affinity ${マスク} ${呼び出すプログラムと引数}とすることで、プログラムを利用するコアとその数を制限することができます。
例えば、今回行うベンチマークのコマンドはstart /affinity 00000111 gradle jmh --no-daemonというようになります。

00000111がマスクで、1を指定すると該当するコアがプロセスに占有されます。
gradle ...以降は、実行するプログラムに関する指定です。

指定の有無でCPU使用率がどうなるかをタスクマネージャーで見た様子が以下です。
指定無しでは使用率が100%に張り付かないコアが出ている一方、指定有りでは綺麗に3コアの使用率が張り付いています。

f:id:wrongwrongwrongwrong163377:20210109235749p:plain
/affinity無し
f:id:wrongwrongwrongwrong163377:20210110000101p:plain
/affinity有り

ベンチマークが利用するスレッド数などを変更して確認した所、スレッド数 = 指定コア数であれば指定したコアの利用率が100%に張り付き、スレッド数の方が少ない場合利用が100%に張り付かなくなるようでした。
ベンチマークスコアの安定性という観点では、CPU周波数の変動なども加味すると使用率が安定していた方が良いはずなので、指定有りで実行した方がスコアが安定すると言えると思います(本当に安定するのかは確認できていません!)。

参考にさせて頂いた記事

www.atmarkit.co.jp ss64.com