Информация об изменениях

Сообщение Re[8]: Пример использования шаблонов для оптимизации от 24.02.2015 14:03

Изменено 24.02.2015 14:04 chaotic-good

EP>Встраивать код из другого translation unit это ещё сложнее, так как требует link-time code generation. Выше был пример фейла оптимизации на constexpr-функции, а если она будет ещё и в другом translation unit — то сфейлится и подавно.

Ну это все сейчас умеют, даже студия

EP>Чем же код в headers сложнее? Чем усложняется процесс разработки?

EP>Я наоборот предпочёл бы использовать header-only библиотеку, так это многое упрощает — и так будет до тех пор, пока не появятся модули

Ключевое слово "библиотеку" Если смотреть на это как application developer a не как library developer, то получается грусно. Вносить изменения в хедеры дороже, так как цикл разработки (edit -> compile -> run tests -> fix errors) замедляется. Изменил одну строчку и ждешь пока пересобирутся десять единиц трансляции, завязанных на этот хедер. У нас в конторе это крайне не приветствуется и в code style есть соотв. раздел про код в хедерах.

EP>Чем по твоей классификации отличаются простые алгоритмы от сложных? И почему по-твоему простые на шаблонах получается проще, а сложные — нет?

EP>Ты всё же попробуй переведи пример partition_point на динамический полиморфизм, хотя бы схематично.

Я немного во времени ограничен. Уверен что будет хуже чем с шаблонами, придется нагородить класс итератор с виртуальными ф-ями и использвать его. Получится полная хрень a-la java, но скорее всего работать будет не хуже.

EP>А в этом коде вообще шаблон не нужен был. С vector<int> получается даже потенциально быстрее, например если передаётся rvalue.

EP>Не понимаю о каком лишнем копировании идёт речь — тут всегда создаётся временная копия.

Ну стандарт не гарантирует использование copy elision тут, так что может быть и лишняя копия, по крайней мере те люди, которые пишут такой код, либо не знают про copy elision, либо не очень на это надеются.

EP>В этом месте было неправильное использование шаблонов, которое не приносило никакой пользы, и даже вредило.

EP>Если бы здесь была хоть какая-то польза от шаблонов, то был бы смысл обсуждать tradeoffs — а так, просто пример "так делать не надо", и такие примеры можно найти для любой технологии.

Угу. Вот только это оч. распространенная практика. Очень часто шаблоны появляются в коде там где они не нужны и половина таких случаев это begin end итераторы вместо конкретного типа либо параметр функтор — template<class Fn> void apply(Fn const& f); — который можно заменить std::function или чем-нибудь полиморфным.

EP>А если много разных аргументов? Причём которые вычисляются как промежуточные значения какого-то алгоритма? Будешь за каждым в матлаб бегать? Генерировать скриптом?


Можно в рантайме сгенерировать перед стартом, если это очень долго, то можно сгенирировать на этапе компиляции скриптом и вставить в исходинк, можно фалйик сделать и в ресурсы запихать, много вариантов есть. Считать факториалы шаблонами IMO самый кривой из вышеперечисленных вариантов.

EP>Эти рассуждения теоретически верны, но на практике справедливы только для крайне малого класса случаев. Что уже успешно демонстрировалось примером выше. Тебе нужны ещё примеры?

EP>Да, у компилятора+ликновщика (причём не только у C++) есть вся необходимая информация для крутых оптимизаций — но из этого никак не следует что в компиляторе все эти оптимизации реализованы. Из этого также не следует что подобные оптимизации будут выполнятся за какое-то вменяемое время.
EP>Или, например, у компилятора есть необходимая информация для того чтобы автоматически переделать алгоритм на GPGPU, но он зараза этого не делает.
EP>В общем из наличия возможности, никак не следует то что эта возможность была реализована

Ну это передергивание уже с GPGPU. По факту, современные версии clang и gcc очень агрессивно оптимизируют код. Я однажды запарился и написал множество небольших программ тестирующих возможности компиляторов и я реально видел что gcc активно делает девиртуализацию, например, и если заменить функтор параметризованый типом на что-нибудь полиморфное, gcc это дело девиртуализирует очень запросто, даже в другой единице трансляции. Помимо этого я периодически пишу тесты производительности, поэтому если компилятор начнет испытывать затруднения с каким-либо кодом, я в своем проекте об этом узнаю и смогу ему помочь. В общем, я не вижу проблемы с таким подходом.

EP>Разворачивать циклы вручную через рекурсивные шаблоны смысл есть, так как компиляторы далеко не всегда додумываются развернуть цикл с фиксированным числом итераций. Даже недавно подобная тема поднималась
Автор: nen777w
Дата: 19.02.15
.

EP>Шаблонный loop unroll используется во многих библиотеках, как раз потому что компиляторы не всегда способны его сделать

Я там в той теме отписывался, честно попытался воспроизвести кейс с помощью клэнга 3.6 но ничего не получилось, он генерит здоровую ф-ю, которая проверяет нет ли алиасинга и потом если его нет — использует быстрый векторизованый цикл иначе — более сложную и медленную реализацию. В месте вызова оно вообще инлайнилось и векторизировалось. Я не смог заставить clang сгенирировать плохой код с включенными оптимизациями (-O2)
Re[8]: Пример использования шаблонов для оптимизации
EP>Встраивать код из другого translation unit это ещё сложнее, так как требует link-time code generation. Выше был пример фейла оптимизации на constexpr-функции, а если она будет ещё и в другом translation unit — то сфейлится и подавно.

