lameのSPU化

やっとフレームエンコード処理のSPU化を果たせたのでパッチをアップします。こちら。ただし全然速くないです。そのあたりの結果と考察は最後に。

修正のポイント

今回はlame_encode_frame関数以後の処理をSPU化しましたが、SPU化するときの最大の問題はLSの小ささでした。256KBのLSにコード、データ、スタック領域を納めるため、以下の修正を加えてあります。

  • 個人的に使わない部分の削除
    • VBR/ABRモード関係の処理
    • 物理音響モデルの処理(PSY_GPSYCHO処理)
  • 不要な部分の削除
    • printfの削除
    • mallocの削除
  • テーブル処理の削除
  • コンパイルのビルドオプション
    • -O2の指定
    • --short-doubleの指定

今回の作業はまさにLSとの戦いです。一般的なコードは潤沢なメモリを想定しているので、何10KB、何100KBの領域を平気で確保しますが、LSはそんなに大きくありません。まずはリンクエラーがでないようにし、spu-nmコマンドで、不要な関数はリンクされていないか?誰がいちばんメモリを消費しているか?を確認します。また_endと__stackの間のサイズを確認し、十分なスタック領域が残っていることも確認します。

コンパイルオプションは-O2がもっとも小さくなりますが、Cのソースと実行順番がかなり変わるのでデバッグは辛いです。速度のためにはしかたないですが。

結果

さて、肝心の実行速度ですが、全然速くないです。まずSPU化したlameの実行結果です。テストのWAVファイルはスターウォーズのオープニングテーマ(3秒)です。

262093868740: (295521003): LAME version 3.96.1 (http://lame.sourceforge.net/)
262093893047: (295543938): Using polyphase lowpass filter, transition band: 1724 9 Hz - 17782 Hz
262093903776: (295554444): Encoding starwars.wav to starwars.wav.mp3
262093911369: (295561809): Encoding as 44.1 kHz 128 kbps j-stereo MPEG-1 Layer I II (11x) qval=3
262094040867: (295689851):     Frame          |  CPU time/estim | REAL time/esti m | play/CPU |    ETA
262094045298: (295694271):      0/       ( 0%)|    0:00/     :  |    0:00/     :   |         x|     :
262094401357: (296049656):      0/117    ( 0%)|    0:00/    0:00|    0:00/    0: 00|   0.0000x|    0:00
263221451757: (1422481065):     50/117    (43%)|    0:00/    0:00|    0:00/    0 :00|   0.0000x|    0:00
264597462705: (2799048944):    100/117    (85%)|    0:00/    0:00|    0:00/    0 :00|   261.22x|    0:00
265035811980: (3237571151):    114/117    (97%)|    0:00/    0:00|    0:00/    0 :00|   148.90x|    0:00
265035909077: (3237666014): Writing LAME Tag...done
265035914713: (3237671604): ReplayGain: -7.5dB
(265035914713-262093868740)/3000000000=0.98 [sec]
*1


約3倍速です。コンソール上の表示はあてにならないっぽいです。いっぽうPPC版では

12726689669863: (7135824134): LAME version 3.96.1 (http://lame.sourceforge.net/)
12726689693551: (7135846528): Using polyphase lowpass filter, transition band: 17249 Hz - 17782 Hz
12726689703736: (7135856569): Encoding /root/lame-3.96.1.spu7/frontend/starwars.wav to starwars.wav.mp3
12726689712901: (7135865506): Encoding as 44.1 kHz 128 kbps j-stereo MPEG-1 Layer III (11x) qval=3
12726689787056: (7135938937):     Frame          |  CPU time/estim | REAL time/estim | play/CPU |    ETA
12726689791487: (7135943357):      0/       ( 0%)|    0:00/     :  |    0:00/     :  |         x| :
12726690181923: (7136332967):      0/117    ( 0%)|    0:00/    0:00|    0:00/    0:00|   0.0000x|    0:00
12727001615234: (7441693998):     50/117    (43%)|    0:00/    0:00|    0:00/    0:00|   13.061x|    0:00
12727358704609: (7790488171):    100/117    (85%)|    0:00/    0:00|    0:00/    0:00|   12.439x|    0:00
12727472338355: (7901578357):    114/117    (97%)|    0:00/    0:00|    0:00/    0:00|   12.408x|    0:00
12727472422007: (7901660556): Writing LAME Tag...done
12727472427515: (7901666022): ReplayGain: -7.5dB
(12727472427515-12726689669863)/3000000000=0.26 [sec]

約11.5倍速です。こちらはコンソール上の表示とほぼ同じです。

考察

いまいち良い結果が出ませんでしたが、原因としては以下の点が考えられます。

  • テーブル処理の削除

まずはLSに入れることを優先し、テーブル処理を行っていません。これは速度の点から見るとマイナスです。

  • PPUとSPUでのデータ受渡しの最適化がまったくされていない。

PPUとSPUの間ではPCMデータと、エンコードデータのやりとりを行っていますが、単純に転送終了まで待っていますので無駄が発生しています。

今後は上記点の改善を試みたうえで、SIMD化やPPUとの並列処理を検討してみます。とはいっても4倍の差を埋めれる程速くできるか?ちと自信ないです。

*1:ログの一番左の数字が起動してからのCPUサイクルで、3GHzでの動作を想定しています。PS3は3.2GHz動作ですが、過度の期待を抱かぬようこの程度で考えておきます。