openFrameworksパフォーマンスチューニング

  • 101
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

ツール等

Instruments.app

Xcodeに付属のプロファイラ

アプリの稼働中にどの部分がボトルネックになっているかを確認できたり、頑張ればメモリリークも発見できる時がある。

自分が説明するのもアレなので詳しくはこことか

  • 得に何もしなくてもXcodeのメニューから起動できるので楽チン
  • Releaseビルドになっていると関数名のシンボルが消えて何のコッチャになってしまうので注意 (最近はRelease/Debugの速度もかわらないのでずっとDebugでもいいかな、と思ってしまいます)

基本的には:

  • Product > Profile ⌘I で起動
  • Time Profilerを選択
  • 左側のCall Treeのリストの中にあるチェックボックスを 上から4つ入れる
  • メソッド/関数の処理負荷の高い順にリストがソートされるので眺める

という流れです

ofxTimeMeasurements

https://github.com/armadillu/ofxTimeMeasurements

導入が楽で素朴な機能のいい奴

  • 単純な仕組みなので余分なオーバーヘッドが入りこむ余地がない
  • 関数の時間など計測する時に明示的にSTART/STOPのマクロを仕込まないといけない、が、逆に変な挙動もないのでわかりやすい
  • ただSTART/STOP間の時間をはかってるだけなのでDebug/Releaseビルド関係なく計測できる
  • FlashとかThree.jsの左上のアレみたいな機能がついててればもっといいのだが

自力

void ofApp::draw()
{
    // ....

    stringstream ss;
    ss << "framerate: " << ofToString(ofGetFrameRate(), 0);
    ofDrawBitmapString(ss.str(), 10, 20);
}

みたいな

  • 何の導入もいらないので一番楽
  • draw/updateの境なく1フレーム単位でのレートになるのでofxTimeMeasurementsと比較して切り分けは多少雑か
  • ofSetWindowTitle(ofToString(ofGetFrameRate(), 0)); というのもよくやるけど 60fps以上で動かす時にこれが原因でフレームレートが激落ち君になったことがあるので注意 (おそらくOS側UIアップデートでウインドウタイトル変更の処理をブロックしてしまうタイミングがあるのだと思われます)

方針

とりあえず自力でやるのが手間もなくていいと思いますが、ofxTimeMeasurements導入も手間としてはそんなにかわらないので最初から入れててもいいかな… という気もします。

注意点としては ofSetVerticalSync(true); になっていると処理がどんなに早く終わってもディスプレイの垂直同期を待ってからの描画になるので60fpsで頭打ちになります。

この場合十分に処理が早いといいのですが、何かの問題で1フレームあたりの処理にコンスタントに 1000ms/60 = 16.6666ms 以上かかってしまった場合、本来描画するはずの垂直同期に間にあわなくなり最悪次の垂直同期まで待つことになるので急にレートが30fpsまで落ちることがあります。(最近ないけど、昔はよくありました)

なので見た目のブラッシュアップまでも行かないベースシステムの開発中の時は:

void ofApp::setup()
{
    ofSetVerticalSync(false);
    ofSetFrameRate(0);

    // ...
}

のような感じで垂直同期OFF、フレームレート上限無しのフリーランの状態で開発するのが処理が今どれぐらいの負荷になっているのかがfpsを見るだけで大体わかっていいので最近のマイブームです。

見た目的な部分に入ってきた場合には垂直同期が入ってないとティアリングがおきるので入れといてください

oFローカルなパフォーマンスTIPS

  • ofGetElapsedTime() は呼びすぎると結構処理が重い。フレームあたりで一意の時間があればいいだけであれば単純にグローバル変数にキャッシュしてそれを使ったほうがいい
  • ofToString()ofSplitString()等々も内部はstd::stringstreamを使ってたりするので結構重い。sscanf()は比較的高速なのでそっちにするとよい
  • ofImage::getColor() / ofImage::setColor() はofColorのコピーをやりとしているので辛い。ofImage::getPixels()でポインタをもらってガリガリやったほうが倍ぐらい高速
  • ofMatrix4x4も地味に最適化されてないので遅い部類。以前mat4 * vec3の計算を大量にしなければいけない時はその部分だけlibSIMDx86に置き換えたりしましたがかなり高速化できました。

もっとあったっけな、思い出したら追記します…