2019年3月4日月曜日

浮動小数点数演算の速度比較 mbed OS5 vs TureSTUDIO vs SW4STM32 その2

TrueSTUDIOも比較するのは大変なので、mbed OS5とSW4STM32+STM32Cubeで浮動小数点演算を再度比較してみました。

Github:
https://github.com/ryood/Nucleo_F446_FloatingPoint

mbedのDigitalOut::Write()とHAL_GPIO_WritePin()の差


まずは速度計測に使うGPIOをH/Lするのにかかる時間を比較しました。

mbed

#include "mbed.h"

DigitalOut CheckPin1(D2);

int main() {
 while (true) {
  CheckPin1 = 1;
  CheckPin1 = 0;
 }
}

SW4STM32(一部)

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_GPIO_WritePin(CHK1_GPIO_Port, CHK1_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(CHK1_GPIO_Port, CHK1_Pin, GPIO_PIN_RESET);
  }
  /* USER CODE END 3 */

SW4STM32のコンパイルオプションで最適化を-O2にして測定しました。

Buildオプション

MCU GCC Compiler

-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -D__weak=__attribute__((weak)) -D__packed=__attribute__((__packed__)) -DUSE_HAL_DRIVER -DSTM32F446xx -I../Inc -I../Drivers/STM32F4xx_HAL_Driver/Inc -I../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32F4xx/Include -I../Drivers/CMSIS/Include -O2 -g3 -Wall -fmessage-length=0 -ffunction-sections -c -fmessage-length=0

MCU GCC Linker

-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nosys.specs -specs=nano.specs -T"../STM32F446RETx_FLASH.ld" -Wl,-Map=output.map -Wl,--gc-sections -lm

GPIO Write 処理時間(ns) Clock
mbed OS5 61.1 10.9
HAL 126.2 22.5

意外ですがHALよりmbedの方が速いようです。MPUを180MHz駆動すると1クロックの周期は 1 / 180MHz ≒ 5.6nsとなるので、それを元にClockを計算しました。

SW4STM32のデバッガのDiassemblyでは当該部分は以下のようになっています。

104           HAL_GPIO_WritePin(CHK1_GPIO_Port, CHK1_Pin, GPIO_PIN_SET);
080012f8:   mov     r4, r0
080012fa:   ldr     r3, [sp, #16]
080012fc:   bl      0x8000888 <HAL_GPIO_WritePin>

憶測ですが、HALの呼び出しはかなりコストが高いのかもしれません。STM32CubeにはLLというHALより低レベル(高速化が期待できる)のライブラリもありますが・・・

浮動小数点演算の比較


前回、mbedの空のループが速すぎましたが、float型の変数fvをvolatile指定していませんでした。volataile指定して最適化されないようにして計測し直しました。

mbed

#include "mbed.h"
#include <stdio.h>
#include <math.h>

#define PI_F (3.14159265f)
#define LOOP_N (1000)

DigitalOut CheckPin1(D2);

volatile float buffer[LOOP_N];

int main() {
    while (true) {
  CheckPin1 = 1;
  volatile float fv = 0.0f;
  for (int i = 0; i < LOOP_N; i++) {
   fv += 0.001f;
   //buffer[i] = fv + PI_F; // Add
   //buffer[i] = fv - PI_F; // Sub
   //buffer[i] = fv * PI_F; // Mul
   //buffer[i] = fv / PI_F; // Div
   buffer[i] = sinf(fv);
   //buffer[i] = cosf(fv);
   //buffer[i] = tanf(fv);
   //buffer[i] = expf(fv);
   //buffer[i] = logf(fv);
   //buffer[i] = powf(2.0f, fv);
  }
  CheckPin1 = 0;
    }
}

SW4STM32(一部)

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
 HAL_GPIO_WritePin(CHK1_GPIO_Port, CHK1_Pin, GPIO_PIN_SET);
 volatile float fv = 0.0f;
 for (int i = 0; i < LOOP_N; i++) {
  fv += 0.001f;
  //buffer[i] = fv + PI_F; // Add
  //buffer[i] = fv - PI_F; // Sub
  //buffer[i] = fv * PI_F; // Mul
  //buffer[i] = fv / PI_F; // Div
  buffer[i] = sinf(fv);
  //buffer[i] = cosf(fv);
  //buffer[i] = tanf(fv);
  //buffer[i] = expf(fv);
  //buffer[i] = logf(fv);
  //buffer[i] = powf(2.0f, fv);
 }
 HAL_GPIO_WritePin(CHK1_GPIO_Port, CHK1_Pin, GPIO_PIN_RESET);
  }
  /* USER CODE END 3 */

Buildオプション

MCU GCC Compiler

-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -D__weak=__attribute__((weak)) -D__packed=__attribute__((__packed__)) -DUSE_HAL_DRIVER -DSTM32F446xx -I../Inc -I../Drivers/STM32F4xx_HAL_Driver/Inc -I../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32F4xx/Include -I../Drivers/CMSIS/Include -O2 -g3 -Wall -fmessage-length=0 -ffunction-sections -c -fmessage-length=0

MCU GCC Linker

-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nosys.specs -specs=nano.specs -T"../STM32F446RETx_FLASH.ld" -Wl,-Map=output.map -Wl,--gc-sections -lm



測定データ(us)

- mbed-cli SW4STM32 差2
no-op 39 49.6 10.6
add 77.8 99 21.2 10.6
sub 77.8 99 21.2 10.6
mul 77.8 99 21.2 10.6
div 145 165 20 9.4
sinf() 569 525 -44 -54.6
cosf() 621 591 -30 -40.6
tanf() 986 966 -20 -30.6
expf() 958 974 16 5.4
logf() 946 998 52 41.4
powf() 2625 2735 110 99.4

測定データの「差2」はGPIO出力の処理時間の差を考慮したmbedとSW4STM32の処理時間の差です。GPIO分を差し引いても四則演算ではmbedの方が速いです。アセンブラレベルで比較すれば何かわかるかもしれませんが、深みにハマりそうなのでやめておきます。


0 件のコメント:

コメントを投稿