LINUX.ORG.RU

Финты ушами или бесполезных оптимизаций тред

 , ,


0

2

Приветствую всех! Попросите вашу маму налить вам немного борща и зацените мою кулстори. Мы как-то обсуждали с monk полезность eval в common lisp. Для меня, так вещь не особо нужная и мало используемая (как и некоторые другие конструкции языка, впрочем). А он мне привел пример генерации кода на лету для некоторого подмножества входных данных, где этот код проще, чем для полного набора.

И я подумал, а почему бы не сделать так же? Вот тут на C есть кусок кода (из libFLAC), в котором разворачивается следующий цикл:

http://pastebin.com/T8H7wGuw

     /* Here's a slower but clearer version:
        for(i = 0; i < data_len; i++) {
                sum = 0;
                for(j = 0; j < order; j++)
                        sum += qlp_coeff[j] * data[i-j-1];
                residual[i] = data[i] - (sum >> lp_quantization);
        }
        */

для всех допустимых значений order - это [1; 32]. Причем самые часто используемые значения [1;12], входящие в так называемое подмножество FLAC расставлены там так, чтобы к самым вероятным значениям order шло как можно меньше ветвлений.

Сначала я сделал на CL то же самое, заменив разве что блоки вида

sum += qlp_coeff[j] * data[i-j-1];
...
sum += qlp_coeff[0] * data[i-1];
макрой.

А потом подумал, может можно сделать это элегантней? И решил для каждого значения order сделать отдельную функцию, поместить их в заготовленную хеш-таблицу, а потом вызывать их оттуда. А для тех значений order, которые не встречаются в подможестве, генерировать функцию «на лету» и добавлять в таблицу.

В итоге получилось такая любопытная штука:

http://pastebin.com/vh9vEdKE

По длине в 4 раза короче сишной.

Но тут я посчитал скорость выполнения этого дела и прямо таки не почувствовал никакой разницы. Причем пересобрал libLFAC с утилитами без разворачивания цикла и тоже не увидел разницы. Ну и ладно, зато в профайлере можно смотреть статистику про порядкам, подумал я и оставил такой выкрутасный вариант.

А как вы считаете, нужен ли eval? Можете ли вы сделать раскрутку цикла в runtime на вашем любимом ЯП? Дискач.

а вот интересно, что будет быстрее на x86, и насколько? Оптимизированная версия, или эта ваша slower?

emulek
()

Без eval не вытащить и рыбки из пруда.

REPL через что работает? Не через eval ли, случаем?

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

просто нагенерить все 32 версии сразу?

Так не спортивно же! И лишние 10 килобайт!

не юзать таблицу

Это как? А как доступ к ним осуществлять? Генерировать имя символа что ли?

vonenij
() автор топика

И чо вы ко мне прицепились?

Я вообще жду каких-нибудь c++-фанбоев, которые сделают что-то подобное на шаблонах

vonenij
() автор топика
Ответ на: комментарий от vonenij

Именно на 32 бита? Интересно. Хотя биты вряд ли что-то тут дадут. Смотря какой конвейер, наверно

нет, не именно 32. Я просто не уверен, что такое разворачивание даст профит. Раздутый код не влезет в конвейер и в кеш. И потому, не факт, что будет работать быстрее. К тому же в простом цикле проще предсказать переходы.

Короче — пробовать надо и самый простой вариант, не факт, что он медленнее.

emulek
()
Ответ на: комментарий от emulek

Я хочу посмотреть, можно ли это сделать.

Я надеюсь, что с их стороны будут реплики: «Мы написали 100 километров шаблонов, но ничего не смогли сделать». Они отчаются и умрут.

vonenij
() автор топика
Ответ на: комментарий от emulek

Короче — пробовать надо и самый простой вариант, не факт, что он медленнее.

А так, собственно, и вышло, я ж написал. Причем, что в коде на cl, что в коде на C.

Раздутый код не влезет в конвейер и в кеш.

Конвейеру главное, чтобы предсказалось верно, то есть не было его опустошения. Касательно кэша вышло так, что для подмножества FLAC длина цикла в байтах <= 269 (disassemble показал). Это влезет туда?

vonenij
() автор топика
Ответ на: комментарий от emulek

Я тут нагенерировал развернутых версий во время компиляции. И на больших порядках есть профит!

24 секунды против 27 (libFLAC дает 5.5 секунд)

А на маленьких профита нет.

Дело в том, что eval не учитывает декларации и генерирует длинный код. Интересно, можно ли что-то с этим поделать?

vonenij
() автор топика
Ответ на: комментарий от seg-fault

Это не при чём. Вставил декларации в функцию и всё стало как надо. Профит от разворота наблюдается, но маленький.

vonenij
() автор топика

за очевидной ненужностью lisp IRL его eval ненужен тем более.

MKuznetsov ★★★★★
()
Ответ на: комментарий от buddhist

Forth

Вот это надо обязательно как-нибудь

vonenij
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.