PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : HaWe Brickbench Benchmark Test 2.0 für Arduino



HaWe
14.07.2018, 20:06
HaWe Brickbench Benchmark Test 2.1
angepasste Routinen zum besseren Vergleich von SoCs und MCUs,
ver 2.1.1: inkl GPIO toggle r/w Test,
low-level bitRead/Write statt digitalRead/Write (AVR, optional),
und optional reine 32bit fp-Tests vs. 64bit double (32bit cores)



// HaWe Brickbench
// benchmark test for SoCs and MCUs
// PL: GCC,Arduino
// Autor: (C) Helmut Wunder 2013-2018
// ported to Raspi by "HaWe"
//
// freie Verwendung für private Zwecke
// für kommerzielle Zwecke nur nach schriftlicher Genehmigung durch den Autor.
// protected under the friendly Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// http://creativecommons.org/licenses/by-nc-sa/3.0/
// version 2.1.1 2018-07-22
// Adafruit ILI9340 / ILI9341
// change log:
// 2.1.1. 32bit fp tests vs. 64bit double (ARM/32bit cores, optional)
// low-level bitRead/Write vs. digitalRead/Write (AVR cores, optional)
// 2.1 GPIO r/w
// 2.0 loop counts


#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

/*
_DUEMISO_ 74 // Arduino Due SPI Header
_DUEMOSI_ 75
_DUESCK_ 76

_UNOMISO_ 12
_UNOMOSI_ 11
_UNOCLK_ 13

_MEGAMISO_ 50
_MEGAMOSI_ 51
_MEGACLK_ 52

*/

// Arduino TFT pins
#define tft_cs 10
#define tft_dc 9
#define tft_rst 8

//Adafruit_ILI9341 tft = Adafruit_ILI9341(tft_cs, tft_dc, tft_rst);
// Adafruit Hardware SPI, no RST
Adafruit_ILI9341 tft = Adafruit_ILI9341(tft_cs, tft_dc);



#define TimerMS() millis()

unsigned long runtime[8];

#define tpin1 11 // GPIO test pins digitalWrite
#define tpin2 12 // GPIO test pins digitalWrite
#define tpin3 13 // GPIO test pins digitalRead


void TFTprint(char sbuf[], int16_t x, int16_t y) {
tft.setCursor(x, y);
tft.print(sbuf);
}

int a[500], b[500], c[500], t[500];

//--------------------------------------------
// Mersenne Twister
//--------------------------------------------

unsigned long randM(void) {

const int M = 7;
const unsigned long A[2] = { 0, 0x8ebfd028 };

static unsigned long y[25];
static int index = 25+1;

if (index >= 25) {
int k;
if (index > 25) {
unsigned long r = 9, s = 3402;
for (k=0 ; k<25 ; ++k) {
r = 509845221 * r + 3;
s *= s + 1;
y[k] = s + (r >> 10);
}
}
for (k=0 ; k<25-M ; ++k)
y[k] = y[k+M] ^ (y[k] >> 1) ^ A[y[k] & 1];
for (; k<25 ; ++k)
y[k] = y[k+(M-25)] ^ (y[k] >> 1) ^ A[y[k] & 1];
index = 0;
}

unsigned long e = y[index++];
e ^= (e << 7) & 0x2b5b2500;
e ^= (e << 15) & 0xdb8b0000;
e ^= (e >> 16);
return e;
}

//--------------------------------------------
// Matrix Algebra
//--------------------------------------------

// matrix * matrix multiplication (matrix product)

void MatrixMatrixMult(int N, int M, int K, double *A, double *B, double *C) {
int i, j, s;
for (i = 0; i < N; ++i) {
for (j = 0; j < K; ++j) {
C[i*K+j] = 0;
for (s = 0; s < M; ++s) {
C[i*K+j] = C[i*K+j] + A[i*N+s] * B[s*M+j];
}
}
}
}


// matrix determinant

