Re[8]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 17:55
Оценка:
Здравствуйте, so5team, Вы писали:

S>Если у вас скорости такие, что вы укладываетесь в дедлайны даже в Debug режиме, то ваша трогательная забота о накладных расходах выглядит весьма странно.


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

S>Если вас устраивает 50K req/s, то заботиться о методах, которые позволяют достичь 150K req/s уже не нужно. В принципе.


Да, если софт пишется только под конкретное железо (или вообще железо заказывается специально под софт). Но это, вообще-то, не норма.
Re[7]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 06:38
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>так еще и одним взглядом определяете во что современные шаблонные кружева транслируются?


ЕМ>"Современные шаблонные кружева" как-то влияют на алгоритмы кодогенерации, и есть примеры, когда для шаблонного класса создается более эффективный код, чем для эквивалентного нешаблонного?


Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода: https://godbolt.org/z/dTf781
Шаблон tagged_scalar там сделан для того, чтобы при вызове конструктора limiter нельзя было перепутать аргументы, которые имеют один и тот же тип. Такой вот незамысловатый трюк для того, чтобы уменьшить количество ошибок в коде (ну нельзя же все на откуп assert-ам отдавать, ей Богу).

Желающие могут сравнить объем ассемблерного выхлопа при уровнях оптимизации -O0, -O1 и -O2.

Возможно, опыт Евгения Музыченко и netch80 на несколько порядков круче моего и они понимают в программировании сильно больше меня. Поэтому они видят какой-то глубокий смысл в том, чтобы оценивать скорость неоптимизированного C++ного кода. Но глядя на разницу между -O2 и другими уровнями оптимизации я лично этого смысла уловить не могу.
Re[8]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 07:29
Оценка:
Здравствуйте, so5team, Вы писали:

N>>но зачем вы целиком этому подчиняетесь? Что мешает включить голову и самому управлять, что нужно?

S>Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.

При необходимости и это делается. Хотя, да, лучше обойтись внешними средствами.
Но даже в той же STL есть vector::operator[], а есть vector::at.

N>>Те же ассерты — какая-то часть из них должна остаться и в релизе.

S>Ассерты в релизе? Это либо какая-то лютая хрень, либо не ассерты, а часть логики кода (например, часть defensive programming) которая отвечает за проверку контрактов и/или инвариантов. Но эта часть не является зависящими от NDEBUG ассертами.

Ну а кто вам сказал, что все ассерты обязаны зависеть от NDEBUG?
В одной задаче у меня было 4 уровня включения этих ассертов.

N>>Какая-то должна начать писать логи и трейсы вместо полного вышибания.

S>Опять же, это часть логики, от Debug/Release не зависит.

Это всё то же: та часть кода, которая выполняет не целевую логику, а защитную. Стандартный assert() это точно так же часть defensive programming, как и любые самопальные аналоги.

Кстати, не подскажете, в чьей STL и почему есть именно те assertʼы, которые зависят от NDEBUG? MSVC не предлагать.

N>>Есть сравнение по этому поводу, которому уже надцать лет, но я забыл автора: подобные методы это всё равно что сначала вести автомобиль со скоростью пешехода, а затем гонять на всех газах, не пристёгиваясь. Вы вот ровно такого горе-водителя и описываете.

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

Вам Евгений уже несколько раз сказал: есть то, что зовётся good enough — код успевает (например, надо скормить следующую порцию звука за 10 мс — он кормит). Но есть и возможность лучшего результата, и если она достигается за 2 мс без особого напряга — это ещё лучше.
Граница будет проходить там, где мы вступаем в зону недопустимых оптимизаций.
С тем, сколько в C/C++ разных undefined behavior, для меня нормально увидеть код, собранный вроде бы в релизе с -O1 (gcc) — когда большинство потенциально вредоносных оптимизаций ещё не включены: "зачем платить больше?"
Или вот я одному файлу при -O2 всё равно выставил -fno-strict-aliasing — там разборка структур по байтам, и не хочу, чтобы кто-то лажанулся и, сам того не заметив, дал сложные эффекты там, где их потом фиг поймаешь.

