JUCEアプリケーションのベンチマーク測定
JUCEでオーディオのアプリケーション・プラグインを作るとき、 その性能が大事になってくるケースも多いかと思います。 そこでGoogle Benchmarkを使ったベンチマークの測定が可能なJUCEプロジェクトをCMakeを使って作ります。
今回はプロジェクトの設定にあたって
- 巷にあるテンプレートリポジトリに頼らずやる
- 最小限の設定にして、できるだけシンプルにする
という方針でやります。
事前に用意するもの
参考までに最終コードの動作確認は - macOS 12.0 + clang 13.0.0 - ubuntu 21.10 + gcc 11.2.0 - Windows 10 + Visual Stduio 2019のMSVC
で行いました。
空のGitHubリポジトリの用意
リポジトリにJUCEの追加(ダウンロード)
git submoduleを使ってJUCEのリポジトリをサブモジュールとしてlib/JUCE
ディレクトリに追加します。
# プロジェクトルート (.gitファイルがあるフォルダ) にcdコマンドで事前に移動してください $ git submodule add https://github.com/juce-framework/JUCE lib/JUCE
これでJCUEのmasterブランチが追加されますが、より安定しているリリースバージョン(今回は6.1.2)を 使います。
$ cd lib/JUCE $ git checkout 6.1.2 # "HEAD is now at 46ea87973 JUCE version 6.1.2"と表示されるはず。
ここまでの変更を一旦コミットします。
$ cd ../../ # プロジェクトルートに戻る $ git add . $ git commit -m "Add JUCE 6.1.2"
これでサブモジュールの追加は完了です。
アプリ・プラグイン本体のコードテンプレートの生成
JuceにはProjucerというツールが用意されていて JUCEアプリケーション(ベンチマークではなく本体)の骨組みを簡単に生成できます。 今回はVST3などのオーディオプラグインを作ります。
Projucerの用意
./lib/JUCE/README.md
(要するJUCEリポジトリのREADME.md)に従ってProjucerをビルドをします。
$ cd lib/JUCE # サブモジュールとして追加したJUCEのディレクトリに移動。 $ cmake . -B cmake-build -DCMAKE_BUILD_TYPE=Release -DJUCE_BUILD_EXTRAS=ON # Configureする $ cmake --build cmake-build --config Release --target Projucer # JUCEプロジェクト生成アプリをビルド
.lib/JUCE/cmake-build/extras/Projucer/Projucer_artefacts/Release/
以下にProjucerの実行ファイルが (Projucer.appとかProjucer.exeとかの名前で) 生成されているはずです。
Projucerを使ったコードテンプレートの生成
以下の手順でプラグインのコードテンプレートを生成します。
- Projucerを開きます
- Plug-in->Basicをクリック
- Project Nameを入力
- Path to Modulesから./lib/JUCEを選択
- Create Projectをクリックして適当なフォルダにプロジェクト生成。
- Save and Open in IDEをクリック
これで保存したプロジェクトのSource
ディレクトリ内にPluginEditor.cpp
, PluginEditor.h
, PluginProcessor.cpp
, PluginProcessor.h
の4つのファイルが生成されているはずです。
参考: https://docs.juce.com/master/tutorial_new_projucer_project.html
プラグイン本体のCMakeプロジェクトの作成
まず生成されたSource
ディレクトリ内の4つのファイルをリポジトリの./src
にコピーしてください。
次にプロジェクトルート用とsrcフォルダ以下にそれぞれCMakeLists.txtを作ります。 変更内容はこちらのコミットで見れます。
公式ドキュメント: https://github.com/juce-framework/JUCE/blob/master/docs/CMake%20API.md
参考: https://qiita.com/tomoyanonymous/items/97cae1b83805ebcc2d00
以下のコマンドでプラグインがビルドできます。
$ cmake . -DCMAKE_BUILD_TYPE=Release -B cmake-build $ cmake --build cmake-build --config Release --target JuceBenchmark_Standalone # プラグイン(スタンドアローン版)をビルド
ちなみにビルド可能なターゲットの一覧はgccやclangを使っている場合、$ cmake --build cmake-build --target help
で確認できます。
ベンチマーク対象のクラスを作成
Google Benchmarkでベンチマークをとるには測定対象をC++のクラスとして用意する必要があります。
このコミットでFancyFx
という名前のクラスを作りました。
ベンチマークの作成
プロジェクトルートのCMakeLists.txtにGoogle Benchmarkとその依存ライブラリのGoogle Testを追加します。
# Google Benchmark and its dependency # https://stackoverflow.com/questions/55376111/how-to-build-and-link-google-benchmark-using-cmake-in-windows include(FetchContent) FetchContent_Declare(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.11.0) # 2021年12月での最新バージョン FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0) # 2021年12月での最新バージョン FetchContent_MakeAvailable( googletest googlebenchmark)
同じファイルの最後に以下の様に追記して、これから作る./benchmark
ディレクトリをプロジェクトに追加します。
add_subdirectory(benchmark)
benchmarkディレクトリ内にCMakeLists.txtを作ります。
# JUCEのコンソールアプリとしてCMakeターゲットを追加 juce_add_console_app(JuceBenchmark_Benchmark) # Google Benchmarkをリンク target_link_libraries(JuceBenchmark_Benchmark PUBLIC benchmark) target_compile_definitions(JuceBenchmark_Benchmark PUBLIC JUCE_WEB_BROWSER=0 # いらないものは使用しないための設定 JUCE_USE_CURL=0) # いらないものは使用しないための設定 target_sources(JuceBenchmark_Benchmark PRIVATE Main.cpp) # 測定対象のコード。次に追加します。 # JUCE関連のライブラリをリンク(必要に応じて足したり消したりしてください。) target_link_libraries(JuceBenchmark_Benchmark PUBLIC juce::juce_audio_basics juce::juce_audio_devices juce::juce_audio_formats juce::juce_audio_plugin_client juce::juce_audio_processors juce::juce_audio_utils juce::juce_core juce::juce_data_structures juce::juce_dsp juce::juce_events juce::juce_graphics juce::juce_gui_basics juce::juce_gui_extra ) juce_generate_juce_header(JuceBenchmark_Benchmark)
Main.cppにベンチマークの中身を書きます。 ここは単なる普通のGoogle Benchmarkの使い方です。
#include <JuceHeader.h> #include <benchmark/benchmark.h> #include <cmath> #include "../src/FancyFx.h" //============================================================================== // Constants constexpr double SAMPLE_RATE = 44100.0; constexpr double MAX_TIME_SEC = 2.0; constexpr double PI = 3.14159265359; constexpr double FREQ_A = 440.0; constexpr int NUM_SAMPLE = static_cast<int> (SAMPLE_RATE) * static_cast<int> (MAX_TIME_SEC); constexpr int NUM_CHANNEL = 2; //============================================================================== // benchmark::Fixtureを継承 class FancyFxFixture : public benchmark::Fixture { public: FancyFxFixture() : buffer(NUM_CHANNEL, NUM_SAMPLE), fancy_fx() {} // Google Benchmarkフィクスチャ特有のセットアップ void SetUp (::benchmark::State& state) override { // ベンチマーク用のインプットバッファを用意。 for (int channel = 0; channel < buffer.getNumChannels(); ++channel) { auto* channelData = buffer.getWritePointer (channel); for (int i = 0; i < buffer.getNumSamples(); i++) { // 440 Hz sin wave channelData[i] = channelData[i] * std::sin(2.0 * PI * FREQ_A * i / SAMPLE_RATE); } } } // Google Benchmarkフィクスチャ特有のテアダウン void TearDown (::benchmark::State& state) override { } // 計測対象コード。名前は任意。 void render() { fancy_fx.render (buffer); } //============================================================================== private: juce::AudioBuffer<float> buffer; FancyFx fancy_fx; }; // Google Benchmark独自のお作法 BENCHMARK_F (FancyFxFixture, render) (benchmark::State& state) { for (auto _ : state) { render(); } } BENCHMARK_MAIN();
以下のようにすればベンチマークを実行できます。
$ cmake . -DCMAKE_BUILD_TYPE=Release -B cmake-build # Configureする $ cmake --build cmake-build --config Release --target JuceBenchmark_Benchmark # ベンチマークをビルド $ ./cmake-build/benchmark/JuceBenchmark_Benchmark_artefacts/Release/JuceBenchmark_Benchmark # 実行(拡張子はOSによって違うので適宜調節してください。)
結果の例
Run on (10 X 24.1212 MHz CPU s) CPU Caches: L1 Data 64 KiB (x10) L1 Instruction 128 KiB (x10) L2 Unified 4096 KiB (x5) Load Average: 7.95, 5.90, 4.00 ---------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------- FancyFxFixture/render 17418 ns 17418 ns 38999
トラブルシューティング
コンパイル失敗
コンパイラ, Google Benchmark, Google Testのバージョンの組み合わせ次第で 失敗することがあったのでその辺りを見直すといいかもしれません。
CPUスケーリングの警告
次のような警告が出ることがあります。
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
この場合はドキュメントに従って、 ベンチマーク実行前と後でそれぞれ下の様に設定すれば良い様です。
sudo cpupower frequency-set --governor performance
sudo cpupower frequency-set --governor powersave
まとめ
数字として性能がわかると安心ですね。