double MatrixDet(int N, double A[]) {
int i, j, i_count, j_count, count = 0;
double Asub[N - 1][N - 1], det = 0;

if (N == 1)
return *A;
if (N == 2)
return ((*A) * (*(A+1+1*N)) - (*(A+1*N)) * (*(A+1)));

for (count = 0; count < N; count++) {
i_count = 0;
for (i = 1; i < N; i++) {
j_count = 0;
for (j = 0; j < N; j++) {
if (j == count)
continue;
Asub[i_count][j_count] = *(A+i+j*N);
j_count++;
}
i_count++;
}
det += pow(-1, count) * A[0+count*N] * MatrixDet(N - 1, &Asub[0][0]);
}
return det;
}



//--------------------------------------------
// shell sort
//--------------------------------------------

void shellsort(int size, int* A)
{
int i, j, increment;
int temp;
increment = size / 2;

while (increment > 0) {
for (i = increment; i < size; i++) {
j = i;
temp = A[i];
while ((j >= increment) && (A[j-increment] > temp)) {
A[j] = A[j - increment];
j = j - increment;
}
A[j] = temp;
}

if (increment == 2)
increment = 1;
else
increment = (unsigned int) (increment / 2.2);
}
}

//--------------------------------------------
// gnu quick sort
// (0ptional)
//--------------------------------------------

int compare_int (const int *a, const int *b)
{
int temp = *a - *b;

if (temp > 0) return 1;
else if (temp < 0) return -1;
else return 0;
}

// gnu qsort:
// void qsort (void *a , size_a count, size_a size, compare_function)
// gnu qsort call for a[500] array of int:
// qsort (a , 500, sizeof(a), compare_int)



//--------------------------------------------
// benchmark test procedures
//--------------------------------------------


int test_Int_Add() { // 10,000,000 int +,-
int i=1, j=11, k=112, l=1111, m=11111, n=-1, o=-11, p=-111, q=-1112, r=-11111;
unsigned long x;
volatile long s=0;
for(x=0;x<5000000;x++) {
s+=i; s+=j; s+=k; s+=l; s+=m; s+=n; s+=o; s+=p; s+=q; s+=r;
}
return s; // debug
}


//--------------------------------------------
long test_Int_Mult() { // 2,000,000 int *,/
int x;
unsigned long y;
volatile long s;

for(y=0;y<500000;y++) {
s=1;
for(x=1;x<=10;x++) { s*=x;}
for(x=10;x>0;--x) { s/=x;}
}
return s; // debug
}


#define PI M_PI

//--------------------------------------------
double test_fp_math() { // 2,500,000 fp (double) mult, transcend.
volatile double s=(double)PI;
unsigned long y;

for(y=0;y<500000UL;y++) {
s*=sqrt(s);
s=sin(s);
s=exp(s);
s*=s;
}
return s;
}

//--------------------------------------------
float test_fp_math32() { // 2,500,000 32bit float mult, transcend.
volatile float s=(float)PI;
unsigned long y;

for(y=0;y<500000UL;y++) {
s*=sqrtf(s);
s=sinf(s);
s=expf(s);
s*=s;
}
return s;
}


//--------------------------------------------
long test_rand_MT() { // 2,500,000 PRNGs
volatile unsigned long s;
unsigned long y;

for(y=0;y<2500000;y++) {
s=randM()%10001;
}
return s;
}

//--------------------------------------------
double test_matrix_math() { // 150,000 2D Matrix algebra (mult, det)
unsigned long x;

double A[2][2], B[2][2], C[2][2];
double S[3][3], T[3][3];
unsigned long s;

for(x=0;x<50000;++x) {

A[0][0]=1; A[0][1]=3;
A[1][0]=2; A[1][1]=4;

B[0][0]=10; B[0][1]=30;
B[1][0]=20; B[1][1]=40;

MatrixMatrixMult(2, 2, 2, A[0], B[0], C[0]);

A[0][0]=1; A[0][1]=3;
A[1][0]=2; A[1][1]=4;

MatrixDet(2, A[0]);

S[0][0]=1; S[0][1]=4; S[0][2]=7;
S[1][0]=2; S[1][1]=5; S[1][2]=8;
S[2][0]=3; S[2][1]=6; S[2][2]=9;

MatrixDet(3, S[0]);

s=(S[0][0]*S[1][1]*S[2][2]);
}
return s;
}