S>Если у вас есть примеры того, где важна максимальная скорость кода, собранного в Debug режиме, то с интересом послушаю.


Если вы перестанете думать только про Debug и Release, то можно обсудить. Но пока у вас только чёрное и белое — я воздержусь.

N>>В качестве простейшего примера: отладчики могут поддерживать скрипты точек останова, которые будут писать, если нужно, детали обстановки, или модифицировать её по условию, и тут же запускать код дальше.

S>Если ТС апеллирует к реал-тайму, то даже такие продвинутые отладчики в условиях реал-тайма идут лесом. Ну или у реал-тайма там время отклика секундное.

Миллисекундного достаточно. Это таки >90% обычного реалтайма в Windows/Linux/etc.
The God is real, unless declared integer.
Re[8]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 07:46
Оценка:
Здравствуйте, so5team, Вы писали:

S>Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода: https://godbolt.org/z/dTf781

S>Шаблон tagged_scalar там сделан для того, чтобы при вызове конструктора limiter нельзя было перепутать аргументы, которые имеют один и тот же тип. Такой вот незамысловатый трюк для того, чтобы уменьшить количество ошибок в коде (ну нельзя же все на откуп assert-ам отдавать, ей Богу).
S>Желающие могут сравнить объем ассемблерного выхлопа при уровнях оптимизации -O0, -O1 и -O2.

Спасибо, кэп.
Надеюсь, вы понимаете (или поймёте когда-нибудь), что это всё не имеет значения, например, в коде, который разбирает аргументы командной строки чего-то работающего заметное время: он может быть ещё хуже скомпилирован, да хоть встроенный Javascript вызывать — всё равно это доли секунды, и на общий результат не повлияет.

С другой стороны, никому вроде в голову не придёт писать для Debug на голых циклах там, где для Release применяют AVX интринсики — даже с учётом того, насколько на них сложнее писать, а потом понимать написанное.

S>Возможно, опыт Евгения Музыченко и netch80 на несколько порядков круче моего и они понимают в программировании сильно больше меня.


Я не знаю, можно ли мой опыт оценивать "круче", это очень неконкретное понятие. Но я подозреваю, что 1) он заметно разнообразнее, 2) я кроме голого стажа ещё и делаю выводы из пройденного.
У меня бывали разные случаи. Грамотно написанная с нуля программа на питоне побивала в разы вроде бы хорошо оптимизированную на C++, потому что в последнем авторы увлеклись своими абстракциями по передаче данных между тем, что сейчас бы назвали акторами. Да, это было где-то в 2002 и после этого они очень быстро исправились (но поезд ушёл и наша соответствующая компонента так и сидит на питоне, хотя сейчас это уже точно гири на ногах). С другой стороны, для одной вычислительной задачи оказалось недостаточно игр с флагами оптимизации, и мы ещё несколько процентов выиграли на выборе компилятора для каждого файла (между gcc, icc и open64). И в обоих игра в бирюльки типа Debug/Release ничем не помогла, только сбивала бы с толку.

S> Поэтому они видят какой-то глубокий смысл в том, чтобы оценивать скорость неоптимизированного C++ного кода. Но глядя на разницу между -O2 и другими уровнями оптимизации я лично этого смысла уловить не могу.


Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код. Дальше пойдёт легче.
The God is real, unless declared integer.
Re[9]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 07.11.20 07:49
Оценка: +1
Здравствуйте, netch80, Вы писали:

S>>Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.


N>При необходимости и это делается. Хотя, да, лучше обойтись внешними средствами.

N>Но даже в той же STL есть vector::operator[], а есть vector::at.

Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release.

N>>>Те же ассерты — какая-то часть из них должна остаться и в релизе.

