Salamander 0 Posted January 11 · Report post 6 hours ago, jcxz said: все команды, начинающиеся на 'V' здесь - команды FPU одинарной точности. Если у вас скомпилилось с эмуляцией FPU, то вместо них будут стоять вызовы функций эмуляции (BL ...). Вот что я сделал h[0] = (a[0] + b[0] + c[0]) / 3.0; h[1] = (a[1] + b[1] + c[1]) / 3.0f; То есть, в одном месте поставил f, в другом оставил как есть. И вот листинг ;;;698 h[0] = (a[0] + b[0] + c[0]) / 3.0; 000016 ed950a00 VLDR s0,[r5,#0] 00001a edd60a00 VLDR s1,[r6,#0] 00001e ee300a20 VADD.F32 s0,s0,s1 000022 edd70a00 VLDR s1,[r7,#0] 000026 ee300a20 VADD.F32 s0,s0,s1 00002a ee101a10 VMOV r1,s0 00002e 4608 MOV r0,r1 000030 f7fffffe BL __aeabi_f2d 000034 ec410b19 VMOV d9,r0,r1 000038 ed9f0b37 VLDR d0,|L1.280| 00003c ec532b10 VMOV r2,r3,d0 000040 f7fffffe BL __aeabi_ddiv 000044 ec410b18 VMOV d8,r0,r1 000048 f7fffffe BL __aeabi_d2f 00004c 9003 STR r0,[sp,#0xc] ;;;699 h[1] = (a[1] + b[1] + c[1]) / 3.0f; 00004e ed950a01 VLDR s0,[r5,#4] 000052 edd60a01 VLDR s1,[r6,#4] 000056 ee300a20 VADD.F32 s0,s0,s1 00005a edd70a01 VLDR s1,[r7,#4] 00005e ee300a20 VADD.F32 s0,s0,s1 000062 eef00a08 VMOV.F32 s1,#3.00000000 000066 ee801a20 VDIV.F32 s2,s0,s1 00006a ed8d1a04 VSTR s2,[sp,#0x10] с "f" определенно короче. А судя по командам - FPU работает. И, как я понял, "BL __aeabi_f2d" - это не просто одна команда, а отсыл к жуткой софтовой тягомотине? Не серчайте на мое упрямство. Я не знал некоторых тонкостей и, думал, что это вы меня не понимаете. Спасибо за то, что терпеливо разъяснили. Quote Ответить с цитированием Share this post Link to post Share on other sites
Михась 0 Posted January 11 (edited) · Report post Совершенно верно. И кстати я тестировал софтовые флоаты - они не очень тяжелые за счет 32х битности платформы. А вот даблы софтовые куда как тяжелее. Грубо говоря на платформе M3 софтовые даблы считаются в три раза дольше чем софтовые флоаты. А аппаратные флоаты в десять раз быстрее чем софтварные флоаты. На такой синтетической формуле = add(result[0], result[1]); = mul(result[0], result[2]); = div(result[1], result[2]); Edited January 11 by Михась Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 11 · Report post 9 minutes ago, Михась said: Совершенно верно. И кстати я тестировал софтовые флоаты - они не очень тяжелые за счет 32х битности платформы. А вот даблы софтовые куда как тяжелее. Грубо говоря на платформе M3 софтовые даблы считаются в три раза дольше чем софтовые флоаты. А аппаратные флоаты в десять раз быстрее чем софтварные флоаты. Ну что я хочу сказать, вот число тиков DWT; vnFace[0] = (v1[6] + v2[6] + v3[6]) / 3.0; - от 160 до 190 vnFace[1] = (v1[7] + v2[7] + v3[7]) / 3.0; - от 110 до 280 vnFace[2] = (v1[8] + v2[8] + v3[8]) / 3.0; - от 85 до 205 А если аппаратно vnFace[0] = (v1[6] + v2[6] + v3[6]) / 3.0f; - 32 vnFace[1] = (v1[7] + v2[7] + v3[7]) / 3.0f; -35 vnFace[2] = (v1[8] + v2[8] + v3[8]) / 3.0f; -30 Не в 10 раз, но все же в разы быстрее. Все понял, буду чистить библиотеку... Quote Ответить с цитированием Share this post Link to post Share on other sites
MrBearManul 0 Posted January 11 · Report post 1 час назад, Salamander сказал: Это об этом мне компилятор говорит? А вы владеете английским? Или хотя бы google translate? Тексты ошибок и предупреждений компиляторов обычно уже сами по себе информативны. Если нет, то вбивание их в гугл обычно позволяет понять причину недовольства компилятоар после чтения первых двух-трёх ссылок. 51 минуту назад, Salamander сказал: это не просто одна команда, а отсыл к жуткой софтовой тягомотине? Команда одна. И это отсыл к жуткой софтовой тягомотине. Вернее вызов этой "тягомотины" с последующим возвратом, т.к. адрес инструкции после BL автоматически сохраняется в регистре LR процессора. Т.е. процессор "знает" куда вернуться. Но всё же читайте описание команд. В Technical Reference Manual на ваш процессор (не микроконтроллер) это одна таблица! с кратким описанием. Хотя можете посмотреть и детальное описание, перейдя на нужную страницу. 53 минуты назад, Salamander сказал: Я не знал некоторых тонкостей и, думал, что это вы меня не понимаете. Да, это типичное заблуждение начинающих. Не обижайтесь) Себя я тоже имею в виду) 37 минут назад, Salamander сказал: Все понял, буду чистить библиотеку.. Это правильно. Но, самое главное, читайте документацию на компилятор, линкер и ваш процессор, микроконтроллер. Да, её очень много. Но читать можно по-маленьку, каждый день хотя бы по паре страничек общим планом. И детальные главы когда встретите конкретную проблему. Quote Ответить с цитированием Share this post Link to post Share on other sites
Arlleex 0 Posted January 11 · Report post 41 минуту назад, Salamander сказал: Не в 10 раз, но все же в разы быстрее. А теперь не делите на 3.0f, а умножьте на 1/3.0f. P.S. Вам уже даже предлагали это Quote Ответить с цитированием Share this post Link to post Share on other sites
Михась 0 Posted January 11 · Report post 16 minutes ago, Arlleex said: А теперь не делите на 3.0f, а умножьте на 1/3.0f. P.S. Вам уже даже предлагали это Интересно, почему компилятор сам так не делает? Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 11 · Report post 1 час назад, Salamander сказал: vnFace[0] = (v1[6] + v2[6] + v3[6]) / 3.0f; - 32 vnFace[1] = (v1[7] + v2[7] + v3[7]) / 3.0f; -35 vnFace[2] = (v1[8] + v2[8] + v3[8]) / 3.0f; -30 Слишком много. Я уже вам советовал - замените деление на умножение - будет значительно быстрее: vnFace[0] = (v1[6] + v2[6] + v3[6]) * (1.f / 3); 34 минуты назад, Arlleex сказал: P.S. Вам уже даже предлагали это Да, точно. По нескольку раз приходится повторять... 16 минут назад, Михась сказал: Интересно, почему компилятор сам так не делает? Возможно потому, что с его точки зрения деление и умножение на обратное число дадут немного разные результаты. А вот почему такие очвидные вещи не сделал автор "либы" - неизвестно. Или его компилятор заменяет или такой он писатель. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 11 · Report post 40 minutes ago, jcxz said: Слишком много. Я уже вам советовал - замените деление на умножение - будет значительно быстрее: vnFace[0] = (v1[6] + v2[6] + v3[6]) * (1.f / 3); Получилось 14-14-19 тиков. Quote Ответить с цитированием Share this post Link to post Share on other sites
Herz 0 Posted January 11 · Report post 1 час назад, Arlleex сказал: А теперь не делите на 3.0f, а умножьте на 1/3.0f. О, это интересно. Разве есть такое представление числа? И разве в этом выражении нет деления? Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 11 · Report post 3 минуты назад, Salamander сказал: Получилось 14-14-19 тиков. ну вот! Наконец-то! 2 минуты назад, Herz сказал: О, это интересно. Разве есть такое представление числа? И разве в этом выражении нет деления? (1.f/3) - константа, вычисляемая на этапе компиляции компилятором. А на этапе выполнения деления уже нет, только умножение. Quote Ответить с цитированием Share this post Link to post Share on other sites
Herz 0 Posted January 11 · Report post Ясно, спасибо. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 11 · Report post 1 minute ago, jcxz said: ну вот! Наконец-то! Быстрее конечно стало, но в целом еще дофига где тормозов.... хотя везде, где значения указаны как 1.0, 3.0 и пр., я сделал замены. Вот тут никаких фортелей типа замены деления на умножение не надо сделать? yScale = 1.0f / tan(fov * 0.5f); Смущает еще вот такая шляпа в листинге ;;;187 arm_sub_f32(lightPosition, vertex, lightDirection, 3); 00000e 2303 MOVS r3,#3 000010 aa07 ADD r2,sp,#0x1c 000012 4621 MOV r1,r4 000014 4630 MOV r0,r6 000016 f7fffffe BL arm_sub_f32 В конце вызывается функция, которая в библиотеке arm_math... Вот ее текст? void arm_sub_f32( float32_t * pSrcA, float32_t * pSrcB, float32_t * pDst, uint32_t blockSize) { uint32_t blkCnt; /* loop counter */ #if defined (ARM_MATH_DSP) /* Run the below code for Cortex-M4 and Cortex-M3 */ float32_t inA1, inA2, inA3, inA4; /* temporary variables */ float32_t inB1, inB2, inB3, inB4; /* temporary variables */ /*loop Unrolling */ blkCnt = blockSize >> 2U; /* First part of the processing with loop unrolling. Compute 4 outputs at a time. ** a second loop below computes the remaining 1 to 3 samples. */ while (blkCnt > 0U) { /* C = A - B */ /* Subtract and then store the results in the destination buffer. */ /* Read 4 input samples from sourceA and sourceB */ inA1 = *pSrcA; inB1 = *pSrcB; inA2 = *(pSrcA + 1); inB2 = *(pSrcB + 1); inA3 = *(pSrcA + 2); inB3 = *(pSrcB + 2); inA4 = *(pSrcA + 3); inB4 = *(pSrcB + 3); /* dst = srcA - srcB */ /* subtract and store the result */ *pDst = inA1 - inB1; *(pDst + 1) = inA2 - inB2; *(pDst + 2) = inA3 - inB3; *(pDst + 3) = inA4 - inB4; /* Update pointers to process next sampels */ pSrcA += 4U; pSrcB += 4U; pDst += 4U; /* Decrement the loop counter */ blkCnt--; } /* If the blockSize is not a multiple of 4, compute any remaining output samples here. ** No loop unrolling is used. */ blkCnt = blockSize % 0x4U; #else /* Run the below code for Cortex-M0 */ /* Initialize blkCnt with number of samples */ blkCnt = blockSize; #endif /* #if defined (ARM_MATH_DSP) */ while (blkCnt > 0U) { /* C = A - B */ /* Subtract and then store the results in the destination buffer. */ *pDst++ = (*pSrcA++) - (*pSrcB++); /* Decrement the loop counter */ blkCnt--; } } Это явно "софтовая тягомотина". Она имеет аналог в аппаратном исполнении? Это ошибка автора библиотеки - использовать эту функцию вместо аппаратной или это вынужденная мера? Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted January 11 · Report post 17 минут назад, Salamander сказал: Вот тут никаких фортелей типа замены деления на умножение не надо сделать? yScale = 1.0f / tan(fov * 0.5f); Ищите прототип фоункции tan(). Скорее всего она принимает double-аргумент. Возможно нужно заменить на tanf() или что-то в этом духе. Цитата Смущает еще вот такая шляпа в листинге Криминала нет. Внутри думаю только float. (суффикс _f32 как бы намекает) Возможно это что-то из математики матриц. 17 минут назад, Salamander сказал: Это явно "софтовая тягомотина". Она имеет аналог в аппаратном исполнении? Это ошибка автора библиотеки - использовать эту функцию вместо аппаратной или это вынужденная мера? "Софтового" тут ничего нет. Если у вас >= Cortex-M4, то ARM_MATH_DSP будет defined и будет выполняться соотв.ветка #if. PS: Всё подряд оптимизировать нет смысла, только критичные по скорости места. Quote Ответить с цитированием Share this post Link to post Share on other sites
Salamander 0 Posted January 11 · Report post Вернемся теперь к выходу за границы Quote ..\Middlewares\Third_Party\dsp3D\src\dsp3D.c(804): warning: #61-D: integer operation result is out of range dsp3D_drawFaceGouraud(vertex_transform_a, vertex_transform_b, vertex_transform_c, ASSEMBLE_ARGB(0xFF, RGBr, RGBg, RGBb)); Тут самое интересное. Выход за границы вызывается макросом ASSEMBLE_ARGB - #define ASSEMBLE_ARGB(A,R,G,B) (A << 24 | R << 16 | G << 8 | B) Если написать к примеру так dsp3D_drawFaceGouraud(vertex_transform_a, vertex_transform_b, vertex_transform_c, 0xFFFFFFFF); // замена ASSEMBLE_ARGB на 0xFFFFFF То ошибка исчезает. Почему же? А вот почему - в нее подставляется RGBr, RGBg, RGBb. А они берутся из массива float32_t dsp3dModel[122] = {8,12, ...................} Задумка автора такова, что в однородном массиве запакованы и цвета и координаты и нормали. Поскольку нормали могут быть float32_t, то и все остальные данные - float32_t. Это не есть гуд? 7 minutes ago, jcxz said: Если у вас >= Cortex-M4, то ARM_MATH_DSP будет defined и будет выполняться соотв.ветка #if. У меня так #define ARM_MATH_CM7 #if defined(ARM_MATH_CM7) #include "core_cm7.h" #define ARM_MATH_DSP #elif defined (ARM_MATH_CM4) #include "core_cm4.h" #define ARM_MATH_DSP #elif defined (ARM_MATH_CM3) #include "core_cm3.h" #elif defined (ARM_MATH_CM0) #include "core_cm0.h" #define ARM_MATH_CM0_FAMILY 9 minutes ago, jcxz said: PS: Всё подряд оптимизировать нет смысла, только критичные по скорости места. Да вот что странно - вроде бы расчеты там, где деление меняли на умножение сократили с 200 до 14, а функция отрисовки одной точки все так же длится около 340 попугаев.... Может в измерениях напутал, но тормоза на экране говорят об обратном. Буду искать, что грузит сильнее всего.... Quote Ответить с цитированием Share this post Link to post Share on other sites
MrBearManul 0 Posted January 12 (edited) · Report post 9 часов назад, Salamander сказал: Не в 10 раз, но все же в разы быстрее. Загляните же уже в Technical Reference Manual Там есть таблица с инструкциями процессора (раздел 3.3.1 Cortex-M4 instructions) и сопроцессора (раздел 7.2.3 FPU instruction set). В таблице указано количество циклов, которое требуется для выполнения каждой команды. Edited January 12 by MrBearManul Quote Ответить с цитированием Share this post Link to post Share on other sites