//--------------------------------------------
// for array copy using void *memcpy(void *dest, const void *src, size_t n);

long test_Sort() { // 1500 sort of random array[500]
unsigned long s;
int y, i;

int t[500];

for(y=0;y<500;++y) {
memcpy(t, a, sizeof(a));
shellsort(500, t);

memcpy(t, a, sizeof(b));
shellsort(500, t);

memcpy(t, a, sizeof(c));
shellsort(500, t);
}
return y;
}


//--------------------------------------------
int32_t test_GPIO() { // 6,000,000 GPIO r/w
volatile static bool w=false, r;
uint32_t y;
for (y=0; y<2000000; y++) {
digitalWrite(tpin1, w);
w=!w;
r=digitalRead(tpin3);
digitalWrite(tpin2, w&!r);
}
return 1;
}

/*
//--------------------------------------------
int32_t test_GPIO_AVR() { // 6,000,000 GPIO bit r/w
volatile static bool w=false, r;
uint32_t y;
for (y=0; y<2000000; y++) {
bitWrite(PORTB, PB5, w);
w=!w;
r = bitRead(PINB, PB7);
bitWrite(PORTB, PB6, w&!r); // optional: bitWrite(PORTB, PB6, w&r);
}
return 1; // debug
}
*/


//--------------------------------------------
inline void displayValues() {

char buf[120];
tft.fillScreen(ILI9341_BLACK); // clrscr()

sprintf (buf, "%3d %9ld int_Add", 0, runtime[0]); TFTprint(buf, 0,10);
sprintf (buf, "%3d %9ld int_Mult", 1, runtime[1]); TFTprint(buf, 0,20);
sprintf (buf, "%3d %9ld fp_op", 2, runtime[2]); TFTprint(buf, 0,30);
sprintf (buf, "%3d %9ld randomize", 3, runtime[3]); TFTprint(buf, 0,40);
sprintf (buf, "%3d %9ld matrx_algb", 4, runtime[4]); TFTprint(buf, 0,50);
sprintf (buf, "%3d %9ld arr_sort", 5, runtime[5]); TFTprint(buf, 0,60);
sprintf (buf, "%3d %9ld GPIO_togg", 6, runtime[6]); TFTprint(buf, 0,70);
sprintf (buf, "%3d %9ld Graphics", 7, runtime[7]); TFTprint(buf, 0,80);
}

//--------------------------------------------
int32_t test_TextOut(){
int y;
char buf[120];

for(y=0;y<10;++y) {
tft.fillScreen(ILI9341_BLACK); // clrscr()
sprintf (buf, "%3d %9d int_Add", y, 1000); TFTprint(buf, 0,10);
sprintf (buf, "%3d %9d int_Mult", 0, 1010); TFTprint(buf, 0,20);
sprintf (buf, "%3d %9d fp_op", 0, 1020); TFTprint(buf, 0,30);
sprintf (buf, "%3d %9d randomize", 0, 1030); TFTprint(buf, 0,40);
sprintf (buf, "%3d %9d matrx_algb", 0, 1040); TFTprint(buf, 0,50);
sprintf (buf, "%3d %9d GPIO_togg", 0, 1050); TFTprint(buf, 0,60);
sprintf (buf, "%3d %9d Graphics", 0, 1060); TFTprint(buf, 0,70);
sprintf (buf, "%3d %9d testing...", 0, 1070); TFTprint(buf, 0,80);

}
return y;
}


//--------------------------------------------
int32_t test_graphics(){
int y;
char buf[120];


for(y=0;y<10;++y) {
tft.fillScreen(ILI9341_BLACK);
sprintf (buf, "%3d", y); TFTprint(buf, 0,80); // outcomment for downwards compatibility

tft.drawCircle(50, 40, 10, ILI9341_WHITE);
tft.fillCircle(30, 24, 10, ILI9341_WHITE);
tft.drawLine(10, 10, 60, 60, ILI9341_WHITE);
tft.drawLine(50, 20, 90, 70, ILI9341_WHITE);
tft.drawRect(20, 20, 40, 40, ILI9341_WHITE);
tft.fillRect(65, 25, 20, 30, ILI9341_WHITE);
tft.drawCircle(70, 30, 15, ILI9341_WHITE);

}
return y;
}


//--------------------------------------------
long test(){
unsigned long time0, x, y;
double s;
char buf[120];
int i;
float f;

Serial.println("init test arrays");

for(y=0;y<500;++y) {
a[y]=randM()%30000; b[y]=randM()%30000; c[y]=randM()%30000;
}

Serial.println("start test");
delay(10);



time0= TimerMS();

s=test_Int_Add();
runtime[0]=TimerMS()-time0;
sprintf (buf, "%3d %9ld int_Add", 0, runtime[0]); Serial.println( buf);

time0=TimerMS();
s=test_Int_Mult();
runtime[1]=TimerMS()-time0;
sprintf (buf, "%3d %9ld int_Mult", 1, runtime[1]); Serial.println( buf);


time0=TimerMS();
s=test_fp_math();
runtime[2]=TimerMS()-time0;
sprintf (buf, "%3d %9ld fp_op ", 2, runtime[2]); Serial.println( buf);
//debug // Serial.println(s);

time0=TimerMS();
s=test_rand_MT();
runtime[3]=TimerMS()-time0;
sprintf (buf, "%3d %9ld randomize", 3, runtime[3]); Serial.println( buf);


time0=TimerMS();
s=test_matrix_math();
runtime[4]=TimerMS()-time0;
sprintf (buf, "%3d %9ld matrx_algb", 4, runtime[4]); Serial.println( buf);


time0=TimerMS();
s=test_Sort();
runtime[5]=TimerMS()-time0;
sprintf (buf, "%3d %9ld arr_sort", 5, runtime[5]); Serial.println( buf);


// GPIO R/W toggle test
//Serial.println("GPIO_toggle test");
time0=TimerMS();
s=test_GPIO();
runtime[6]=TimerMS()-time0;
sprintf (buf, "%3d %9ld GPIO_toggle", 6, runtime[6]); Serial.println( buf);


// lcd display text / graphs
time0=TimerMS();
s=test_TextOut();
s=test_graphics();
runtime[7]=TimerMS()-time0;
sprintf (buf, "%3d %9ld Graphics ", 7, runtime[7]); Serial.println( buf);

Serial.println();

y = 0;
for (x = 0; x < 8; ++x) {
y += runtime[x];
}

displayValues();
sprintf (buf, "runtime ges.: %-9ld ", y);
Serial.println( buf); TFTprint(buf, 0,90);

x=50000000.0/y;
sprintf (buf, "benchmark: %-9ld ", x);
Serial.println( buf); TFTprint(buf, 0,100);


return 1;
}

//--------------------------------------------
void setup() {

Serial.begin(115200);

// Setup the LCD
tft.begin();
tft.setRotation(3);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
Serial.println("tft started");

pinMode(tpin1, OUTPUT);
pinMode(tpin2, OUTPUT);
pinMode(tpin3, INPUT_PULLUP);

}

void loop() {
char buf[120];
test();

sprintf (buf, "Ende HaWe brickbench");
Serial.println( buf);
TFTprint(buf, 0, 110);

while(1);
}





test design:
0 int_Add 50,000,000 int +,- plus counter
1 int_Mult 10,000,000 int *,/ plus counter
2 float_op 2,500,000 fp mult, transc. plus counter
3 randomize 2,500,000 Mersenne PRNG (+ * & ^ << >>)
4 matrx_algb 150,000 2D Matrix algebra (mult, det)
5 arr_sort 1500 shellsort of random array[500]
6 GPIO toggle 6,000,000 toggle GPIO r/w plus counter
7 Graphics 10*8 textlines + 10*8 shapes + 20 clrscr