S>>Ассерты в релизе? Это либо какая-то лютая хрень, либо не ассерты, а часть логики кода (например, часть defensive programming) которая отвечает за проверку контрактов и/или инвариантов. Но эта часть не является зависящими от NDEBUG ассертами.

N>Ну а кто вам сказал, что все ассерты обязаны зависеть от NDEBUG?

N>В одной задаче у меня было 4 уровня включения этих ассертов.

Тогда вы assert-ами называете свой велосипед, а не штатный assert.

N>>>Какая-то должна начать писать логи и трейсы вместо полного вышибания.

S>>Опять же, это часть логики, от Debug/Release не зависит.

N>Это всё то же: та часть кода, которая выполняет не целевую логику, а защитную. Стандартный assert() это точно так же часть defensive programming, как и любые самопальные аналоги.


У меня совершенно другое представление о defensive programming. Я привык думать, что defensive programming -- это набор техник и приемов, которые обеспечивают защиту от работы с некорректными значениями, нарушенными контрактами и инвариантами. Причем защита эта не зависит от того, компилируемся ли мы в Debug или в Release, эта защита присутствует в итоговом коде приложения.

Приемы же, которые используются на этапе отладки и которые изымаются из итогового кода -- это отладочные средства. К коим и относится штатный assert.

Если для вас defensive programming -- это что-то другое, то OK. Значит мы спорим не договорившись об определениях.

N>Кстати, не подскажете, в чьей STL и почему есть именно те assertʼы, которые зависят от NDEBUG? MSVC не предлагать.


Не подскажу.

N>Вам Евгений уже несколько раз сказал: есть то, что зовётся good enough — код успевает (например, надо скормить следующую порцию звука за 10 мс — он кормит). Но есть и возможность лучшего результата, и если она достигается за 2 мс без особого напряга — это ещё лучше.

N>Граница будет проходить там, где мы вступаем в зону недопустимых оптимизаций.

Евгений, видимо, существует в очень комфортных условиях. Скажем, у него время отклика 10ms и его код (причем, скорее всего, только его, без каких-либо внешних зависимостей) даже в Debug сборке успевает в это время уложиться.

Повторюсь: этому можно только позавидовать. Вопрос в том, что он будет делать, если у него оптимизированный код будет с трудом в 10ms укладываться. Он все еще продолжит рассуждать о важности скорости в Debug варианте?

S>>Если у вас есть примеры того, где важна максимальная скорость кода, собранного в Debug режиме, то с интересом послушаю.


N>Если вы перестанете думать только про Debug и Release, то можно обсудить. Но пока у вас только чёрное и белое — я воздержусь.


Не я завел разговор о Debug сборках. А, так уж получается, что Debug и Release -- это вполне себе устоявшиеся понятия. Вплоть до того, что на том же MSVC в Debug и Release вы вынуждены линковаться к разным версиям runtime-библиотек.

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

Так-то и я могу рассказать, что временами собираю код с -O2 и -g для целей профилирования.
Re[9]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 08:10
Оценка: +1
Здравствуйте, netch80, Вы писали:

N>Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код. Дальше пойдёт легче.


а зачем?
если существующий подход нормально работает и используемые средства разработки под него заточены.
что именно мы получаем от придуманных нами каких-то дополнительных уровней отладки/сборки?
Re[9]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 08:19
Оценка:
Здравствуйте, netch80, Вы писали:

N>Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код.


Да без проблем. Пусть у нас есть приложение из модулей A, B и C. Каждый из них компилируется с разными уровнями оптимизации (и вообще с разными ключами компилятора, а может и даже разными компиляторами).

Если нас интересует производительность модуля C, то при наличии столь существенной разницы между -O0 и -O2 какой смысл оценивать скорость модуля C при -O0?

Может кто-то живет в условиях, когда -O2 запрещен на законадательном уровне?

N>Дальше пойдёт легче.


Сомнительно.
Re[10]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 08:19
Оценка:
Здравствуйте, so5team, Вы писали:

S>>>Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.

