Перейти к содержанию
    

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

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

Чего я в упор не вижу?

Изменено пользователем Salamander

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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));
    }

Уф, у меня тут утро. Надеюсь, что не накосматил с вашим кодом))) Проверяйте.

Изменено пользователем MrBearManul

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

MrBearManul опередил (-8Ж
А TCу - отдыхать, глаз замылился; делитель "(float32_t)(ex - sx)" тоже до цикла один раз вычислять.

Изменено пользователем Obam

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, Obam сказал:

А TCу - отдыхать, глаз замылился; делитель "(float32_t)(ex - sx)" тоже до цикла один раз вычислять.

Отдыхать это точно))) А вот делитель я и не заметил, что можно раньше вычислить. Тогда вычислить его как

const float32_t devider_multiplier = 1.0f / (ex - sx);

И дальше уже на него умножать. И тогда, согласно табличке с циклами инструкций, быстродействие прям должно взлететь)))

Изменено пользователем MrBearManul

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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.

 

Листинг не смотрел, мне пора убегать. Но так, для информации.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

наоборот добавило тормозов

Гм... странно. Убирается, как минимум BL (при вызове)/POP (при возврате).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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);

Во первых, мне непонятно, почему он не хочет сдвигать влево заключенное в скобках произведение, а во вторых - в теории, должно ли это сократить число тактов?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Проверю.

Проверьте. Возможно я погорячисля: пара инструкций убирается, но добавляются новые. Кто знает, что там оптимизатор с компилятором выдумают)

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

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

Потому что у вас там есь число с плавающей точкой, и, согласно стандарту, второй целосчисленный множитель будет расширен до этого же типа. А "флоаты" сдвигать бессмысленно.

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

на прямое присваивание.

Рекомендую избегать адресов в виде магических чисел. Да и любых значений. Лучше писать константы с говорящими именами. Потом вам самому же легче будет программу модифицировать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, MrBearManul said:

Потому что у вас там есь число с плавающей точкой, и, согласно стандарту, второй целосчисленный множитель будет расширен до этого же типа. А "флоаты" сдвигать бессмысленно.

то есть, нужно приводить к int, а именно это и делается в вашем объявлении переменной? Иными словами, это нельзя оптимизировать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

а во вторых - в теории, должно ли это сократить число тактов?

Вряд ли. Макросы @define разворачиваются препроцессором (не компилятором), который работает с текстом без анализа синтаксиса. И будет примерно то же самое, что и вы предлагаете предоставлено компилятору. Оптимизировать имеет смысл именно код, т.е. то, что "схавает" компилятор. Оптимизаторы, конечно нынче очень умные. Но всё же прежде всего нужно постараться самому)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

разницы нет, но что добавилось,  я не знаю, но адреса, если вы обратите внимание, сместились, значит что-то добавилось.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

то есть, нужно приводить к int

Да.

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

а именно это и делается в вашем объявлении переменной?

Да. Но вы учтите, что я не вижу весь ваш код, работаю с отрывками, да у меня и своя работа есть))) Я могу и накосячить. Т.е. я вам излагаю основные принципы, детали вы должны сами проверить. Т.е. не принимать мой код, как истину в последней инстанции.

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

Иными словами, это нельзя оптимизировать?

Честно говоря, не знаю. Я не вижу критериев оптимизации. Возможно, если бы долго сидел и разбирался, то нашёл. Может быть их увидят другие участники форума.

 

При оптимизации программы нужно хорошо понимать работу железа, а это и процессор и периферия и эргономика и компилятор и много чего другого. Тут нельзя действовать в лоб. Если опыта недостаточно, то вы можете приготовить несколько вариантов кода, проанализировать быстродействие и выбрать подходящий, либо, почуяв, куда идти, оптимизировать дальше. Я обычно начинаю оптимизацию с количества машинных команд. Если на мой взгляд они занимают слишком много тактов (это не обязательно связано с их большим количеством), то стараюсь избавиться от вызова процедур, пытаюсь задействовать по-максимуму архитектуру. Например, ну уж совсем грубо, если нет FPU, то убираем плавающую точки и заменяем целочисленной арифметикой. Если нет целочисленного деления, то заменяем всё умножением. Если у нас на одной шине AHB висит и ПДП и процессор, то не ждём чуда быстродействия с использованием ПДП, который может заставить процессор курить в сторонке пока гонится "без процессора" 1 кб данных... Извините, что спонтанно, но примерно так и происходит. Нужны критерии оптимизации, а они могут проявиться только тогда, когда вы знаете с чем работаете. Тем не менее основная работа у вас уже всё-таки сделана) Количество тактов сократилось значительно:blum3: Поэтому экспериментируйте, это же не опасно, вы же не двигателем на поезде управляете))))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, MrBearManul said:

да у меня и своя работа есть)))

Упаси бог меня требовать от вас делать что-то для меня в ущерб своей работе.

2 minutes ago, MrBearManul said:

Я могу и накосячить. Т.е. я вам излагаю основные принципы, детали вы должны сами проверить. Т.е. не принимать мой код, как истину в последней инстанции.

Так я так и делаю, не совсем я "бум-бум" ))

2 minutes ago, MrBearManul said:

то стараюсь избавиться от вызова процедур

Наверное я содержимое того, что инлайнится, перенесу внутрь целиком, посмотрю, что выйдет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

а вот без и инлайна

Так он не инлайнит dsp3_interpolate. Он как вызывал её с помощью BL так и вызывает. Попробуйте разместить функции в заголовочном файле (для Си++ это достустипо, как в Си - не помню, тут лучше почитать что-нить от классиков). Либо, возможно, что у вашего компилятора есть директива, которая заставит компилятор заинлайнить эти функции.

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

Упаси бог меня требовать от вас делать что-то для меня в ущерб своей работе.

Простите, я ничего такого не подразумевал, просто выразился немного некорректно, т.к. торопился)

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

Так я так и делаю, не совсем я "бум-бум" ))

Ещё раз простите, если дал повод думать в том направлении))) Писал всё в спешке, постараюсь так больше не делать)))

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

если вы обратите внимание, сместились, значит что-то добавилось.

Вижу, что адреса инструкций изменились. Т.е. код "лёг" по другим адресам. Вполне возможно, не обязательно, что что-то добавилось. Возможно, что что-то переместилось с одного места на другое.

Изменено пользователем MrBearManul

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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:

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

есть у меня сравнивалка файлов. Погляжу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...