.





Arduino MEGA + ILI9225 + Karlson UTFT
0 90244 int_Add
1 237402 int_Mult
2 163613 float_op (float)
3 158567 randomize
4 46085 matrx_algb
5 23052 arr_sort
6 41569 GPIO toggle
7 62109 Graphics
runtime ges.: 822641
benchmark: 60

.




Arduino MEGA + ILI9225 + Karlson UTFT + Register bitRead/Write
0 90238 int_Add
1 237387 int_Mult
2 163602 float_op (float)
3 158557 randomize
4 45396 matrx_algb
5 23051 arr_sort
6 4528 GPIO_toggle bit r/w
7 62106 Graphics
runtime ges.: 784865
benchmark: 63

.



Arduino MEGA + adafruit_ILI9341 Hardware-SPI
0 90244 int_Add
1 237401 int_Mult
2 163612 float_op (float)
3 158725 randomize
4 46079 matrx_algb
5 23051 arr_sort
6 41947 GPIO toggle
7 6915 Graphics
runtime ges.: 767974
benchmark: 65

.




Arduino/ItsyBitsy M0 + adafruit_ILI9341 Hardware-SPI +32bit float
0 7746 int_Add
1 15795 int_Mult
2 89054 float_op (float)
3 17675 randomize
4 18650 matrx_algb
5 6328 arr_sort
6 9944 GPIO_toggle
7 6752 Graphics

runtime ges.: 171944
benchmark: 290
.




Arduino/Adafruit M0 + adafruit_ILI9341 Hardware-SPI +64bit double
0 7746 int_Add
1 15795 int_Mult
2 199888 float_op (double)
3 17727 randomize
4 18559 matrx_algb
5 6330 arr_sort
6 9734 GPIO toggle
7 6759 Graphics
runtime ges.: 282538
benchmark: 176

.




Arduino DUE + adafruit_ILI9341 Hardware-SPI + 32bit float
0 4111 int_Add
1 1389 int_Mult
2 29124 float_op (float)
3 3853 randomize
4 4669 matrx_algb
5 2832 arr_sort
6 11859 GPIO_toggle
7 6142 Graphics

runtime ges.: 63979
benchmark: 781

.




Arduino DUE + adafruit_ILI9341 Hardware-SPI +64bit double
0 4111 int_Add
1 1389 int_Mult
2 57225 float_op (double)
3 3852 randomize
4 4666 matrx_algb
5 2833 arr_sort
6 11787 GPIO toggle
7 6143 Graphics
runtime ges.: 92006
benchmark: 543

.


Code, auszugsweise ohne Display: https://forum.arduino.cc/index.php?action=dlattach;topic=559309.0;attach=26 7064

auszugsweise, ohne Display:
Benchmark for Teensy 3.2 96 MHz (Overclock) Optimize: Faster (Quelle: Mxt)
0 2819 int_Add
1 1086 int_Mult
2 45820 double_op
2 23443 float_op
3 1797 randomize
4 3656 matrx_algb
5 1523 arr_sort
6 1955 GPIO toggle

.



auszugsweise, ohne Display:
Benchmark for Teensy 3.5 120 MHz Optimize: Faster (Quelle: Mxt)
0 2255 int_Add
1 869 int_Mult
2 32253 double_op
2 2674 float_op
3 1449 randomize
4 2642 matrx_algb
5 1231 arr_sort
6 1838 GPIO toggle

.



auszugsweise, ohne Display:
Benchmark for Teensy 3.6 180 MHz Optimize: Faster (Quelle: Mxt)
0 1501 int_Add
1 579 int_Mult
2 15871 double_op
2 955 float_op
3 947 randomize
4 1279 matrx_algb
5 819 arr_sort
6 1040 GPIO toggle

.



Vergleich Raspberry Pi 2, Code siehe: https://www.roboternetz.de/community/threads/72216-HaWe-Brickbench-Benchmark-Test-2-0

