STM32 計算速度データ

2019年09月12日 カテゴリー:STM32 エフェクター



デジタルエフェクターでリアルタイムにデジタル信号処理をする場合、計算が間に合わずまともな音が出なくなるという可能性があります。そこで、様々な計算方法についてどの程度処理時間がかかるのか確認しておくことにしました。使ったのはNUCLEO-F401REで、FPU(浮動小数点演算処理装置)を備えています。開発環境はSTM32CubeIDE(1.0.2)です。



経過時間を確認するには、CPUのクロックサイクルのカウント数(以下サイクル数)を利用すると便利です。下記の記載をしておくと、サイクル数を確認できるようになります。(参考ページ→ARMのData Watchpoint and Trace Unitを使って処理時間計測をしてみよう
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

そして下記のようにコードを書きます。「DWT->CYCCNT」に現在のサイクル数が入ります。コンパイル時に最適化されないように、volatileを入れ、サイクル数を変数として使うことにします。
volatile uint32_t start = 0;
volatile uint32_t stop = 0;
volatile uint32_t ivar[50] = {};
volatile uint32_t cnt[50] = {};

start = DWT->CYCCNT;   // 開始時サイクル数
ivar[0] = start;       // 計測したい処理
stop = DWT->CYCCNT;    // 終了時サイクル数
cnt[0] = stop - start; // 処理にかかったサイクル数

上記「変数の代入」を基準として、処理を追加した場合にどのぐらいサイクル数が増えるかを確認しました。例えば乗算の場合、「ivar[1] = start * stop;」のようにして、変数の乗算を1つ追加するといった具合です。定数を使うと事前に計算されてしまう場合があるため、全て変数を使います。

コンパイル時の最適化オプション「O0(最適化なし)」と「Ofast(最速最適化)」での違いも確認します。1000回平均値ですが結果が結構変わるときがあり、あまり正確ではなさそうです。



<32ビット整数(uint32_t)>

サイクル数(O0)サイクル数(Ofast)
何もしない84
代入(=)※基準167
加算(+) 減算(-) 乗算(*)53
除算(/)97
剰余演算(%)118
各ビット演算(& | ! ^ >> <<)53
変数の呼び出しに数サイクル必要なのか、代入だけで結構時間がかかるようです。剰余演算がそんなに遅くないというのが意外でした。



<32ビット浮動小数点数(float)>

サイクル数(O0)サイクル数(Ofast)
代入(=)※基準167
加算(+) 減算(-) 乗算(*)54
除算(/)1717
定数での除算の場合は最適化で乗算と同じ速さになりますが、変数だと遅いままとなってしまいます。

C言語標準ライブラリmath.hにある数学の関数については以下の通りです。
サイクル数(O0)サイクル数(Ofast)
sqrtf5116
logf189189
expf216207
powf565571
sinf8279
sinhf286283
atanf189178
デシベル計算に使うpowfがかなり遅いので、ルックアップテーブルの利用を考える必要がありそうです。

CMSIS-DSPライブラリを導入し、とりあえず2つの関数を使ってみました。(参考ページ→STM32 CubeIDE環境で、CMSIS-DSPを使う方法
サイクル数(O0)サイクル数(Ofast)
arm_sqrt_f329113
arm_sin_f325652
今後、BiQuadフィルタやフーリエ変換等の活用について検討したいと思います。