N>>При необходимости и это делается. Хотя, да, лучше обойтись внешними средствами.
N>>Но даже в той же STL есть vector::operator[], а есть vector::at.
S>Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release.

И в надцатый раз — это вам так кажется, пока для вас эти два слова это нечто в настройках сборки, правилами которой вы не управляете.
Сделайте свой враппер, который выбирает между ними — и получите управляемый выбор.

N>>Ну а кто вам сказал, что все ассерты обязаны зависеть от NDEBUG?

N>>В одной задаче у меня было 4 уровня включения этих ассертов.
S>Тогда вы assert-ами называете свой велосипед, а не штатный assert.

Я называю этим весь комплект защитных средств системы "если условие не выполнилось, тут не продолжаем", и это правильнее.

N>>Это всё то же: та часть кода, которая выполняет не целевую логику, а защитную. Стандартный assert() это точно так же часть defensive programming, как и любые самопальные аналоги.

S>У меня совершенно другое представление о defensive programming. Я привык думать, что defensive programming -- это набор техник и приемов, которые обеспечивают защиту от работы с некорректными значениями, нарушенными контрактами и инвариантами. Причем защита эта не зависит от того, компилируемся ли мы в Debug или в Release, эта защита присутствует в итоговом коде приложения.

S>Приемы же, которые используются на этапе отладки и которые изымаются из итогового кода -- это отладочные средства. К коим и относится штатный assert.


S>Если для вас defensive programming -- это что-то другое, то OK. Значит мы спорим не договорившись об определениях.


Да, другое, и я это уже пару раз подчёркивал в предыдущих сообщениях — например, в том, как вы гоняете не пристегнувшись.

N>>Вам Евгений уже несколько раз сказал: есть то, что зовётся good enough — код успевает (например, надо скормить следующую порцию звука за 10 мс — он кормит). Но есть и возможность лучшего результата, и если она достигается за 2 мс без особого напряга — это ещё лучше.

N>>Граница будет проходить там, где мы вступаем в зону недопустимых оптимизаций.
S>Евгений, видимо, существует в очень комфортных условиях. Скажем, у него время отклика 10ms и его код (причем, скорее всего, только его, без каких-либо внешних зависимостей) даже в Debug сборке успевает в это время уложиться.

Пусть сам расскажет. Я пример про 10 мс дал только навскидку. Может, у него 10 мкс. Может, ему меньше чем аналог -Og не подходит.

S>Повторюсь: этому можно только позавидовать. Вопрос в том, что он будет делать, если у него оптимизированный код будет с трудом в 10ms укладываться. Он все еще продолжит рассуждать о важности скорости в Debug варианте?


Вполне возможно. Можно испытать корректность в условиях, где пойдёт 20 или 50 мс, и потом ужесточить до реальных.

S>Но, я так понимаю, что волнительных историй на счет скорости именно в Debug не будет.


Вы ждёте "волнительных историй" вместо обсуждения по сути... Ну ждите, ждите.
The God is real, unless declared integer.
Re[11]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 07.11.20 08:35
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Но даже в той же STL есть vector::operator[], а есть vector::at.

S>>Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release.

N>И в надцатый раз — это вам так кажется, пока для вас эти два слова это нечто в настройках сборки, правилами которой вы не управляете.

N>Сделайте свой враппер, который выбирает между ними — и получите управляемый выбор.

Простите, но либо вы выбрали крайне неудачный пример, либо говорите какую-то ерунду.

Различия в семантике operator[] и at для std::vector определены на уровне стандарта. Так, at гарантированно выполняет проверки индекса и бросает исключения (вне зависимости от режима сборки), тогда как operator[] эти проверки не делает. И последствия передачи в at/operator[] невалидного индекса принципиально разные. Соответственно, и сфера применения у них разные. Так, at применяется для обеспечения защиты в коде, а operator[] для получения максимальной производительности ценой небезопасности.

