2022年6月5日日曜日

gcc: インライン展開の効果

発端はやはりmotion。

ループ中の関数呼び出しを行った後のif文分岐で処理をキャンセルしている形が目についたので、これってかなり不利だよなぁとか引っかかってたので処理のオーバーヘッドがどの程度影響するのか確認してみました。

最初はソースを書き換えることを考えたのですが、この辺はコンパイラがどのような実行コードのするのか決めることができます。c言語でもinlineという指定があるのである程度指示することができます。ある程度と言う意味は、現状のc/c++コンパイラはinline修飾子をヒントとして用いているのでinline修飾子だけでは確定させることができません。

前置きはこのぐらいで、本題へ。

用意したのは単純なループと関数定義

#include <stdio.h>
#include <time.h>

int proc1(int i){
        i++;
        return(i);
}

inline static int iproc1(int i){
        i++;
        return(i);
}

int main(int argc, char *argv[]) {
        int i, w;
        long t0, t1, t2;
        double s;

        t0=clock();

        w=1;
        for(i=0; i<100; i++){
                w=proc1(w);
        }
        t1=clock();

        w=1;
        for(i=0; i<100; i++){
                w=iproc1(w);
        }
        t2=clock();

        s=(double)(t1 - t0) / CLOCKS_PER_SEC;
        printf("%f sec\n", s);

        s=(double)(t2 - t1) / CLOCKS_PER_SEC;
        printf("%f sec\n", s);

        return 0;
}

インターバルの時間計測の比較で実行してみてみると…

pi@rasp2b:~/ctest $ gcc inlinetest.c -o inlinetest
pi@rasp2b:~/ctest $ ls -l
合計 12
-rwxr-xr-x 1 pi pi 8152  6月  4 14:47 inlinetest
-rw-r--r-- 1 pi pi  485  6月  4 14:47 inlinetest.c
pi@rasp2b:~/ctest $ ./inlinetest
0.000023 sec
0.000013 sec

確かに早い結果は得られたが、この桁ではクロック変動や誤差の範囲w

ループ回数をもう少し増やしてみましょう。ゼロを4つ増やして…

pi@rasp2b:~/ctest $ gcc inlinetest.c -o inlinetest
pi@rasp2b:~/ctest $ ls -l
合計 12
-rwxr-xr-x 1 pi pi 8152  6月  4 14:56 inlinetest
-rw-r--r-- 1 pi pi  493  6月  4 14:56 inlinetest.c
pi@rasp2b:~/ctest $ ./inlinetest
0.050699 sec
0.051429 sec
pi@rasp2b:~/ctest $ ./inlinetest
0.044166 sec
0.042028 sec
pi@rasp2b:~/ctest $ ./inlinetest
0.048412 sec
0.044907 sec

最初に遅くなっているときはクロッキング時のオーバーヘッドがこれだけかかっているという結果でしょう。raspberry pi 2辺りの動作クロックのオーバーヘッドが結構大きいのですが、それだけで結果がひっくり返りました。

現実問題として、秒単位の処理で高速化のためにインライン展開を利用するのは効果は非常に薄いです。関数の引数の数で差はでるとしても、100万回の呼び出しでも4ms程度の差しかでない。

結局、サンプルコードも書いてみたものの、効果がほとんどないという結果は喜ぶべきか悔しがるべきか、悩みます。

ことの発端は、ボトルネックとなっている撮影開始時の処理で、処理が1s以上程度処理落ちしている様で、それを何とかしたいと思ったから。

現状ではminimum_motion_framesとpre_captureの値で内部バッファが確保され、動作検知をした時点でバッファの画像をエンコードを行い、処理が終わるまでほかの処理が行われません。(実装を変えれば…)

しかしそのバッファを0になるように設定してもどうしても1秒程度のラグが発生してしまっているために何とかならないかと。一番マズそうなのは、pipeでffmpegエンコードしている部分だとは思いますが…

extpipeさせている理由は単純で記録される動画のファイルサイズを小さくしたいというだけなのですが、現状だとtmpf上に一回保存した後、soundと結合させたりしていることを考えると、動画も再エンコードさせてもいいのかもしれないが、無駄にデジタル劣化させるのもなぁと言ったところ。

 

 

0 件のコメント:

コメントを投稿