Производительность FPU Cortex-M4

Взял вот такой код, который умножает матрицы размером 5x5, количество операций я насчитал 525, отдельно учитывал сложения и умножения. Исходные данные берутся из таймера, записываются в глобальную переменную, компилятор не должен уклонится от генерации кода и слишком все упростить.
#include "hal/cmsis/stm32f4xx.h"
static void
mTrans(float *X, const float *A, int M, int N)
{
int i, j;
for (i = 0; i < M; ++i)
for (j = 0; j < N; ++j) {
X[j * M + i] = A[i * N + j];
}
}
static void
mMul(float *X, const float *A, const float *B, int M, int N, int K)
{
int i, j, k;
float s;
for (i = 0; i < M; ++i)
for (j = 0; j < N; ++j) {
s = 0.f;
for (k = 0; k < K; ++k)
s += A[i * K + k] * B[k * N + j];
X[i * N + j] = s;
}
}
static float P[25];
void sKF()
{
float A[25], AT[25], AP[25];
int i, j;
int T0, T1;
float dT;
for (i = 0; i < 5; ++i)
for (j = 0; j < 5; ++j) {
P[i * 5 + j] = 1.f / (float) SysTick->VAL;
}
for (i = 0; i < 5; ++i)
for (j = 0; j < 5; ++j) {
A[i * 5 + j] = 1.f / (float) SysTick->VAL;
}
T0 = SysTick->VAL;
mTrans(AT, A, 5, 5);
mMul(AP, A, P, 5, 5, 5);
mMul(P, AP, AT, 5, 5, 5);
T1 = SysTick->VAL;
printf("TICK (%i %i) %i \r\n", T0, T1, T0 - T1);
}
Весь код здесь.
Тест делался как я уже говорил на stm32f4discovery, частота 168МГц. Код находился в RAM либо во FLASH, переменные в RAM, стек в CCM. Посторонних задач не было, только uart, led и таймер.
GCC (RAM/FLASH):
-O2 4709/3677 ticks (2196 bytes) 19/23 MFLOPS
-O3 1658/1473 ticks (3596 bytes) 53/60 MFLOPS
-Os 5615/3714 ticks (1908 bytes) 16/24 MFLOPS
Clang (RAM):
-O2 2917 ticks (2664 bytes) 30 MFLOPS
-O3 1770 ticks (3304 bytes) 50 MFLOPS
-Os 5867 ticks (2496 bytes) 15 MFLOPS
На тестах из FLASH первый запуск был на 10-20 тактов дольше, дальше стабильно. Из RAM стабильно всегда. Итого для такой тактовой частоты получаем одну операцию с float на ~3 такта. И наверно можно выдавить еще скорости, положить переменные в CCM, развернуть циклы вручную, учесть разреженность матриц.
Неплохо, но для моей задачи мало. Похоже снова придется отказатся от фильтра Калмана и пойти на третий круг.
Добавка
Сделал еще один тест, с более развернутым кодом. Теперь простое одиночное уменожение двух матриц размера 5 на 5. Можете посчитать, для этого нужно 125 умножений и 100 сложений, всего 225 операций. На это количество операций я и буду пересчитывать такты во флопсы.float P[25];
void sKF()
{
float A[25], B[25];
int j, T0, T1;
float dT;
for (j = 0; j < 25; ++j)
A[j] = 1.f / (float) SysTick->VAL;
for (j = 0; j < 25; ++j)
B[j] = 1.f / (float) SysTick->VAL;
T0 = SysTick->VAL;
__DSB();
P[0] = A[0] * B[0] + A[1] * B[5] + A[2] * B[10] + A[3] * B[15] + A[4] * B[20];
P[1] = A[0] * B[1] + A[1] * B[6] + A[2] * B[11] + A[3] * B[16] + A[4] * B[21];
P[2] = A[0] * B[2] + A[1] * B[7] + A[2] * B[12] + A[3] * B[17] + A[4] * B[22];
P[3] = A[0] * B[3] + A[1] * B[8] + A[2] * B[13] + A[3] * B[18] + A[4] * B[23];
P[4] = A[0] * B[4] + A[1] * B[9] + A[2] * B[14] + A[3] * B[19] + A[4] * B[24];
P[5] = A[5] * B[0] + A[6] * B[5] + A[7] * B[10] + A[8] * B[15] + A[9] * B[20];
P[6] = A[5] * B[1] + A[6] * B[6] + A[7] * B[11] + A[8] * B[16] + A[9] * B[21];
P[7] = A[5] * B[2] + A[6] * B[7] + A[7] * B[12] + A[8] * B[17] + A[9] * B[22];
P[8] = A[5] * B[3] + A[6] * B[8] + A[7] * B[13] + A[8] * B[18] + A[9] * B[23];
P[9] = A[5] * B[4] + A[6] * B[9] + A[7] * B[14] + A[8] * B[19] + A[9] * B[24];
P[10] = A[10] * B[0] + A[11] * B[5] + A[12] * B[10] + A[13] * B[15] + A[14] * B[20];
P[11] = A[10] * B[1] + A[11] * B[6] + A[12] * B[11] + A[13] * B[16] + A[14] * B[21];
P[12] = A[10] * B[2] + A[11] * B[7] + A[12] * B[12] + A[13] * B[17] + A[14] * B[22];
P[13] = A[10] * B[3] + A[11] * B[8] + A[12] * B[13] + A[13] * B[18] + A[14] * B[23];
P[14] = A[10] * B[4] + A[11] * B[9] + A[12] * B[14] + A[13] * B[19] + A[14] * B[24];
P[15] = A[15] * B[0] + A[16] * B[5] + A[17] * B[10] + A[18] * B[15] + A[19] * B[20];
P[16] = A[15] * B[1] + A[16] * B[6] + A[17] * B[11] + A[18] * B[16] + A[19] * B[21];
P[17] = A[15] * B[2] + A[16] * B[7] + A[17] * B[12] + A[18] * B[17] + A[19] * B[22];
P[18] = A[15] * B[3] + A[16] * B[8] + A[17] * B[13] + A[18] * B[18] + A[19] * B[23];
P[19] = A[15] * B[4] + A[16] * B[9] + A[17] * B[14] + A[18] * B[19] + A[19] * B[24];
P[20] = A[20] * B[0] + A[21] * B[5] + A[22] * B[10] + A[23] * B[15] + A[24] * B[20];
P[21] = A[20] * B[1] + A[21] * B[6] + A[22] * B[11] + A[23] * B[16] + A[24] * B[21];
P[22] = A[20] * B[2] + A[21] * B[7] + A[22] * B[12] + A[23] * B[17] + A[24] * B[22];
P[23] = A[20] * B[3] + A[21] * B[8] + A[22] * B[13] + A[23] * B[18] + A[24] * B[23];
P[24] = A[20] * B[4] + A[21] * B[9] + A[22] * B[14] + A[23] * B[19] + A[24] * B[24];
__DSB();
T1 = SysTick->VAL;
printf("TICK (%i %i) %i \r\n", T0, T1, T0 - T1);
}
GCC (FLASH):
-O3 475 ticks 80 MFLOPS (~2.1 tick./op.)
Clang (FLASH):
-O3 540 ticks 70 MFLOPS (~2.4 tick./op.)
Clang выдал код без инструкции vmla, все только на vmul и vadd, возможно из-за этого результат хуже. Ну и вот код GCC от dsb до dsb, если кому будет не лень.
54: 6891 ldr r1, [r2, #8]
56: f3bf 8f4f dsb sy
5a: eddd 5a01 vldr s11, [sp, #4]
5e: ed9d 6a1e vldr s12, [sp, #120] ; 0x78
62: ed9d 0a00 vldr s0, [sp]
66: ed9d 4a19 vldr s8, [sp, #100] ; 0x64
6a: eddd 6a1f vldr s13, [sp, #124] ; 0x7c
6e: ed9d 7a20 vldr s14, [sp, #128] ; 0x80
72: eddd 7a21 vldr s15, [sp, #132] ; 0x84
76: eddd fa22 vldr s31, [sp, #136] ; 0x88
7a: eddd 4a1a vldr s9, [sp, #104] ; 0x68
7e: ed9d 5a1b vldr s10, [sp, #108] ; 0x6c
82: eddd da1d vldr s27, [sp, #116] ; 0x74
86: ed9d ea1c vldr s28, [sp, #112] ; 0x70
8a: ee25 2a86 vmul.f32 s4, s11, s12
8e: ee65 2aa6 vmul.f32 s5, s11, s13
92: ee25 3a87 vmul.f32 s6, s11, s14
96: ee00 2a04 vmla.f32 s4, s0, s8
9a: ee65 3aa7 vmul.f32 s7, s11, s15
9e: ee65 5aaf vmul.f32 s11, s11, s31
a2: eddd 0a02 vldr s1, [sp, #8]
a6: eddd ca23 vldr s25, [sp, #140] ; 0x8c
aa: ee40 2a24 vmla.f32 s5, s0, s9
ae: ee00 3a05 vmla.f32 s6, s0, s10
b2: ee40 3a0e vmla.f32 s7, s0, s28
b6: ee40 5a2d vmla.f32 s11, s0, s27
ba: eddd ba25 vldr s23, [sp, #148] ; 0x94
be: ed9d ba26 vldr s22, [sp, #152] ; 0x98
c2: eddd aa27 vldr s21, [sp, #156] ; 0x9c
c6: ed9d 0a24 vldr s0, [sp, #144] ; 0x90
ca: ee00 2aac vmla.f32 s4, s1, s25
ce: ed9d 1a03 vldr s2, [sp, #12]
d2: ee40 2a80 vmla.f32 s5, s1, s0
d6: ee00 3aab vmla.f32 s6, s1, s23
da: ee40 3a8b vmla.f32 s7, s1, s22
de: ee40 5aaa vmla.f32 s11, s1, s21
e2: eddd 0a28 vldr s1, [sp, #160] ; 0xa0
e6: eddd 9a29 vldr s19, [sp, #164] ; 0xa4
ea: ed9d 9a2a vldr s18, [sp, #168] ; 0xa8
ee: eddd 8a2b vldr s17, [sp, #172] ; 0xac
f2: ee01 2a20 vmla.f32 s4, s2, s1
f6: eddd 1a04 vldr s3, [sp, #16]
fa: ed9d 0a2c vldr s0, [sp, #176] ; 0xb0
fe: eddd 0a2d vldr s1, [sp, #180] ; 0xb4
102: ee41 2a29 vmla.f32 s5, s2, s19
106: ee01 3a09 vmla.f32 s6, s2, s18
10a: ee41 3a28 vmla.f32 s7, s2, s17
10e: ee01 2aa0 vmla.f32 s4, s3, s1
112: ee41 5a00 vmla.f32 s11, s2, s0
116: eddd 0a30 vldr s1, [sp, #192] ; 0xc0
11a: ed9d 1a2e vldr s2, [sp, #184] ; 0xb8
11e: ed9d 0a2f vldr s0, [sp, #188] ; 0xbc
122: ee41 2a81 vmla.f32 s5, s3, s2
126: ee01 3a80 vmla.f32 s6, s3, s0
12a: ee41 3aa0 vmla.f32 s7, s3, s1
12e: f240 0300 movw r3, #0
132: f2c0 0300 movt r3, #0
136: ed9d 1a31 vldr s2, [sp, #196] ; 0xc4
13a: ed83 2a00 vstr s4, [r3]
13e: edc3 2a01 vstr s5, [r3, #4]
142: ed83 3a02 vstr s6, [r3, #8]
146: edc3 3a03 vstr s7, [r3, #12]
14a: eddd 0a06 vldr s1, [sp, #24]
14e: ee41 5a81 vmla.f32 s11, s3, s2
152: eddd 1a05 vldr s3, [sp, #20]
156: ee26 aaa0 vmul.f32 s20, s13, s1
15a: ee04 aaa1 vmla.f32 s20, s9, s3
15e: ed9d 2a07 vldr s4, [sp, #28]
162: ed9d 0a24 vldr s0, [sp, #144] ; 0x90
166: ee26 ca20 vmul.f32 s24, s12, s1
16a: ee00 aa02 vmla.f32 s20, s0, s4
16e: ee27 8a20 vmul.f32 s16, s14, s1
172: ee27 0aa0 vmul.f32 s0, s15, s1
176: ee6f 0aa0 vmul.f32 s1, s31, s1
17a: ee04 ca21 vmla.f32 s24, s8, s3
17e: ee05 8a21 vmla.f32 s16, s10, s3
182: ee0e 0a21 vmla.f32 s0, s28, s3
186: ee4d 0aa1 vmla.f32 s1, s27, s3
18a: ee0c ca82 vmla.f32 s24, s25, s4
18e: ee0b 8a82 vmla.f32 s16, s23, s4
192: ee0b 0a02 vmla.f32 s0, s22, s4
196: ee4a 0a82 vmla.f32 s1, s21, s4
19a: eddd 2a08 vldr s5, [sp, #32]
19e: ed9d 3a0b vldr s6, [sp, #44] ; 0x2c
1a2: ed9d 1a28 vldr s2, [sp, #160] ; 0xa0
1a6: ed9d 2a2c vldr s4, [sp, #176] ; 0xb0
1aa: eddd 3a0a vldr s7, [sp, #40] ; 0x28
1ae: ed9d fa15 vldr s30, [sp, #84] ; 0x54
1b2: edc3 5a04 vstr s11, [r3, #16]
1b6: eddd 5a10 vldr s11, [sp, #64] ; 0x40
1ba: ed9d da14 vldr s26, [sp, #80] ; 0x50
1be: eddd ea0f vldr s29, [sp, #60] ; 0x3c
1c2: ee01 ca22 vmla.f32 s24, s2, s5
1c6: ee09 aaa2 vmla.f32 s20, s19, s5
1ca: ee09 8a22 vmla.f32 s16, s18, s5
1ce: ee26 1a03 vmul.f32 s2, s12, s6
1d2: ee08 0aa2 vmla.f32 s0, s17, s5
1d6: ee42 0a22 vmla.f32 s1, s4, s5
1da: ee66 1a83 vmul.f32 s3, s13, s6
1de: ee27 2a03 vmul.f32 s4, s14, s6
1e2: ee67 2a83 vmul.f32 s5, s15, s6
1e6: ee2f 3a83 vmul.f32 s6, s31, s6
1ea: ee04 1a23 vmla.f32 s2, s8, s7
1ee: ee44 1aa3 vmla.f32 s3, s9, s7
1f2: ee05 2a23 vmla.f32 s4, s10, s7
1f6: ee4e 2a23 vmla.f32 s5, s28, s7
1fa: ee0d 3aa3 vmla.f32 s6, s27, s7
1fe: ee66 3a25 vmul.f32 s7, s12, s11
202: ee26 6a0f vmul.f32 s12, s12, s30
206: ee44 3a2e vmla.f32 s7, s8, s29
20a: ee04 6a0d vmla.f32 s12, s8, s26
20e: ee26 4aa5 vmul.f32 s8, s13, s11
212: ee66 6a8f vmul.f32 s13, s13, s30
216: ee04 4aae vmla.f32 s8, s9, s29
21a: ee44 6a8d vmla.f32 s13, s9, s26
21e: ee67 4a25 vmul.f32 s9, s14, s11
222: ee27 7a0f vmul.f32 s14, s14, s30
226: ee45 4a2e vmla.f32 s9, s10, s29
22a: ee05 7a0d vmla.f32 s14, s10, s26
22e: ee27 5aa5 vmul.f32 s10, s15, s11
232: ee6f 5aa5 vmul.f32 s11, s31, s11
236: ee67 7a8f vmul.f32 s15, s15, s30
23a: ee2f fa8f vmul.f32 s30, s31, s30
23e: ee4d 5aae vmla.f32 s11, s27, s29
242: ee4e 7a0d vmla.f32 s15, s28, s26
246: ee0d fa8d vmla.f32 s30, s27, s26
24a: ed9d da0c vldr s26, [sp, #48] ; 0x30
24e: eddd da24 vldr s27, [sp, #144] ; 0x90
252: ee0e 5a2e vmla.f32 s10, s28, s29
256: ee0c 1a8d vmla.f32 s2, s25, s26
25a: ee4d 1a8d vmla.f32 s3, s27, s26
25e: ee0b 2a8d vmla.f32 s4, s23, s26
262: ee4b 2a0d vmla.f32 s5, s22, s26
266: ee0a 3a8d vmla.f32 s6, s21, s26
26a: ed9d da11 vldr s26, [sp, #68] ; 0x44
26e: ee4c 3a8d vmla.f32 s7, s25, s26
272: ee0d 4a8d vmla.f32 s8, s27, s26
276: ee4b 4a8d vmla.f32 s9, s23, s26
27a: ee0b 5a0d vmla.f32 s10, s22, s26
27e: ee4a 5a8d vmla.f32 s11, s21, s26
282: ed9d da16 vldr s26, [sp, #88] ; 0x58
286: ee0c 6a8d vmla.f32 s12, s25, s26
28a: ee4d 6a8d vmla.f32 s13, s27, s26
28e: ee0b 7a8d vmla.f32 s14, s23, s26
292: ee4b 7a0d vmla.f32 s15, s22, s26
296: ee0a fa8d vmla.f32 s30, s21, s26
29a: ed9d ba12 vldr s22, [sp, #72] ; 0x48
29e: eddd aa17 vldr s21, [sp, #92] ; 0x5c
2a2: eddd ca28 vldr s25, [sp, #160] ; 0xa0
2a6: eddd da2c vldr s27, [sp, #176] ; 0xb0
2aa: eddd ba0d vldr s23, [sp, #52] ; 0x34
2ae: ee4c 3a8b vmla.f32 s7, s25, s22
2b2: ee0c 6aaa vmla.f32 s12, s25, s21
2b6: ee09 4a8b vmla.f32 s8, s19, s22
2ba: ee49 6aaa vmla.f32 s13, s19, s21
2be: ee49 4a0b vmla.f32 s9, s18, s22
2c2: ee09 7a2a vmla.f32 s14, s18, s21
2c6: ee08 5a8b vmla.f32 s10, s17, s22
2ca: ee4d 5a8b vmla.f32 s11, s27, s22
2ce: ee48 7aaa vmla.f32 s15, s17, s21
2d2: ed9d ba09 vldr s22, [sp, #36] ; 0x24
2d6: ee0d faaa vmla.f32 s30, s27, s21
2da: eddd aa2d vldr s21, [sp, #180] ; 0xb4
2de: ee0c 1aab vmla.f32 s2, s25, s23
2e2: ee0a ca8b vmla.f32 s24, s21, s22
2e6: eddd ca2f vldr s25, [sp, #188] ; 0xbc
2ea: eddd aa31 vldr s21, [sp, #196] ; 0xc4
2ee: ee49 1aab vmla.f32 s3, s19, s23
2f2: ee09 2a2b vmla.f32 s4, s18, s23
2f6: ee48 2aab vmla.f32 s5, s17, s23
2fa: ee0d 3aab vmla.f32 s6, s27, s23
2fe: eddd ba2e vldr s23, [sp, #184] ; 0xb8
302: eddd da30 vldr s27, [sp, #192] ; 0xc0
306: eddd 9a0e vldr s19, [sp, #56] ; 0x38
30a: ed9d 9a13 vldr s18, [sp, #76] ; 0x4c
30e: eddd 8a18 vldr s17, [sp, #96] ; 0x60
312: ee0b aa8b vmla.f32 s20, s23, s22
316: ee0c 8a8b vmla.f32 s16, s25, s22
31a: ee0d 0a8b vmla.f32 s0, s27, s22
31e: ee4a 0a8b vmla.f32 s1, s21, s22
322: ed9d ba2d vldr s22, [sp, #180] ; 0xb4
326: ee4b 1aa9 vmla.f32 s3, s23, s19
32a: ee0b 1a29 vmla.f32 s2, s22, s19
32e: ee0c 2aa9 vmla.f32 s4, s25, s19
332: ee4d 2aa9 vmla.f32 s5, s27, s19
336: ee0a 3aa9 vmla.f32 s6, s21, s19
33a: ee4b 3a09 vmla.f32 s7, s22, s18
33e: ee0b 6a28 vmla.f32 s12, s22, s17
342: ee0b 4a89 vmla.f32 s8, s23, s18
346: ee4b 6aa8 vmla.f32 s13, s23, s17
34a: ee4c 4a89 vmla.f32 s9, s25, s18
34e: ee0c 7aa8 vmla.f32 s14, s25, s17
352: ee0d 5a89 vmla.f32 s10, s27, s18
356: ee4a 5a89 vmla.f32 s11, s21, s18
35a: ee4d 7aa8 vmla.f32 s15, s27, s17
35e: ee0a faa8 vmla.f32 s30, s21, s17
362: ed83 ca05 vstr s24, [r3, #20]
366: ed83 aa06 vstr s20, [r3, #24]
36a: ed83 8a07 vstr s16, [r3, #28]
36e: ed83 0a08 vstr s0, [r3, #32]
372: edc3 0a09 vstr s1, [r3, #36] ; 0x24
376: ed83 1a0a vstr s2, [r3, #40] ; 0x28
37a: edc3 1a0b vstr s3, [r3, #44] ; 0x2c
37e: ed83 2a0c vstr s4, [r3, #48] ; 0x30
382: edc3 2a0d vstr s5, [r3, #52] ; 0x34
386: ed83 3a0e vstr s6, [r3, #56] ; 0x38
38a: edc3 3a0f vstr s7, [r3, #60] ; 0x3c
38e: ed83 4a10 vstr s8, [r3, #64] ; 0x40
392: edc3 4a11 vstr s9, [r3, #68] ; 0x44
396: ed83 5a12 vstr s10, [r3, #72] ; 0x48
39a: edc3 5a13 vstr s11, [r3, #76] ; 0x4c
39e: ed83 6a14 vstr s12, [r3, #80] ; 0x50
3a2: edc3 6a15 vstr s13, [r3, #84] ; 0x54
3a6: ed83 7a16 vstr s14, [r3, #88] ; 0x58
3aa: edc3 7a17 vstr s15, [r3, #92] ; 0x5c
3ae: ed83 fa18 vstr s30, [r3, #96] ; 0x60
3b2: f3bf 8f4f dsb sy
3b6: 6892 ldr r2, [r2, #8]
Пробовал включить remap в SYSCFG->MEMRMP но скорость выполнения кода из RAM не изменилась, она ниже чем из флеша.
- +4
- 25 ноября 2014, 20:58
- amaora
Если оценивать ядро — не лучше ли было на асме тест писать? Или интересует именно производительность кода на С?
Да, неудачно назвал пост. Интересует С и как хорошо компиляторы справляются. То есть ближе к реальности.
Как-то не интересовался никогда, как и на каких условиях их можно получить. Есть ли линуксовая версия. И наверно еще какие-то компиляторы есть, сравнить конечно было бы интересно.
Так и просят сравнить основные компиляторы.
ЗЫ. Подозреваю что интерес к Clang'у на уровне погрешности.
ЗЫ. Подозреваю что интерес к Clang'у на уровне погрешности.
- zloe_morkoffko
- 27 ноября 2014, 00:40
- ↑
- ↓
Подозреваю что интерес к Clang'у на уровне погрешностиДа ну! Как бы не получилось так, что многие ARM-мэны резко не перескочили в следующем году с GCC на Clang, т.е. ломанный ARM DS-5.
- well-man2000
- 27 ноября 2014, 22:42
- ↑
- ↓
И много народу этим пользуется? В основном все на IAR'е и Eclipce сидят вроде
- zloe_morkoffko
- 28 ноября 2014, 16:43
- ↑
- ↓
Он же вроде контроллером моделистского BLDC занимается, а ставить туда i7 как-то…
Да и эти МК уже вполне полноценный процессор, хотя для данной задачи, возможно, лучше бы подошел DSP.
Да и эти МК уже вполне полноценный процессор, хотя для данной задачи, возможно, лучше бы подошел DSP.
Он же вроде контроллером моделистского BLDC занимается, а ставить туда i7 как-то…

- well-man2000
- 26 ноября 2014, 20:02
- ↑
- ↓
Неплохо, но для моей задачи мало.Можно поподробнее о задаче? Всё же 50 мегафлопсов, мечта настолки двадцатилетней давности.
- count_enable
- 26 ноября 2014, 00:54
- ↓
Да вот еще посчитал, может быть и умещается. Фильтр на 4-5 переменных скорее всего уместиться, но хочется на 7-9 переменных, с адаптацией к изменению сопротивления обмотки, потока от магнитов, параметров магнитопровода. Подробнее надо отдельно рассказывать. Недостаток производительности от того, что сигналы быстро изменяющиеся. Частота фильтра как минимум 20кГц. То есть надо все успевать за ~8к тактов, а лучше за 4к.
IMHO, в коде многовато «шума» в виде целочисленных умножений, которые негативно влияют на производительность. Скажем, во всех циклах выражения типа i*N/i*K можно вынести из тела цикла. Да и вообще мне не совсем понятно зачем было реализовывать адресную арифметику руками и использовать одномерные массивы, при том, что работа идет с матрицами.
Кстати, насколько я понимаю, задача может вполне вписаться в DSP extension Cortex-M4 (у stm-ок оно тоже есть). Возможно имеет смысл покопать в этом направлении, все-таки 16/32 умножение-сложение за один такт или два 16/16 умножения-сложения за один такт это весьма немало.
Кстати, насколько я понимаю, задача может вполне вписаться в DSP extension Cortex-M4 (у stm-ок оно тоже есть). Возможно имеет смысл покопать в этом направлении, все-таки 16/32 умножение-сложение за один такт или два 16/16 умножения-сложения за один такт это весьма немало.
Это черновой вариант для отладки. Окончательный вариант должен учитывать разреженность и симметричность матриц. Ну и циклы все развернуты будут.
Для компиляторов, мне кажется, давно уже не имеют значения такие мелочи как размерность массива и вручную введенная индексация. Они распознают, что выражения эквивалентны, и неизменное слагаемое за цикл вынесут.
С DSP extension, там целые числа, фильтр Калмана на них переложить не просто. Там же матрица ковариации, а в ней легко могут быть в одном элементе 10^3 а в другом 10^-8. А еще сколько с ними всякой возни (выбрать правильно диапазон, следить за переполнением), даже без фильтра.
Для компиляторов, мне кажется, давно уже не имеют значения такие мелочи как размерность массива и вручную введенная индексация. Они распознают, что выражения эквивалентны, и неизменное слагаемое за цикл вынесут.
С DSP extension, там целые числа, фильтр Калмана на них переложить не просто. Там же матрица ковариации, а в ней легко могут быть в одном элементе 10^3 а в другом 10^-8. А еще сколько с ними всякой возни (выбрать правильно диапазон, следить за переполнением), даже без фильтра.
Это черновой вариант для отладки.Я понимаю. Я больше к тому, что на таком коде сложно делать оценки производительности.
Для компиляторов, мне кажется, давно уже не имеют значения такие мелочи как размерность массива и вручную введенная индексация. Они распознают, что выражения эквивалентны, и неизменное слагаемое за цикл вынесут.Возможно. Но, как по мне, не стоит нагружать компилятор без необходимости. Тем более, что двухмерный массив и читать и понимать проще.
А с какой опцией -mfloat-abi компилировалось, 'softfp' или 'hard'? Исходя из моей практики, 'hard' даёт на 5-10% более быстрый код.
А с какой опцией -mfloat-abi компилировалось, 'softfp' или 'hard'?Попробовал собрать проект с опцией 'hard' — вообще не собралось… Что бы это значило? Тулчайн (или его либы) не поддерживает данную опцию?
Тулчайн — Yagarto.
Скорее всего нет либ, собранных для 'hard'. Можно взять какую-нибудь сборку с launchpad.net/gcc-arm-embedded/+download — там с поддержкой 'hard' собрано.
На эту тему даже статью тут писал
we.easyelectronics.ru/STM32/osobennosti-vybora-i-ustanovki-stm32f4-tulcheyna-na-macos-x-1075.html
we.easyelectronics.ru/STM32/osobennosti-vybora-i-ustanovki-stm32f4-tulcheyna-na-macos-x-1075.html
Попробовал собрать ещё раз. Получил такое сообщение:
Получается что опция hard линкеру указана.
Building target: stm_01.elf
Invoking: Cross ARM C++ Linker
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O2 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -g3 -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"stm_01.map" -o "stm_01.elf" ./system/src/stm32f4-hal/stm32f4xx_hal.o ./system/src/stm32f4-hal/stm32f4xx_hal_cortex.o ./system/src/stm32f4-hal/stm32f4xx_hal_flash.o ./system/src/stm32f4-hal/stm32f4xx_hal_flash_ex.o ./system/src/stm32f4-hal/stm32f4xx_hal_flash_ramfunc.o ./system/src/stm32f4-hal/stm32f4xx_hal_gpio.o ./system/src/stm32f4-hal/stm32f4xx_hal_iwdg.o ./system/src/stm32f4-hal/stm32f4xx_hal_pcd_ex.o ./system/src/stm32f4-hal/stm32f4xx_hal_pwr.o ./system/src/stm32f4-hal/stm32f4xx_hal_pwr_ex.o ./system/src/stm32f4-hal/stm32f4xx_hal_rcc.o ./system/src/stm32f4-hal/stm32f4xx_hal_rcc_ex.o ./system/src/newlib/_cxx.o ./system/src/newlib/_exit.o ./system/src/newlib/_sbrk.o ./system/src/newlib/_startup.o ./system/src/newlib/_syscalls.o ./system/src/newlib/_write.o ./system/src/newlib/assert.o ./system/src/diag/Trace.o ./system/src/diag/trace_impl.o ./system/src/cortexm/_initialize_hardware.o ./system/src/cortexm/_reset_hardware.o ./system/src/cortexm/exception_handlers.o ./system/src/CMSIS/system_stm32f4xx.o ./system/src/CMSIS/vectors_stm32f4xx.o ./src/BlinkLed.o ./src/Timer.o ./src/_initialize_hardware.o ./src/main.o
c:/yagarto_20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/bin/ld.exe: error: stm_01.elf uses VFP register arguments, c:/yagarto_20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libg.a(lib_a-svfiprintf.o) does not
c:/yagarto_20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/bin/ld.exe: failed to merge target specific data of file c:/yagarto_20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libg.a(lib_a-svfiprintf.o)
...
collect2.exe: error: ld returned 1 exit status
make: *** [stm_01.elf] Ошибка 1
Получается что опция hard линкеру указана.
Код совершенно лажовый в смысле объема — переписать все на asm (float point команды MAC VM**.F32 выполняются за 3 такта у Cortex-M4(см. стр.70)). И развернуть циклы. Если кто не знает что такое разворачивание цикла, это, например, следующий код:
int i;
float a = 0;
for (i = 0; i < 256; i++) {
a += b*c;
}
превращаем в такой код:int i;
float a = 0;
for (i = 0; i < 16; i++) {
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
a += b*c;
}
т.е. в разы/десятки уменьшаем паразитное время на выполнение команд перехода и инкремента счетчика в цикле.
- well-man2000
- 26 ноября 2014, 23:01
- ↓
Ну и… получил 80 MFLOPS, но самое интересное: а сколько надо было в итоге для реализации задачи? (Публика застыла в молчаливом ожидании)
- well-man2000
- 27 ноября 2014, 21:57
- ↑
- ↓
Задача поставлена не так. Я оцениваю на сколько я могу рассчитывать, а не сколько надо. На более быстрые DSP переходить не хочется по разным причинам.
Пока насчитал, что смогу оценивать 8 переменных, из которых 3 (R, L, E) постоянные плавающие от температуры и нелинейности в магнитопроводе. Можно оставить только 5 переменных а постоянные оценивать заранее, при неподвижном роторе. Фильтр выдерживает уходы до 20%..40% судя по малочисленным тестам на модели. А можно добавить еще 2-3 переменных (дрейфы датчиков тока), но уже будет толстовато, и неизвестно получится ли все оценивать одновременно. Вариантов много, можно переключать фильтры во время работы, секунду оцениваем дрейфа, дальше снова R,L,E.
Пока насчитал, что смогу оценивать 8 переменных, из которых 3 (R, L, E) постоянные плавающие от температуры и нелинейности в магнитопроводе. Можно оставить только 5 переменных а постоянные оценивать заранее, при неподвижном роторе. Фильтр выдерживает уходы до 20%..40% судя по малочисленным тестам на модели. А можно добавить еще 2-3 переменных (дрейфы датчиков тока), но уже будет толстовато, и неизвестно получится ли все оценивать одновременно. Вариантов много, можно переключать фильтры во время работы, секунду оцениваем дрейфа, дальше снова R,L,E.
А какой rate оцифровки с ADC датчиков будет на входе этого фильтра? Это вопрос по поводу 80 MFLOPS.
P.S. Есть аналог такого(проектируемого) BLDC-контроллера уже at the Globe? И где его можно купить?
P.S. Есть аналог такого(проектируемого) BLDC-контроллера уже at the Globe? И где его можно купить?
- well-man2000
- 30 ноября 2014, 00:42
- ↑
- ↓
Ну вот, почти голый фильтр на 6 переменных, достаточно оптимизированный, занимает 2756 тактов из 8400 доступных (~33%) при частоте 20кГц. Но этого мало, этих шести переменных хватит если заранее оценить сопротивление, индуктивности, и если нужно момент инерции. А измерения датчиков тока не должны содержать сильно дрейфующей постоянной составляющей. Ну и сопротивление обмотки не должно сильно изменяться во время работы, то есть надо брать значение для рабочего режима а не холодного двигателя.
Запас конечно еще есть, но с увеличением количества переменных сложность растет не линейно. А всего было бы хорошо оценивать 12 переменных.
Запас конечно еще есть, но с увеличением количества переменных сложность растет не линейно. А всего было бы хорошо оценивать 12 переменных.
Комментарии (40)
RSS свернуть / развернуть