То, что operator[] в разных видах сборки может выдавать какую-то диагностику -- это лишь приятный бонус. Не более того. Тем более, что этого бонуса запросто может и не быть.

S>>Тогда вы assert-ами называете свой велосипед, а не штатный assert.


N>Я называю этим весь комплект защитных средств системы "если условие не выполнилось, тут не продолжаем", и это правильнее.


Ну а я называю assert-ами именно штатные assert-ы, коие в избытке встречаются в коде тех или иных сторонних библиотек.

S>>Если для вас defensive programming -- это что-то другое, то OK. Значит мы спорим не договорившись об определениях.


N>Да, другое, и я это уже пару раз подчёркивал в предыдущих сообщениях — например, в том, как вы гоняете не пристегнувшись.


Аналогии -- это скользкий путь и он еще быстрее ведет к недопониманиям. Тем не менее, если уж показывать примеры на аналогиях, то в моем представлении defensive programming -- это когда вы вынуждены использовать ремень безопасности всегда, и во время учебы, и во время гонок, и во время обычных поездок. А вот применение того, что вы считаете assert-ами -- это избирательное использование ремней безопасности. Мол, при обучении (в Debug) ремни пристегиваем, а на гонке (в Release) -- нет.

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

N>Вы ждёте "волнительных историй" вместо обсуждения по сути... Ну ждите, ждите.


Да уже понятно, что их не будет. Всем можно расслабиться.
Re[10]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 08:47
Оценка:
Здравствуйте, night beast, Вы писали:

N>>Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код. Дальше пойдёт легче.


NB>а зачем?

NB>если существующий подход нормально работает и используемые средства разработки под него заточены.

В том и дело, что не работает он "нормально". Или, если для вас "нормально" это случай этого героя интернета, то да, нормально — но очень быстро выходишь за пределы таких ограничений.

NB>что именно мы получаем от придуманных нами каких-то дополнительных уровней отладки/сборки?


У вас некая очень толстая программа со своей историей, которую ведёт достаточно разнообразная команда. Вам надо её улучшить — например, есть конкретное место, где вам надо ускорить (неважно что — отрисовку на экране, расчёт зарплаты, парсинг сетевого запроса, etc.)
Вы определили те модули/функции/методы, где происходит критичное по скорости выполнение.
Вам надо в этих модулях:
1. Вылизать код относительно всех плюх.
2. Установить для него максимум оптимизации. При этом, так как оптимизации начинают вызывать предположения компилятора, которые не соответствуют предположениям программиста (вспоминаем весь комплект ужастиков про undefined behavior с переполнениями, алиасингом и т.п.) — это будет смесь визуальной верификации и запусков санитайзеров, пока не будет достигнуто выполнение, которое адекватно по скорости и не вызывает жалобы на проблемы кода.
3. Установить на всех границах этого кода контроль значений (который в идеале никогда не должен выключаться).
После этого быть всё равно готовым к тому, что что-то пойдёт не так и надо иметь базовую информацию хотя бы на уровне стейтрейсов и тех переменных, которые не убиты оптимизацией.

Остальной код, выполняющий тонны разнообразных сервисных функций, типа: передачу сообщений, чтение/запись файлов, общение с базой данных, общение с сетью и т.п. — занимает копейки относительно общих затрат времени, и пишется менее квалифицированными людьми.

В терминах gcc это значит, что критичные функции могут быть скомпилированы с -O2 или -O3, а для остальных достаточно -Og (чтобы совсем уж жуткие случаи типа гоняния одного значения по 5 регистрам или, как у so5team@, несвёрнутые шаблоны — были устранены) или даже -O0 (для половины кода). Причём ни в условном Release вам не нужна оптимизация всех 99% некритичного кода, ни в Debug вам нельзя понижать уровень оптимизации критичного кода ниже -O или даже -O2 — он просто не сможет выполнять свои функции.

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