Raspi 2 GPU 400MHz, NO CPU OVERCLOCK, openVG:
0 384 int_Add
1 439 int_Mult
2 441 float_op (double)
3 399 randomize
4 173 matrx_algb
5 508 arr_sort
6 823 GPIO_toggle
7 2632 graphics
runtime ges.: 5799
benchmark: 8622

.

HaWe
19.07.2018, 12:59
Update,

GPIO-Routine für Arduino Mega testweise optional ersetzbar durch low-level Register bit read/write:


//--------------------------------------------
int32_t test_GPIO_AVR() { // 6,000,000 GPIO bit r/w
volatile static bool w=false, r;
uint32_t y;
for (y=0; y<2000000; y++) {
bitWrite(PORTB, PB5, w);
w=!w;
r = bitRead(PINB, PB7);
bitWrite(PORTB, PB6, w&!r); // optional: bitWrite(PORTB, PB6, w&r);
}
return 1; // debug
}



6a 41569 GPIO digitalRead/Write
6b 4528 GPIO register bitRead/Write


Anm.:

direct port manipulation compiles to 1 or 2 instructions, calling digitalRead is dozens.
One issue to be aware of is interrupts - some of the native direct-port manipulation code will not be
interrupt-safe, where as digitalRead/digitalWrite/pinMode() are carefully coded to work when used
both in an ISR and the main program.


Update 2:
Habe jetzt auch die Routine für optional 32bit fp_op (float) neu geschrieben, die dadurch jetzt auch erhebliche Laufzeitunterschiede zu 64bit double auf allen ARM-Cores erkennen lässt!

HaWe
22.07.2018, 19:08
besitzt hier jemand einen ARM mit M4F, z.B. einen Teensy 3.5 oder 3.6?
Der M4F von Adafruit scheint bei fp_double keinen Gebrauch von der fpu zumachen, sondern nur bei 32bit-float!

And for grins, a SAMD51:


