Jump to content

    
Salamander

Как наибыстрейше вывести на экран точку?

Recommended Posts

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" - это не просто одна команда, а отсыл к жуткой софтовой тягомотине?

Не серчайте на мое упрямство. Я не знал некоторых тонкостей и, думал, что это вы меня не понимаете. Спасибо за то, что терпеливо разъяснили.

Share this post


Link to post
Share on other sites

Совершенно верно. И кстати я тестировал софтовые флоаты - они не очень тяжелые за счет 32х битности платформы. А вот даблы софтовые куда как тяжелее. 

Грубо говоря на платформе M3 софтовые даблы считаются в три раза дольше чем софтовые флоаты. А аппаратные флоаты в десять раз быстрее чем софтварные флоаты.

На такой синтетической формуле

 

 = add(result[0], result[1]);
 = mul(result[0], result[2]);
 = div(result[1], result[2]);

Edited by Михась

Share this post


Link to post
Share on other sites
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 раз, но все же в разы быстрее.

 

Все понял, буду чистить библиотеку...

Share this post


Link to post
Share on other sites
1 час назад, Salamander сказал:

Это об этом мне компилятор говорит?

А вы владеете английским? Или хотя бы google translate? Тексты ошибок и предупреждений компиляторов обычно уже сами по себе информативны. Если нет, то вбивание их в гугл обычно позволяет понять причину недовольства компилятоар после чтения первых двух-трёх ссылок.

 

51 минуту назад, Salamander сказал:

это не просто одна команда, а отсыл к жуткой софтовой тягомотине?

Команда одна. И это отсыл к жуткой софтовой тягомотине. Вернее вызов этой "тягомотины" с последующим возвратом, т.к. адрес инструкции после BL автоматически сохраняется в регистре LR процессора. Т.е. процессор "знает" куда вернуться. Но всё же читайте описание команд. В Technical Reference Manual на ваш процессор (не микроконтроллер) это одна таблица! с кратким описанием. Хотя можете посмотреть и детальное описание, перейдя на нужную страницу.

53 минуты назад, Salamander сказал:

Я не знал некоторых тонкостей и, думал, что это вы меня не понимаете.

Да, это типичное заблуждение начинающих. Не обижайтесь) Себя я тоже имею в виду)

37 минут назад, Salamander сказал:

Все понял, буду чистить библиотеку..

Это правильно. Но, самое главное, читайте документацию на компилятор, линкер и ваш процессор, микроконтроллер. Да, её очень много. Но читать можно по-маленьку, каждый день хотя бы по паре страничек общим планом. И детальные главы когда встретите конкретную проблему.

Share this post


Link to post
Share on other sites
16 minutes ago, Arlleex said:

А теперь не делите на 3.0f, а умножьте на 1/3.0f.

P.S. Вам уже даже предлагали это:smile:

Интересно, почему компилятор сам так не делает?

Share this post


Link to post
Share on other sites
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. Вам уже даже предлагали это:smile:

Да, точно. По нескольку раз приходится повторять... :unknw:

16 минут назад, Михась сказал:

Интересно, почему компилятор сам так не делает?

Возможно потому, что с его точки зрения деление и умножение на обратное число дадут немного разные результаты.

А вот почему такие очвидные вещи не сделал автор "либы" - неизвестно. Или его компилятор заменяет или такой он писатель.  :unknw:

Share this post


Link to post
Share on other sites
40 minutes ago, jcxz said:

Слишком много. Я уже вам советовал - замените деление на умножение - будет значительно быстрее:

vnFace[0] = (v1[6] + v2[6] + v3[6]) * (1.f / 3);

 

Получилось 14-14-19 тиков.

Share this post


Link to post
Share on other sites
1 час назад, Arlleex сказал:

А теперь не делите на 3.0f, а умножьте на 1/3.0f.

О, это интересно. Разве есть такое представление числа? И разве в этом выражении нет деления?

Share this post


Link to post
Share on other sites
3 минуты назад, Salamander сказал:

Получилось 14-14-19 тиков.

ну вот! Наконец-то!  :dance4:

2 минуты назад, Herz сказал:

О, это интересно. Разве есть такое представление числа? И разве в этом выражении нет деления?

(1.f/3) - константа, вычисляемая на этапе компиляции компилятором. А на этапе выполнения деления уже нет, только умножение.

Share this post


Link to post
Share on other sites
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--;
  }
}

Это явно "софтовая тягомотина". Она имеет аналог в аппаратном исполнении? Это ошибка автора библиотеки - использовать эту функцию вместо аппаратной или это вынужденная мера?

Share this post


Link to post
Share on other sites
17 минут назад, Salamander сказал:

Вот тут никаких фортелей типа замены деления на умножение не надо сделать?


yScale = 1.0f / tan(fov * 0.5f);

Ищите прототип фоункции tan(). Скорее всего она принимает double-аргумент. Возможно нужно заменить на tanf() или что-то в этом духе.

Цитата

Смущает еще вот такая шляпа в листинге

Криминала нет. Внутри думаю только float. (суффикс _f32 как бы намекает)

Возможно это что-то из математики матриц.

 

17 минут назад, Salamander сказал:

Это явно "софтовая тягомотина". Она имеет аналог в аппаратном исполнении? Это ошибка автора библиотеки - использовать эту функцию вместо аппаратной или это вынужденная мера?

"Софтового" тут ничего нет. Если у вас >= Cortex-M4, то ARM_MATH_DSP будет defined и будет выполняться соотв.ветка #if.

 

PS: Всё подряд оптимизировать нет смысла, только критичные по скорости места.

Share this post


Link to post
Share on other sites

Вернемся теперь к выходу за границы

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 попугаев.... Может в измерениях напутал, но тормоза на экране говорят об обратном. Буду искать, что грузит сильнее всего....

Share this post


Link to post
Share on other sites
9 часов назад, Salamander сказал:

Не в 10 раз, но все же в разы быстрее.

Загляните же уже в Technical Reference Manual:blum: Там есть таблица с инструкциями процессора (раздел 3.3.1 Cortex-M4 instructions) и сопроцессора (раздел 7.2.3 FPU instruction set). В таблице указано количество циклов, которое требуется для выполнения каждой команды.

Edited by MrBearManul

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.