В результате получается, что да, у вас может быть несколько режимов сборки. Может, хоть 100 (ну или предположим 128): в зависимости от того, подробности какого из критичных модулей вам важнее для конкретного испытания. И ни один из них не должен становиться каноническим Debug (-O0 -g), ни каноническим Release (-O2 или -O3, к которому кроме отсутствия -g добавлен ещё и strip на итоговые бинарники).
Даже если какой-то из этих уровней, для простоты и общности, будет иметь название Debug или Release, его суть будет заметно другой.
The God is real, unless declared integer.
Отредактировано 07.11.2020 8:54 netch80 . Предыдущая версия .
Re[12]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 08:59
Оценка:
Здравствуйте, so5team, Вы писали:

S>Различия в семантике operator[] и at для std::vector определены на уровне стандарта. Так, at гарантированно выполняет проверки индекса и бросает исключения (вне зависимости от режима сборки), тогда как operator[] эти проверки не делает. И последствия передачи в at/operator[] невалидного индекса принципиально разные. Соответственно, и сфера применения у них разные. Так, at применяется для обеспечения защиты в коде, а operator[] для получения максимальной производительности ценой небезопасности.

S>То, что operator[] в разных видах сборки может выдавать какую-то диагностику -- это лишь приятный бонус. Не более того. Тем более, что этого бонуса запросто может и не быть.

Вы угадали все буквы и не угадали слово.
Да, определены, именно так, как описано. Поэтому я могу выбирать между ними сам, и делать это каким-то универсальным управляемым методом.

N>>Да, другое, и я это уже пару раз подчёркивал в предыдущих сообщениях — например, в том, как вы гоняете не пристегнувшись.


S>Аналогии -- это скользкий путь и он еще быстрее ведет к недопониманиям. Тем не менее, если уж показывать примеры на аналогиях, то в моем представлении defensive programming -- это когда вы вынуждены использовать ремень безопасности всегда, и во время учебы, и во время гонок, и во время обычных поездок. А вот применение того, что вы считаете assert-ами -- это избирательное использование ремней безопасности. Мол, при обучении (в Debug) ремни пристегиваем, а на гонке (в Release) -- нет.


Ну а для кого я говорил, что используем такие, которые не выключаются при (условном) релизе?

N>>Вы ждёте "волнительных историй" вместо обсуждения по сути... Ну ждите, ждите.

S>Да уже понятно, что их не будет.

Ну я тут таки по делу, а не по литературе. Хотя вы можете что-нибудь сами рассказать.
The God is real, unless declared integer.
Re[8]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 09:03
Оценка:
Здравствуйте, so5team, Вы писали:

ЕМ>>"Современные шаблонные кружева" как-то влияют на алгоритмы кодогенерации, и есть примеры, когда для шаблонного класса создается более эффективный код, чем для эквивалентного нешаблонного?


S>Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода:


Вы лучше попытайтесь ответить на заданный вопрос о влиянии "шаблонных кружев" на эффективность генерируемого кода.
Re[11]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 09:04
Оценка:
Здравствуйте, netch80, Вы писали:

NB>>а зачем?

NB>>если существующий подход нормально работает и используемые средства разработки под него заточены.

N>В том и дело, что не работает он "нормально".


нормально, это значит устраивает большинство.
иначе бы использовалась другая модель.

NB>>что именно мы получаем от придуманных нами каких-то дополнительных уровней отладки/сборки?


N>У вас некая очень толстая программа со своей историей, которую ведёт достаточно разнообразная команда. Вам надо её улучшить — например, есть конкретное место, где вам надо ускорить (неважно что — отрисовку на экране, расчёт зарплаты, парсинг сетевого запроса, etc.)

N>Вы определили те модули/функции/методы, где происходит критичное по скорости выполнение.

и начинаете оптимизировать именно эти методы/функции, переписывая их на асме, играясь с ключами компиляции и прочее.
без сомнения, ситуации, требующие индивидуального подхода, встречаются.
но мы вроде говорим об общем случае, тех самых 99% "написанных на питоне"

