2017年11月26日日曜日

Raspberry Pi 3とCortex-M7のNucleo F767ZIの浮動小数点演算を比較

Nucleo用にmbedで書いたプログラムとほぼおなじものをRaspberry Pi3用にC++で書いて比較してみた。

Nucleo用プログラム (mbed)
https://os.mbed.com/users/ryood/code/FloatingPointTest/ Revison:1

Raspberry Pi 3用プログラム <floating_point_test.cc>

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

#define LOOP_N  (10000)

float buffer[LOOP_N];

clock_t start;

void floatTest()
{
    // divf
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = (float)i / LOOP_N;
    }
    int elapse = clock() - start;
    printf("divf\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);
    
    // sinf
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = sinf((float)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("sinf\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);

    // cosf
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = cosf((float)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("cosf\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);

    // expf
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = expf((float)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("expf\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);
    
    // logf
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = logf((float)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("logf\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);
    
    // sqrtf
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = sqrtf((float)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("sqrtf\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);      
}

void doubleTest()
{
    // div
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = (double)i / LOOP_N;
    }
    int elapse = clock() - start;
    printf("div\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);
    
    // sin
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = sin((double)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("sin\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);

    // cos
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = cos((double)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("cos\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);

    // exp
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = exp((double)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("exp\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);
    
    // log
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = log((double)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("log\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);
    
    // sqrt
    start = clock();
    for (int i = 0; i < LOOP_N; i++) {
        buffer[i] = sqrt((double)i / LOOP_N);
    }
    elapse = clock() - start;
    printf("sqrt\t%d\t%f\r\n", elapse, (float)elapse / LOOP_N);      
}

int main()
{
    printf("\nFloating Point Test\n");
    printf("CLOCKS_PER_SEC: %ld\n", CLOCKS_PER_SEC); 
    
    // 単精度浮動小数点演算
    printf("\nFloating Point Test\n");
    printf("float\n");
    printf("op\ttotal\t1-op\n");
    printf("-------------------------------\n");
    floatTest();
    
    // 倍精度浮動小数点演算
    printf("double\n");
    printf("op\ttotal\t1-op\n");
    printf("-------------------------------\n");
    doubleTest();
}


pi@raspberrypi:~ $ gcc -o floating_point_test -lm floating_point_test.cc

pi@raspberrypi:~ $ cat /etc/debian_version
8.0

Raspberry PiのプログラムはLinux上で実行しているのでNucleoの方が有利ですが、Raspberry PiをOSなし(ベアメタルと言うそうです)で動かすのはかなり難しいので、実用的な性能比較ということになると思います。

実行結果

Floating Point Test
CLOCKS_PER_SEC: 1000000

Floating Point Test
float
op      total   1-op
-------------------------------
divf    629     0.062900
sinf    2124    0.212400
cosf    2163    0.216300
expf    3632    0.363200
logf    2659    0.265900
sqrtf   3630    0.363000
double
op      total   1-op
-------------------------------
div     753     0.075300
sin     4805    0.480500
cos     4829    0.482900
exp     5356    0.535600
log     4408    0.440800
sqrt    4871    0.487100

※Raspberry Pi上では実行ごとに結果が異なる。



float型ではsqrtf()以外ではNucleo F767はRasPi3の約0.6倍の性能。なぜだかsqrtf()だけはNucleo F767の方が速い。

double型ではsqrt()以外はNucleo F767はRasPi3の約0.2倍~0.5倍の性能。これもsqrt()はNucleo F767の方が速い。

駆動クロックは

Nucleo F767ZI: 216MHz
Raspberry Pi 3: 1.2GHz

で約6倍差があるので、Cortex-M7のNucleo F767ZIは、まあまあ健闘していると思う。

Nucleo F767ZIの消費電流は98mAで(ボード上のJP5 IDDで測定)、Raspberry Pi 3よりかなり少ない。