...
2 24482 double_op
2 2772 float_op
...
(I'm not convinced that the double floating point library "properly" utilizes single point hardware. Sigh.)




#define PI M_PI

//--------------------------------------------
double test_fp_math() { // 2,500,000 fp (double) mult, transcend.
volatile double s=(double)PI;
unsigned long y;

for(y=0;y<500000UL;y++) {
s*=sqrt(s);
s=sin(s);
s=exp(s);
s*=s;
}
return s; // debug
}

//--------------------------------------------
float test_fp_math32() { // 2,500,000 32bit float mult, transcend.
volatile float s=(float)PI;
unsigned long y;

for(y=0;y<500000UL;y++) {
s*=sqrtf(s);
s=sinf(s);
s=expf(s);
s*=s;
}
return s; // debug
}

Mxt
23.07.2018, 08:05
besitzt hier jemand einen ARM mit M4F, z.B. einen Teensy 3.5 oder 3.6?
Der M4F von Adafruit scheint bei fp_double keinen Gebrauch von der fpu zumachen, sondern nur bei 32bit-float!


Ja, besitze ich, aber kein solches Display, deswegen habe ich mir den Code nicht weiter angesehen.

Cortex M4F kann nur float, das ist normal. Für double muss man z.B. auf den Teensy 4 warten, Cortex M7 600 MHz und dann auch FPU mit double. Wird aber sicher noch 1-2 Jahre dauern.

HaWe
23.07.2018, 10:01
Ja, besitze ich, aber kein solches Display, deswegen habe ich mir den Code nicht weiter angesehen.
Cortex M4F kann nur float, das ist normal. Für double muss man z.B. auf den Teensy 4 warten, Cortex M7 600 MHz und dann auch FPU mit double. Wird aber sicher noch 1-2 Jahre dauern.

das Display brauchst du nicht anschließen: wenn es nicht verkabelt ist, tut er nur so als ob er es nutzt, aber es schadet nicht weiter und blockiert auch nichts. Adafruit GFX und ILI9341 libs lassen sich über den lib manager direkt in der IDE installieren.

Mxt
23.07.2018, 10:26
Das sind zwei Libraries von denen der Teensy-Installer schon eigene optimierte Varianten mitbringt. Da fehlt mir im Moment sowohl Zeit als auch Lust, um zu schauen, ob er auch die normalen nimmt.

Mit großen Unterschieden zwischen Adafruit Metro und Teensy 3.5 würde ich sowieso nicht rechnen.

HaWe
23.07.2018, 10:30
es gibt auch eine Test-Version von westfw, ganz vergessen:

https://forum.arduino.cc/index.php?action=dlattach;topic=559309.0;attach=26 7064

Mxt
23.07.2018, 10:35
Das sollte gehen, eventuell komme ich heute Abend dazu die Werte aufzunehmen.

HaWe
23.07.2018, 10:58
gerade gesehen, der Teensy 35 wurde von jemand anderem bereits getestet, ich hatte es erst nicht entdeckt, welcher Typ es genau war. Hab es oben eingefügt! Sieht aus, als ob auf dem teeny35 double noch deutlich langsamer läuft als auf dem Adafruit Metro M4, und übrigens, auch Matrix Algebra nutzt ja auch double statt float... :-k

Mxt
23.07.2018, 11:09
Das hat eventuell mehr mit Compilereinstellung und (Library-)code zu tun, als mit der Hardware.

Beim Teensy ist der Compiler z.B. so eingestellt, dass er Fliesskommakonstanten im Code immer als float interpretiert, eventuell führt das zu vielen überflüssigen Umwandlungen zwischen float und double.

Ansonsten sind die Ergebnisse so wie ich vermutet habe. Der Teensy 3.2 dürfte irgendwo in der Mitte zwischen Arduino Due und Teensy 3.5 liegen.

HaWe
23.07.2018, 11:22
Das hat eventuell mehr mit Compilereinstellung und (Library-)code zu tun, als mit der Hardware.
Beim Teensy ist der Compiler z.B. so eingestellt, dass er Fliesskommakonstanten im Code immer als float interpretiert, eventuell führt das zu vielen überflüssigen Umwandlungen zwischen float und double.

Das kann aber doch nicht bedeuten, dass der Teensy dann letztendlich gar nicht double verwendet und rechnet, obwohl es so im Code steht... oder? Denn das wäre ja fatal...

Mxt
23.07.2018, 11:36
Das ist als Optimierung gedacht für solche Fälle



float x = 3.5f;

float y = x * 2.1; // f vergessen


Hier wird bei x * 2.1 zuerst das x von float nach double gewandelt, dann als double multipliziert und dann das Ergebnis wieder in float konvertiert.

Weil aber in typischem Arduino Code float und double häufig gemischt verwendet wird, weils auf den 8-Bittern eh das selbe ist, ist beim Teensy standardmäßig der Compilerschalter -fsingle-precision-constant gesetzt, der dazu führt, dass Fliesskommakonstanten als float interpretiert werden. Das macht den Code normalerweise schneller, weil man meist eh nur mit float rechnen will.

Wenn man explizit eine double Konstante braucht, kann man ja 2.1L schreiben, das ist dann zwar long double, aber das dürfte bei den kleinen Prozessoren auch double sein.

Ich bin mir nicht sicher, wie das die anderen getesteten Boards handhaben, muss man also die Dateien in der Arduino IDE erforschen ...

Ein weiterer Unterschied sind die Compilereinstellungen zur Optimierung. Ich bin mir ziemlich sicher die Arduino IDE optimiert beim Due den Code auf Größe, nicht auf Geschwindigkeit. Beim Teensy lässt sich das im Menu der Arduino IDE einstellen ...

HaWe
23.07.2018, 11:45
aaa-ha...!
was macht er dann bei sin, cos, exp, sqrt? grundsätzlich doch double, wie es richtig wäre, oder "nur" float per XXXXf Funktionen?
Arduino M0 und M3 verwenden dann double, für float muss man die XXXXf Versionen nutzen (habe ich getestet), und so würde ich es auch an sich immer erwarten, nach allem was ich jetzt weiß.

(PS, nach den Laufzeiten zu urteilen, scheint der M4 ja IMMER für double länger zu brauchen, daher dann wohl wschl doch double, wie zu erwarten, wenn auch ohne Nutzung der fpu wie es scheint...)

Mxt
23.07.2018, 11:56
Wie der Name des Schalters schon andeutet, wirkt er nur auf Konstanten.

In Standard C++ sollte bei sin, cos usw. eigentlich anhand der Parameter entschieden werden, was raus kommt
https://en.cppreference.com/w/cpp/numeric/math/sin

sinf ist nur eine zusätzliche Variante um float zu erzwingen.

- - - Aktualisiert - - -


scheint der M4 ja IMMER für double länger zu brauchen,

Bei double rechnet der M4 ohne Verwendung der FPU. Das bedeutet auch deren Register bleiben unbenutzt. Optimaler Code auf den M4 macht was mit int und float gemischt und nutzt so die Prozessorregister optimal aus.

HaWe
23.07.2018, 12:22
Wie der Name des Schalters schon andeutet, wirkt er nur auf Konstanten.

In Standard C++ sollte bei sin, cos usw. eigentlich anhand der Parameter entschieden werden, was raus kommt
https://en.cppreference.com/w/cpp/numeric/math/sin

sinf ist nur eine zusätzliche Variante um float zu erzwingen.

Bei double rechnet der M4 ohne Verwendung der FPU. Das bedeutet auch deren Register bleiben unbenutzt. Optimaler Code auf den M4 macht was mit int und float gemischt und nutzt so die Prozessorregister optimal aus.

bei z.B. sin(x) ist es tatsächlich so, dass M0 und M3 immer die double Version verwenden, egal ob x double oder float ist. Analog bei exp() und sqrt() etc.
Das merkt man extrem deutlich bei den Laufzeiten: in diesen Fällen braucht man bei float x sogar 20% länger als bei double x.
Nur bei sinf() mit float x etc. sind die float-tests etwa 2x so schnell wie auf double.

Mxt
23.07.2018, 18:09
Sodele,

hier meine Messwerte mit der aktuellen Teensyduino 1.42 auf Arduino 1.8.5, jeweils mit den Default-Einstellungen der IDE für Taktfrequenz und Optimierung:



Benchmark for Teensy 3.2 96 MHz (Overclock) Optimize: Faster

0 2819 int_Add
1 1086 int_Mult
2 45820 double_op
2 23443 float_op
3 1797 randomize
4 3656 matrx_algb
5 1523 arr_sort
6 1955 GPIO toggle




Benchmark for Teensy 3.5 120 MHz Optimize: Faster

0 2255 int_Add
1 869 int_Mult
2 32253 double_op
2 2674 float_op
3 1449 randomize
4 2642 matrx_algb
5 1231 arr_sort
6 1838 GPIO toggle




Benchmark for Teensy 3.6 180 MHz Optimize: Faster

0 1501 int_Add
1 579 int_Mult
2 15871 double_op
2 955 float_op
3 947 randomize
4 1279 matrx_algb
5 819 arr_sort
6 1040 GPIO toggle


Der Teensy 3.2 hat keine FPU, das sieht man deutlich im float_op Ergebnis.
Die Werte für den 3.5 sind leicht anders, als oben gepostet, könnte an einer anderen Softwareversion liegen.
Der 3.6 ist das Topmodell u.a. mit viel größerem Cache, das sieht man bei einigen Ergebnissen.

HaWe
23.07.2018, 19:37
Der Teensy 3.2 hat keine FPU, das sieht man deutlich im float_op Ergebnis.
Die Werte für den 3.5 sind leicht anders, als oben gepostet, könnte an einer anderen Softwareversion liegen.
Der 3.6 ist das Topmodell u.a. mit viel größerem Cache, das sieht man bei einigen Ergebnissen.

Dankeschön, ich trage deine Werte sofort oben ein, und da sie aus 1 Hand sind, kann man sie sogar deutlich besser vergleichen!
Danke für deine Mühe!