Ну это все сейчас умеют, даже студия

EP>Чем же код в headers сложнее? Чем усложняется процесс разработки?

EP>Я наоборот предпочёл бы использовать header-only библиотеку, так это многое упрощает — и так будет до тех пор, пока не появятся модули

Ключевое слово "библиотеку" Если смотреть на это как application developer a не как library developer, то получается грусно. Вносить изменения в хедеры дороже, так как цикл разработки (edit -> compile -> run tests -> fix errors) замедляется. Изменил одну строчку и ждешь пока пересобирутся десять единиц трансляции, завязанных на этот хедер. У нас в конторе это крайне не приветствуется и в code style есть соотв. раздел про код в хедерах.

EP>Чем по твоей классификации отличаются простые алгоритмы от сложных? И почему по-твоему простые на шаблонах получается проще, а сложные — нет?

EP>Ты всё же попробуй переведи пример partition_point на динамический полиморфизм, хотя бы схематично.

Я немного во времени ограничен. Уверен что будет хуже чем с шаблонами, придется нагородить класс итератор с виртуальными ф-ями и использвать его. Получится полная хрень a-la java, но скорее всего работать будет не хуже. Если хочешь в code golf поиграть, могу потом как-нибудь наваять.

EP>А в этом коде вообще шаблон не нужен был. С vector<int> получается даже потенциально быстрее, например если передаётся rvalue.

EP>Не понимаю о каком лишнем копировании идёт речь — тут всегда создаётся временная копия.

Ну стандарт не гарантирует использование copy elision тут, так что может быть и лишняя копия, по крайней мере те люди, которые пишут такой код, либо не знают про copy elision, либо не очень на это надеются.

EP>В этом месте было неправильное использование шаблонов, которое не приносило никакой пользы, и даже вредило.

EP>Если бы здесь была хоть какая-то польза от шаблонов, то был бы смысл обсуждать tradeoffs — а так, просто пример "так делать не надо", и такие примеры можно найти для любой технологии.

Угу. Вот только это оч. распространенная практика. Очень часто шаблоны появляются в коде там где они не нужны и половина таких случаев это begin end итераторы вместо конкретного типа либо параметр функтор — template<class Fn> void apply(Fn const& f); — который можно заменить std::function или чем-нибудь полиморфным.

EP>А если много разных аргументов? Причём которые вычисляются как промежуточные значения какого-то алгоритма? Будешь за каждым в матлаб бегать? Генерировать скриптом?


Можно в рантайме сгенерировать перед стартом, если это очень долго, то можно сгенирировать на этапе компиляции скриптом и вставить в исходинк, можно фалйик сделать и в ресурсы запихать, много вариантов есть. Считать факториалы шаблонами IMO самый кривой из вышеперечисленных вариантов.

EP>Эти рассуждения теоретически верны, но на практике справедливы только для крайне малого класса случаев. Что уже успешно демонстрировалось примером выше. Тебе нужны ещё примеры?

EP>Да, у компилятора+ликновщика (причём не только у C++) есть вся необходимая информация для крутых оптимизаций — но из этого никак не следует что в компиляторе все эти оптимизации реализованы. Из этого также не следует что подобные оптимизации будут выполнятся за какое-то вменяемое время.
EP>Или, например, у компилятора есть необходимая информация для того чтобы автоматически переделать алгоритм на GPGPU, но он зараза этого не делает.
EP>В общем из наличия возможности, никак не следует то что эта возможность была реализована

Ну это передергивание уже с GPGPU. По факту, современные версии clang и gcc очень агрессивно оптимизируют код. Я однажды запарился и написал множество небольших программ тестирующих возможности компиляторов и я реально видел что gcc активно делает девиртуализацию, например, и если заменить функтор параметризованый типом на что-нибудь полиморфное, gcc это дело девиртуализирует очень запросто, даже в другой единице трансляции. Помимо этого я периодически пишу тесты производительности, поэтому если компилятор начнет испытывать затруднения с каким-либо кодом, я в своем проекте об этом узнаю и смогу ему помочь. В общем, я не вижу проблемы с таким подходом.

EP>Разворачивать циклы вручную через рекурсивные шаблоны смысл есть, так как компиляторы далеко не всегда додумываются развернуть цикл с фиксированным числом итераций. Даже недавно подобная тема поднималась
Автор: nen777w
Дата: 19.02.15
.

EP>Шаблонный loop unroll используется во многих библиотеках, как раз потому что компиляторы не всегда способны его сделать

Я там в той теме отписывался, честно попытался воспроизвести кейс с помощью клэнга 3.6 но ничего не получилось, он генерит здоровую ф-ю, которая проверяет нет ли алиасинга и потом если его нет — использует быстрый векторизованый цикл иначе — более сложную и медленную реализацию. В месте вызова оно вообще инлайнилось и векторизировалось. Я не смог заставить clang сгенирировать плохой код с включенными оптимизациями (-O2)