Salamander 2 13 января, 2021 Опубликовано 13 января, 2021 (изменено) · Жалоба Почистил. Софтового FPU не стало. Но все равно ужасно медленно. Очень много времени (до 30 000 тактов) занимает вот этот фрагмент, выводящий одну линию. for (x = sx; x < ex; x++) { gradient = (float32_t)(x - sx) / (float32_t)(ex - sx); z = dsp3D_interpolate(z1, z2, gradient); ndl = dsp3D_interpolate(snl, enl, gradient); a = (color >> 24); r = (color >> 16); g = (color >> 8); b = (color); r = (uint8_t)((float32_t)r * ndl); g = (uint8_t)((float32_t)g * ndl); b = (uint8_t)((float32_t)b * ndl); dsp3D_drawPointDepthBuffer(x, y, z, ASSEMBLE_ARGB(a, r, g, b)); } НИЖЕ ТАК, ДЛЯ СПРАВКИ СОДЕРЖАНИЕ ИСПОЛЬЗУЕМЫХ ФУНКЦИЙ float32_t dsp3D_clamp(float32_t value) { return MAX(0.0f, MIN(value, 1.0f)); } float32_t dsp3D_interpolate(float32_t min, float32_t max, float32_t gradient) { return (min + (max - min) * dsp3D_clamp(gradient)); } Есть мысли по оптимизации? А вот дальше - может быть я туплю... смотрите, еще раз приведу фрагмент: for (x = sx; x < ex; x++) { gradient = (float32_t)(x - sx) / (float32_t)(ex - sx); z = dsp3D_interpolate(z1, z2, gradient); ndl = dsp3D_interpolate(snl, enl, gradient); a = (color >> 24); // значения a,r,g,b r = (color >> 16);// в этой части цикла всегда одни и те же g = (color >> 8);// логично же вынести эти 4 строки до начала цикла for? и пользоваться единожды вычисленными значениями... b = (color);// но если я это делаю - отрисовка меняется r = (uint8_t)((float32_t)r * ndl); g = (uint8_t)((float32_t)g * ndl); b = (uint8_t)((float32_t)b * ndl); dsp3D_drawPointDepthBuffer(x, y, z, ASSEMBLE_ARGB(a, r, g, b)); } Скажите, почему меняется работа функции, если я указанные 4 строки переношу до начала цикла? Ведь вычисление a,r,g,b из неменяющегося color дает одни и те же значения, так почему бы их не вычислить заранее и потом просто использовать? Чего я в упор не вижу? Изменено 13 января, 2021 пользователем Salamander Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 (изменено) · Жалоба 3 часа назад, Salamander сказал: Есть мысли по оптимизации? 1. Заинлайнить функции dsp3D*(), убедиться по листингу, что они заинлайнены, т.е. отсутствуют машинные команды BL. Не думаю, что это существенно поможет, но как первая идея оптимизации. 2. Не знаю, как в вашем компиляторе настраивается оптимизация, но если есть возможность, выставите оптимизировать по скорости. 3. Попробуйте подумать, как деление заменить на умножение. Это было бы быстрее. 4. Прочёсывайте листинг глазами ни один раз, выкидывайте все вызовы функций, преобразования типов и т.п. 3 часа назад, Salamander сказал: Чего я в упор не вижу? Под вашими четырьмя строками, которые вы хотите вынести за цикл, есть следующие строки, где ваши переменные r, g, b снова меняются. 3 часа назад, Salamander сказал: r = (uint8_t)((float32_t)r * ndl); g = (uint8_t)((float32_t)g * ndl); b = (uint8_t)((float32_t)b * ndl); Перепишите функцию так a = (color >> 24); // значения a,r,g,b r = (color >> 16);// в этой части цикла всегда одни и те же g = (color >> 8);// логично же вынести эти 4 строки до начала цикла for? и пользоваться единожды вычисленными значениями... b = (color);// но если я это делаю - отрисовка меняется for (x = sx; x < ex; x++) { gradient = (float32_t)(x - sx) / (float32_t)(ex - sx); z = dsp3D_interpolate(z1, z2, gradient); ndl = dsp3D_interpolate(snl, enl, gradient); const uint32_t rt = r * ndl; // нет смысла преобразовывать цвет в uint8_t, это лишние операции для процессора const uint32_t gt = g * ndl; // также нет смысла приводить цвет к float, его тип будет расширен автоматически, а текста будет меньше const uint32_t bt = b * ndl; dsp3D_drawPointDepthBuffer(x, y, z, ASSEMBLE_ARGB(a, rt, gt, bt)); } Уф, у меня тут утро. Надеюсь, что не накосматил с вашим кодом))) Проверяйте. Изменено 14 января, 2021 пользователем MrBearManul Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 30 14 января, 2021 Опубликовано 14 января, 2021 (изменено) · Жалоба MrBearManul опередил (-8Ж А TCу - отдыхать, глаз замылился; делитель "(float32_t)(ex - sx)" тоже до цикла один раз вычислять. Изменено 14 января, 2021 пользователем Obam Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 (изменено) · Жалоба 5 минут назад, Obam сказал: А TCу - отдыхать, глаз замылился; делитель "(float32_t)(ex - sx)" тоже до цикла один раз вычислять. Отдыхать это точно))) А вот делитель я и не заметил, что можно раньше вычислить. Тогда вычислить его как const float32_t devider_multiplier = 1.0f / (ex - sx); И дальше уже на него умножать. И тогда, согласно табличке с циклами инструкций, быстродействие прям должно взлететь))) Изменено 14 января, 2021 пользователем MrBearManul Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Salamander 2 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 4 hours ago, Obam said: А TCу - отдыхать, глаз замылился; Ух... это точно... в упор не увидел обновление r,g,b. До этого не застревал и, в общем-то работу провел большую. Один кубик в режиме flat дает 11 FPS на 1024х600. В режиме Gouraud - 6 FPS. И то - у меня пока не отсекается Z-буфер, по непонятным причинам в него идут кривые данные. А теперь результаты каждого из шагов: const float32_t divider_multiplier = 1.0f / (ex - sx); gradient = (float32_t)(x - sx) * divider_multiplier; было 31, стало 12 шагов const uint32_t rt = r * ndl; // нет смысла преобразовывать цвет в uint8_t, это лишние операции для процессора const uint32_t gt = g * ndl; // также нет смысла приводить цвет к float, его тип будет расширен автоматически, а текста будет меньше const uint32_t bt = b * ndl; было 48, стало 31 А вот "заинлайнивание" inline float32_t dsp3D_clamp(float32_t value) { return MAX(0.0f, MIN(value, 1.0f)); } inline float32_t dsp3D_interpolate(float32_t min, float32_t max, float32_t gradient) { return (min + (max - min) * dsp3D_clamp(gradient)); } наоборот добавило тормозов В одном месте было 216, стало 270 В другом было 70 стало 84. Листинг не смотрел, мне пора убегать. Но так, для информации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 9 минут назад, Salamander сказал: наоборот добавило тормозов Гм... странно. Убирается, как минимум BL (при вызове)/POP (при возврате). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Salamander 2 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 1 minute ago, MrBearManul said: Гм... странно. Убирается, как минимум BL (при вызове)/POP (при возврате). Проверю. А пока вопрос.... Хочу заменить конструкцию #define ASSEMBLE_ARGB(A,R,G,B) (A << 24 | R << 16 | G << 8 | B) const uint32_t rt = r * ndl; // нет смысла преобразовывать цвет в uint8_t, это лишние операции для процессора const uint32_t gt = g * ndl; // также нет смысла приводить цвет к float, его тип будет расширен автоматически, а текста будет меньше const uint32_t bt = b * ndl; *(__IO uint32_t*)(0xD0000000 + 3*(y * SCREEN_WIDTH + x))=ASSEMBLE_ARGB(a, r, g, b); на прямое присваивание. *(__IO uint32_t*)(0xD0000000 + 3*(y * SCREEN_WIDTH + x))=(a << 24) | ((r * ndl) << 16) | ((r * ndl) << 8) | (r * ndl); но компилятор негодует ..\Middlewares\Third_Party\dsp3D\src\dsp3D.c(515): error: #1460: expression must have integral or fixed-point type const uint32_t col =(a << 24) | ((r * ndl) << 16) | ((r * ndl) << 8) | (r * ndl); Во первых, мне непонятно, почему он не хочет сдвигать влево заключенное в скобках произведение, а во вторых - в теории, должно ли это сократить число тактов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 19 минут назад, Salamander сказал: Проверю. Проверьте. Возможно я погорячисля: пара инструкций убирается, но добавляются новые. Кто знает, что там оптимизатор с компилятором выдумают) 20 минут назад, Salamander сказал: Во первых, мне непонятно, почему он не хочет сдвигать влево заключенное в скобках произведение Потому что у вас там есь число с плавающей точкой, и, согласно стандарту, второй целосчисленный множитель будет расширен до этого же типа. А "флоаты" сдвигать бессмысленно. 21 минуту назад, Salamander сказал: на прямое присваивание. Рекомендую избегать адресов в виде магических чисел. Да и любых значений. Лучше писать константы с говорящими именами. Потом вам самому же легче будет программу модифицировать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Salamander 2 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 1 minute ago, MrBearManul said: Потому что у вас там есь число с плавающей точкой, и, согласно стандарту, второй целосчисленный множитель будет расширен до этого же типа. А "флоаты" сдвигать бессмысленно. то есть, нужно приводить к int, а именно это и делается в вашем объявлении переменной? Иными словами, это нельзя оптимизировать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 22 минуты назад, Salamander сказал: а во вторых - в теории, должно ли это сократить число тактов? Вряд ли. Макросы @define разворачиваются препроцессором (не компилятором), который работает с текстом без анализа синтаксиса. И будет примерно то же самое, что и вы предлагаете предоставлено компилятору. Оптимизировать имеет смысл именно код, т.е. то, что "схавает" компилятор. Оптимизаторы, конечно нынче очень умные. Но всё же прежде всего нужно постараться самому) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Salamander 2 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 10 minutes ago, MrBearManul said: Возможно я погорячисля: пара инструкций убирается, но добавляются новые. Кто знает, что там оптимизатор с компилятором выдумают) вот что он выдумывает sx = dsp3D_interpolate(pa[0], pb[0], gradient1); 0000a8 ed991a00 VLDR s2,[r9,#0] 0000ac eef00a41 VMOV.F32 s1,s2 0000b0 ed951a00 VLDR s2,[r5,#0] 0000b4 eeb00a41 VMOV.F32 s0,s2 0000b8 eeb01a49 VMOV.F32 s2,s18 0000bc f7fffffe BL dsp3D_interpolate 0000c0 eefd8ac0 VCVT.S32.F32 s17,s0 а вот без и инлайна ;;;550 sx = dsp3D_interpolate(pa[0], pb[0], gradient1); 0000ba ed951a00 VLDR s2,[r5,#0] 0000be eef00a41 VMOV.F32 s1,s2 0000c2 ed911a00 VLDR s2,[r1,#0] 0000c6 eeb00a41 VMOV.F32 s0,s2 0000ca eeb01a44 VMOV.F32 s2,s8 0000ce f7fffffe BL dsp3D_interpolate 0000d2 eefd3ac0 VCVT.S32.F32 s7,s0 разницы нет, но что добавилось, я не знаю, но адреса, если вы обратите внимание, сместились, значит что-то добавилось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 2 минуты назад, Salamander сказал: то есть, нужно приводить к int Да. 2 минуты назад, Salamander сказал: а именно это и делается в вашем объявлении переменной? Да. Но вы учтите, что я не вижу весь ваш код, работаю с отрывками, да у меня и своя работа есть))) Я могу и накосячить. Т.е. я вам излагаю основные принципы, детали вы должны сами проверить. Т.е. не принимать мой код, как истину в последней инстанции. 3 минуты назад, Salamander сказал: Иными словами, это нельзя оптимизировать? Честно говоря, не знаю. Я не вижу критериев оптимизации. Возможно, если бы долго сидел и разбирался, то нашёл. Может быть их увидят другие участники форума. При оптимизации программы нужно хорошо понимать работу железа, а это и процессор и периферия и эргономика и компилятор и много чего другого. Тут нельзя действовать в лоб. Если опыта недостаточно, то вы можете приготовить несколько вариантов кода, проанализировать быстродействие и выбрать подходящий, либо, почуяв, куда идти, оптимизировать дальше. Я обычно начинаю оптимизацию с количества машинных команд. Если на мой взгляд они занимают слишком много тактов (это не обязательно связано с их большим количеством), то стараюсь избавиться от вызова процедур, пытаюсь задействовать по-максимуму архитектуру. Например, ну уж совсем грубо, если нет FPU, то убираем плавающую точки и заменяем целочисленной арифметикой. Если нет целочисленного деления, то заменяем всё умножением. Если у нас на одной шине AHB висит и ПДП и процессор, то не ждём чуда быстродействия с использованием ПДП, который может заставить процессор курить в сторонке пока гонится "без процессора" 1 кб данных... Извините, что спонтанно, но примерно так и происходит. Нужны критерии оптимизации, а они могут проявиться только тогда, когда вы знаете с чем работаете. Тем не менее основная работа у вас уже всё-таки сделана) Количество тактов сократилось значительно Поэтому экспериментируйте, это же не опасно, вы же не двигателем на поезде управляете)))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Salamander 2 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба 1 minute ago, MrBearManul said: да у меня и своя работа есть))) Упаси бог меня требовать от вас делать что-то для меня в ущерб своей работе. 2 minutes ago, MrBearManul said: Я могу и накосячить. Т.е. я вам излагаю основные принципы, детали вы должны сами проверить. Т.е. не принимать мой код, как истину в последней инстанции. Так я так и делаю, не совсем я "бум-бум" )) 2 minutes ago, MrBearManul said: то стараюсь избавиться от вызова процедур Наверное я содержимое того, что инлайнится, перенесу внутрь целиком, посмотрю, что выйдет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 14 января, 2021 Опубликовано 14 января, 2021 (изменено) · Жалоба 31 минуту назад, Salamander сказал: а вот без и инлайна Так он не инлайнит dsp3_interpolate. Он как вызывал её с помощью BL так и вызывает. Попробуйте разместить функции в заголовочном файле (для Си++ это достустипо, как в Си - не помню, тут лучше почитать что-нить от классиков). Либо, возможно, что у вашего компилятора есть директива, которая заставит компилятор заинлайнить эти функции. 27 минут назад, Salamander сказал: Упаси бог меня требовать от вас делать что-то для меня в ущерб своей работе. Простите, я ничего такого не подразумевал, просто выразился немного некорректно, т.к. торопился) 27 минут назад, Salamander сказал: Так я так и делаю, не совсем я "бум-бум" )) Ещё раз простите, если дал повод думать в том направлении))) Писал всё в спешке, постараюсь так больше не делать))) 31 минуту назад, Salamander сказал: если вы обратите внимание, сместились, значит что-то добавилось. Вижу, что адреса инструкций изменились. Т.е. код "лёг" по другим адресам. Вполне возможно, не обязательно, что что-то добавилось. Возможно, что что-то переместилось с одного места на другое. Изменено 14 января, 2021 пользователем MrBearManul Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Salamander 2 14 января, 2021 Опубликовано 14 января, 2021 · Жалоба Just now, MrBearManul said: Так он не инлайнит dsp3_interpolate. Он как вызывал её с помощью BL так и вызывает. Я не так инлайню? inline float32_t dsp3D_interpolate(float32_t min, float32_t max, float32_t gradient) { return (min + (max - min) * dsp3D_clamp(gradient)); } 1 minute ago, MrBearManul said: Вполне возможно, не обязательно, что что-то добавилось. Возможно, что что-то переместилось с одного места на другое. есть у меня сравнивалка файлов. Погляжу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться