2016年8月3日水曜日

RaspPi3(ARM Cortex-A53)とNucleo-F401RE(Cortex-M4)の浮動小数点演算比較

Raspberry PiはCortex Aなので、その実力を見るために以前やったサイン波テーブルの生成をやってみた。

gen_sine_table.c

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

#define M_PI_f     (3.1415926f) /* pi float */
#define TABLE_LENGTH  (8192)

uint8_t waveTable_0[TABLE_LENGTH];

void genSineTable_double(uint8_t *table, int length)
{
    int i;

    int16_t v;
    int8_t* p8;
    for (i = 0; i < length / 2; i++) {
        v = (int16_t)(sin(2.0 * M_PI * i * 2 / length) * 32767);
        p8 = (int8_t *)&v;
        table[i*2] = *(p8+1);
        table[i*2+1] = *p8;
    }
}

void genSineTable_float(uint8_t *table, int length)
{
    int i;
    int16_t v;
    int8_t* p8;
    for (i = 0; i < length / 2; i++) {
        v = (int16_t)(sinf(2.0f * M_PI_f * i * 2 / length) * 32767);
        p8 = (int8_t *)&v;
        table[i*2] = *(p8+1);
        table[i*2+1] = *p8;
    }
}

int main()
{
    clock_t start;

    printf("CLOCKS_PER_SEC: %ld\n", CLOCKS_PER_SEC); 

    // 単精度浮動小数点演算 (with FPU)
    printf("start float: TABLE_SIZE:%d\r\n", TABLE_LENGTH);
    start = clock();
    genSineTable_float(waveTable_0, TABLE_LENGTH);
    printf("%d\r\n", clock() - start);

    // 倍精度浮動小数点演算
    printf("start double: TABLE_SIZE:%d\r\n", TABLE_LENGTH);
    start = clock();
    genSineTable_double(waveTable_0, TABLE_LENGTH);
    printf("%d\r\n", clock() - start);
}

pi@raspberrypi:~ $ gcc -o gen_sine_table -lm gen_sine_table.c

速度を上げる工夫は何もしていない。前回とほぼおなじプログラムをgccでコンパイルしただけ。バイトの入れ替えは__REV()関数を使ったほうが早そうだが、前回と同じく1byteずつ入れ替えた。

Linux上で動かしているので割り込みやらなんやらの影響(?)で実行するごとに値が変わる。適当に見繕って表にしてみた。


TABLE_LENGTH RasPi3 float (us) RasPi3 double (us) Nucleo float (us) RasPi3 float vs Nucleo float(us)
512 160 342 372 2.325
1024 273 454 743 2.721611722
2048 455 730 1486 3.265934066
4096 897 1378 2972 3.313266444
8192 1621 2691 5943 3.666255398


Nucleo F401は84MHz駆動で、RasPi3は1.2GHz駆動なのでもっと差がでても良さそうだが、いろいろなオーバーヘッドがあるのだろう。

8192バイトのサイン・テーブルをdouble型で生成しても3ms以下なので、ファンクションジェネレータとして使った場合、ロータリーエンコーダーをガチャガチャ回したタイミングで毎回波形テーブルを作ってもストレスは少なそうだ。専用機にしてしまうのはもったいないけど。

まじめにやるならスレッドの優先順位を上げたり、HWを使ったりとかいろいろ方法がありそう。

メモ:


Webを眺めていると、GPGPUで行列演算をされている方がいた。http://qiita.com/9_ties/items/15ab7fa198991a61a3a9

ARMのAとMはよく見るが、Rはあんまり見ない。どのへんで使われてるんだろう。

Raspberry Pi Zero($5 PC)なら安いし消費電力も小さいようなので、いろいろ使えるかな~。早く手軽に入手出来るようにならないかな。