さかなソフトブログ

プログラミングやソフトウェア開発に関する情報

テスト

Google Testの実行速度が20倍に! gtest-parallelの使い方

更新日:

最近C++のインテグレーションテストでGoogle Testを使っていますが、ターゲットコードの性質上、コード内部でsleepを入れることが多くてCPUの占有時間はそれ程でも無いですが素にgtestを走らせるとかなりの時間が掛かっていました。

そこで並列実行系のテスト出来ないか調べたところ、Google公式からgtest-parallelというツールが提供されていてこれが今回はカチッと嵌まって劇的に速度向上したので使い方を紹介しながら結果を振りかえります。

gtest-parallelとは

ツールの名の通り、Google Testを並列実行してくれるツールです。仕組みは挙動を見た限りでは非常にシンプルで、gtest-parallelはgtestの--gtest_filterを用いてテストを個別に並列実行させ、最終的にテスト結果を集計する様になっています。

gtest-parallelの使い方

gtest-parallelはPython2系スクリプトとなっており、gtest-parallelを実行することで使用出来ます:

$ git clone https://github.com/google/gtest-parallel.git
$ python gtest-parallel/gtest-parallel /path/to

--helpオプションでヘルプが参照出来るので日本語訳します:

gtest-parallel [options] binary [binary ...] -- [additional args]

オプション:
  -h, --help
                ヘルプを表示します。
  -d OUTPUT_DIR, --output_dir=OUTPUT_DIR
                テストログを出力するディレクトリを指定します。ログは指定したディレクトリより
                `gtest-parallel-logs/` フォルダが配置されます。例えば `--output_dir=/tmp` だと
                `/tmp/gtest-parallel-logs/` フォルダに出力されます。
  -r REPEAT, --repeat=REPEAT
                全テストの実行回数を指定します。
  --retry_failed=RETRY_FAILED
                失敗したテストのリトライ回数を指定します。
  --failed
                失敗したテストと新しいテストケースのみ実行します。
  -w WORKERS, --workers=WORKERS
                同時に生成するワーカープロセス数を指定します。
  --gtest_color=GTEST_COLOR
                カラー出力を指定します。
  --gtest_filter=GTEST_FILTER
                テストケースのフィルタリングを指定します。
  --gtest_also_run_disabled_tests
                無効化されているテストも実行します。
  --print_test_times
                テスト実行後にそれぞれのテストケースの実行時間を表示します。
  --shard_count=SHARD_COUNT
                合計シャード数を指定します。
                複数のマシンでシャーディングテストを行う為に指定します。
  --shard_index=SHARD_INDEX
                0から始まるシャードのインデックスを指定します。
                複数のマシンでシャーディングテストを行う為に指定します。
  --dump_json_test_results=DUMP_JSON_TEST_RESULTS
                テスト結果をJSONフォーマットで保存します。
                フォーマットは以下のURLを参照してください:
                https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md
  --timeout=TIMEOUT
                指定時間を経過するとに残りの実行中プロセスは全て中断します(秒)。
  --serialize_test_cases
                同じテストケースを同時に実行しないようにします。

この中で必ず指定しそうなのはワーカー数で、コア数を大きく上回る数で指定するのが良いようです。自分のPCでは64〜128辺りで一番効率よく並列実行出来ていました。

実行結果

今回gtest-parallelで速度測定したテストターゲットは342 tests from 29 test cases で先ずは単一実行して速度実行すると、

real	5m57.741s
user	0m0.410s
sys	0m0.510s

となり、real 5m57sのわりにはuser 0.41sで殆どCPUを使っておらずターゲットコードはsleep等が入っているので通しで実行してしまうとどうしても時間が掛かっています。

これに対しgtest-parallelを試します。今回はワーカー数を128、 python gtest-parallel -w 128 /path/to/target_test で実行すると、

real	0m17.274s
user	0m6.538s
sys	0m4.565s

となり、実行時間はなんと20倍強!今までのテスト実行時間はなんだったんだwという速度差がついて大満足の結果となりました。

gtest-parallelを使うときに対処しておきたいこと

gtestを最新にしておく

gtestの初期化がテストケース数分行われるためにgtestで例外が出ることがありました。

2018/2/14現在stableの1.8.0よりmasterブランチの最新版の方が安定していたのでそちらを利用した方が良いです

テストケースを最小単位に分割しておく

逐次実行の場合はトータルの実行時間の効率の為にいくつかのテストを一纏めにしたりすることもあるかと思いますが、gtest-parallelの場合、各テストケースが並列実行の基本単位になるので幾ら並列実行したとしてもテストケース中の最長時間より実行速度が速くなることはありません

少々トータルのテスト時間が増えたとしても、TEST_P等を利用してテストケースをなるべく分割して1テスト辺りのテスト時間を短縮することでgtest-parallelのテスト時間も短縮することが可能になります。

gtest-parallelは使った方が良い

というわけで使わない理由が無さそうなgtest-parallel。サクサクとテスト実行を進めてストレスフリーな開発が出来ると良いですね:)

正方形336

正方形336

-テスト
-,

Copyright© さかなソフトブログ , 2019 All Rights Reserved.