или я что-то не понял?
Re[12]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 09:19
Оценка:
Здравствуйте, night beast, Вы писали:

NB>>>а зачем?

NB>>>если существующий подход нормально работает и используемые средства разработки под него заточены.
N>>В том и дело, что не работает он "нормально".
NB>нормально, это значит устраивает большинство.
NB>иначе бы использовалась другая модель.

Это не "устраивает большинство". Это 1) инерция от древних времён (70-80-е, когда эта концепция только была придумана), 2) инерция мышления тех, кто просто не представляет себе иначе и не хочет думать о других вариантах.

В IT тысячи примеров такой инерции, этот далеко не единственный. Каждый из них постепенно устраняется, но на это могут уйти десятилетия. Но размыв идёт постепенно и со стороны. Уже несколько уровней оптимизации в компиляторе — вполне источник альтернативных подходов.
В GCC, например, с 5-й версии есть прагмы задания уровня оптимизации раздельно по каждой функции. Это ещё дальше шаг в данную сторону. Ещё лет 20 и они пройдут в стандарт языка.

NB>и начинаете оптимизировать именно эти методы/функции, переписывая их на асме, играясь с ключами компиляции и прочее.

NB>без сомнения, ситуации, требующие индивидуального подхода, встречаются.
NB>но мы вроде говорим об общем случае, тех самых 99% "написанных на питоне"
NB>или я что-то не понял?

Уже топикстартер явно говорил не о стандартном случае, у него были весьма специфические хотелки. Так что, увы, не поняли.
The God is real, unless declared integer.
Re[9]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 09:26
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода:


ЕМ>Вы лучше попытайтесь ответить на заданный вопрос о влиянии "шаблонных кружев" на эффективность генерируемого кода.


Пройдите таки по ссылке и сравните эффективность кружев с -O0 и -O2.
Re[13]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 09:27
Оценка:
Здравствуйте, netch80, Вы писали:

NB>>нормально, это значит устраивает большинство.

NB>>иначе бы использовалась другая модель.

N>Это не "устраивает большинство". Это 1) инерция от древних времён (70-80-е, когда эта концепция только была придумана), 2) инерция мышления тех, кто просто не представляет себе иначе и не хочет думать о других вариантах.


возможно, но на текущий момент ситуация именно такая

N>В IT тысячи примеров такой инерции, этот далеко не единственный. Каждый из них постепенно устраняется, но на это могут уйти десятилетия. Но размыв идёт постепенно и со стороны. Уже несколько уровней оптимизации в компиляторе — вполне источник альтернативных подходов.


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

NB>>но мы вроде говорим об общем случае, тех самых 99% "написанных на питоне"

NB>>или я что-то не понял?

N>Уже топикстартер явно говорил не о стандартном случае, у него были весьма специфические хотелки. Так что, увы, не поняли.


что хочет ТС я вообще не понял.
но потом вроде обсуждение съехало в сторону
Re[13]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 07.11.20 09:34
Оценка:
Здравствуйте, netch80, Вы писали:

N>Да, определены, именно так, как описано. Поэтому я могу выбирать между ними сам, и делать это каким-то универсальным управляемым методом.


Послушайте, ведь очевидно, что вы говорите про некий уникальный для вашего проекта define, который в зависимости от определения будет приводить либо к использованию operator[], либо к at. И что вы, в зависимости от каких-то факторов, определяете этот define при сборке либо так, либо иначе.

Давайте перестанем играть в эту игру и перейдем к сути.

Суть в том, что operator[] дает скорость ценой безопасности, а at обеспечивает безопасность ценой скорости. И если кому-то нужна скорость, то он выбирает именно operator[]. Причем вне зависимости от Debug/Release. А потому, что ему в итоговом коде нужна именно скорость.

Аналогично и с at.

Так что возвращаемся к тому, о чем говорилось: "Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release."

И мне не понятно, что вы этому пытаетесь возразить. Как и непонятно зачем.

