Codec 2 を試してみる(17-Jan-2019)の続編的な話。あれからCodec 2に700Dモードに加え、LPCNetを使用したFreeDV 2020モードが利用できるようになっています。c2enc/c2decではなくlpcnet_enc/lpcnet_decを使うところから、Codec 2とは別系統と考えるべきかもしれませんが。
このLPCNet(FreeDV 2020)、使うためにはAVX必須と言われていてSSEじゃ駄目なんですかという疑問があり、SSEによるベクトル化を試してみました。
♪
LPCNetを使うには、Codec 2のGitHubリポジトリに書かれている手順(Codec 2→LPCNet→再度Codec 2のビルドを行う)で基本的には問題ないものの、OpenBSD上でビルドする際はcmake -DDISABLE_CPU_OPTIMIZATION=ON -DAVX=ON -DCODEC2_BUILD_DIR=/path/to/codec2/build_openbsd/ ..のように拡張命令セットの指定を自動ではなく手動で設定する必要があります。また、これはOpenBSDに限った話ではないのですが、CODEC2_BUILD_DIRのパスは相対パスではなく絶対パスで記述します。
FreeDV 2020 tests with FreeDV APIの説明には、cat ~/LPCNet/wav/wia.wav | ~/LPCNet/build_linux/src/lpcnet_enc -s | ./ofdm_mod --ts 0.0205 --nc 31 --ldpc 2 --verbose 1 -p 312 | ./ofdm_demod --ts 0.0205 --nc 31 --verbose 1 --ldpc 2 -p 312 | ~/LPCNet/build_linux/src/lpcnet_dec -s | aplay -f S16_LE -r 16000と書かれていますが、OpenBSDで動かす場合aplay〜の部分はaucat -r 16000 -e s16le -i - -h rawとでも読み替えておけば良いでしょう。
♪
とりあえず、lpcnet_encとlpcnet_decでLPCNetへのエンコード/デコードを行うことは分かりました。この部分の処理がどの程度時間がかかるのか、こんなテストをしてみました。
cd /path/to/LPCNet cd build_directory/src time cat ../../wav/all.wav | ./lpcnet_enc -s > test.out time cat test.out | ./lpcnet_dec -s > /dev/null |
LPCNet/wavディレクトリにはテスト用のWAVファイルが色々ありますが、とりあえず一番大きなall.wav(49sec, 16000Hz, 1ch, s16le)を使用します。framboise(A10-7860K)で試した場合、timeコマンドから得られたrealの値はエンコード時が2.567s、デコード時が21.907sとなっていましたのでエンコードよりもデコード処理がかなり重いと言えるでしょう。
これはAVXでの状況です。FreeDV 2020用LPCNetはオリジナルのLPCNetと同様にSSE用のコードは全く入っていないため、Arm NEON用のコードを参考にSSE命令を使った処理(vec_sse.h)を追加して動作を試してみました。
SSEによるベクトル化がきちんとできているかどうかの確認については、test_vecの結果がpassかfailかで判断できます。問題ないことを確認した後に動作速度の測定を行いましたが、どうもSSE 4.1指定の有無でデコード速度が大きく変わるようです。
option | encode | decode |
---|---|---|
-msse | 2.609s | 1m17.046s |
-msse2 | 2.552s | 1m17.323s |
-msse3 | 2.554s | 1m17.117s |
-msse4.1 | 2.550s | 42.694s |
-msse4.2 | 2.561s | 42.697s |
なお、ベクトル化無しでの速度も測ってみましたが、エンコード2.552s、デコード1m42.005sとなったためベクトル化の効果はあるようです。
SSEが高速ではないAMD Bulldozer系の石でぎりぎりの性能は出ているようなので、Intel系の石ならSSEによるベクトル化でも実用になるのかもしれません。ちょっとissueを投げて様子をみてみます。58.60kg(14:25)