N>Ну а для кого я говорил, что используем такие, которые не выключаются при (условном) релизе?


Повторюсь: если что-то не выключается при релизе, то это не assert-ы. Ну вот определение у assert-а такое. Что уж тут поделать.

N>Ну я тут таки по делу, а не по литературе. Хотя вы можете что-нибудь сами рассказать.


Так в том-то и дело, что мне не вспомнаются примеры того, чтобы скорость работы кода в Debug-е имела значение.
Тогда как у вас, можно предположить, подобные примеры имеются:

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

Вот мне было бы интересно (без сарказма) узнать про примеры того, как и почему в Debug-е скорость кода важна, да еще и критически важна.
Re[10]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 09:39
Оценка:
Здравствуйте, so5team, Вы писали:

S>Евгений, видимо, существует в очень комфортных условиях. Скажем, у него время отклика 10ms и его код (причем, скорее всего, только его, без каких-либо внешних зависимостей) даже в Debug сборке успевает в это время уложиться.


Евгений существует в сильно различных условиях. Когда есть возможность, он предпочитает отлаживать свои ядерные драйверы в виртуалках, чтобы не подключать отдельный отладочный ноутбук, обмен которого с отладчиком, даже по гигабитному сетевому шнурку, гораздо медленнее, чем у виртуалки через VirtualKD. Если код в отладочных сборках будет вообще без оптимизаций, то тормоза в самых внутренних циклах, вместе с тормозами VMM и его эмулятора HD Audio, не позволят поддерживать стабильный звуковой поток с периодом меньше 10 мс. А так оно вполне себе работает и на периодах 3-5 мс, а в особо удачных вариантах — и 1 мс. Это, напомню, в виртуалках. А непосредственно на железе, даже 15-летней давности, мне вообще по барабану, отладочная сборка или релизная — обе с большим запасом укладываются в 500 мкс, а уменьшить период уже не позволяет разрешение системного таймера.

S>что он будет делать, если у него оптимизированный код будет с трудом в 10ms укладываться.


Будет оптимизировать алгоритм, вестимо.

S>Он все еще продолжит рассуждать о важности скорости в Debug варианте?


Он в первую очередь рассуждает об относительных накладных расходах, затрачиваемых на организацию удобств. Когда они разумны (от единиц процентов на мелкие удобства, до 10-20 на серьезные), это оправдано. Многократное копирование содержимого объекта при возвратах из функций — это сотни-тысячи процентов накладных расходов. В масштабе всего приложения это, конечно, мелочи, но здесь ярко проявляется способность C++ к малозаметному созданию совершенно неадекватных тормозов. А активное и невнимательное использование шаблонов в традиционном для C++ стиле "ну ужасно, ну криво, но работает же!" это и провоцирует, и маскирует.

Если отладочная сборка тормозит (хотя бы по отдельным фрагментам кода) по сравнению с релизной разумно (в 2-3 раза), то оснований для беспокойства нет. Если же она вдруг начинает тормозить в десятки-сотни раз — это безусловно повод для беспокойства.

S>на том же MSVC в Debug и Release вы вынуждены линковаться к разным версиям runtime-библиотек.


Почему вдруг "вынуждены"? Можете линковаться к любой на выбор.
Re[12]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 09:47
Оценка:
Здравствуйте, night beast, Вы писали:

NB>нормально, это значит устраивает большинство.


Если в смысле "пипл хавает", то да.

NB>и начинаете оптимизировать именно эти методы/функции, переписывая их на асме, играясь с ключами компиляции и прочее.


Правильнее все-таки сперва пытаться оптимизировать алгоритм, затем играться с режимами компиляции, и лишь после этого — переписывать на асме.
Re[13]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 09:53
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

NB>>нормально, это значит устраивает большинство.


ЕМ>Если в смысле "пипл хавает", то да.


ну тебя же не напрягает использование большинством библиотеки std?
ведь можно для конкретных кейсов и лучше написать.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.