Pull to refresh

Comments 38

> То есть: просто включение поддержки исключений привело и к увеличению объёма конечного бинарного файла

Существенная деталь: в вашем трансляторе (суть которого — костыль для процессоров, разработчики которых не любят своих пользователей). В большинстве современных трансляторов используются zero-cost exceptions.

Проблема с исключениями для embedded и real-time в том, что очень сложно реализовать throw так, чтобы для вызова соответствующего catch была оценка времени сверху.
>zero-cost exceptions.
А можно показать это на псевдо-коде? Очень же интересно.

>костыль для процессоров, разработчики которых не любят своих пользователей
Я бы не стал заносить Intel и TI в эту категорию.
> А можно показать это на псевдо-коде? Очень же интересно.
На основе таблиц. Погуглите, до меня хорошо расписано в сотнях источников.

> Я бы не стал заносить Intel и TI в эту категорию.
Qualcomm для Hexagon пилят backend (open source!) для llvm. Автоматически получают все самые свежие возможности C++. Они любят своих пользователей.
>>На основе таблиц. Погуглите, до меня хорошо расписано в сотнях источников.
Гуглится, к примеру это: llvm.org/docs/ExceptionHandling.html. Но все же лучше пример псевдокода
Вот это ещё хорошо: llvm.org/demo/index.cgi
Можно скармливать куски кода и смотреть во что он их компилирует.
Прикол в том, что некоторые вещи сложно показать на псевдокоде. Вообще, это странная постановка вопроса: компилятор преобразует код С++ в байты, грубо говоря ассемблер. При этом непонятно, при чем тут С? Не каждый код может быть легко и непринужденно лечь на код С. Это иллюзия, что С++ со своими конструкциями сводится к С.

Я ожидал в статье увидеть разбор того, как генерируются исключения на современенных компляторах и платформах, когда происходит zero overhead, генерируются таблицы и по ним и колстеку происходит раскрутка. Например, компилятор msvc x64 добавляет nop операции и использует это при генерации исключений. Ничего подобного, что описано в этой статье, к данному случаю не имеет. Таким образом статья получилась как сферический конь в вакууме. Автору стоит внимательней изучить матчасть современных компиляторов.
Жаль, что статья показалась общей. Она больше относится к ситуации в своей узкой сфере.
Ну я бы не сказал, что она была общей. Она была вообще про другое: как старый преобразователь поганит код C++ при переходе к C. Ничего общего к проблеме исключений это не имеет. И взяв этот преобразователь говорить о нечто общем — это несколько странно. Тут скорее взят некий очень частный случай, не имеющий с реальной жизнью ничего общего.
«При этом непонятно, при чем тут С? Не каждый код может быть легко и непринужденно лечь на код С. Это иллюзия, что С++ со своими конструкциями сводится к С.»

Это распространенная практика — использовать Си в качестве portable-асемблера в разного рода трансляторах. В Си можно транслировать даже Scheme, со всеми приколами вроде обязательной оптимизации хвостовой рекурсии и call-cc.
Речь не про то, что можно или нельзя. Конечно можно. Вопрос в том, стоит ли на основании этой трансляции делать выводы о производительности. На мой взгляд ответ — нет. Более того, это даже неправильно, т.к. на производительность могут влиять многие достаточно тонкие эффекты и вещи.
То, как садится производительность (примерно на порядок иногда) заметно на тестах. А вот почему именно — и описывалось в статье.
Была статья по Java:
habrahabr.ru/blogs/java/133452/
в которой выявлен «порог»: если исключения выбрасываются реже 1:1000, то оверхеда по производительности нет.

Вопрос — что лучше: компенсировать оверхед исключений апгрейдом железа, или усложнить разработку неиспользованием исключений.
> если исключения выбрасываются реже 1:1000, то оверхеда по производительности нет.

При условии правильной реализации исключений в трансляторе.
Если выбор есть, то конечно лучше железо апгрейдить. Проблема в том, что не всегда этот выбор существует.
Для не embedded систем всё намного лучше. В случае, когда исключение не выбрасывается, код на исключениях оказался быстрее кода на return values (правда совсем чуть-чуть быстрее). Выбрасывание исключения, само собой, вещь жутко медленная, но мы же их выбрасываем только в исключительных случаях, правда?
Полезные данные, плохая статья. Нет ответа на самый главный вопрос — почему?! Я вообще был бы очень рад узнать, почему выходит быстрее.
Нет оверхеда на проверку возвращаемого результата.
Я правильно понимаю, что в таком случае исключение — банально longjump?
setjump/longjump (SJLJ) — это медленный способ реализации исключений.

В zero-cost способе в случае исключения у нас будет поиск нужного обработчика по таблицам и это может быть не быстро. Но для установки обработчика не нужно производить сложных действий. Поэтому если исключения нет — то мы за обработчики не платим.
UFO landed and left these words here
Возвращаем коды успеха.
UFO landed and left these words here
Хотелось бы понять, как переход от C++ к C связан с быстродействием генерируемого кода с использованием современных компиляторов? Большинство компиляторов просто заменяют виртуальный вызов на невиртуальный, т.к. инстанс известен во время компиляции.
Интересно, какие это компиляторы так делают. Я бы не хотел, чтобы вызов был невиртуальным, т.к. весь смысл виртуальных функций пропадает. И если тип переменной struct AAAAA*, то это не значит, что надо вызывать AAAAA::process(). Переменная может указывать на struct BBBBB*.
Возьмем, например, кусок кода:

BBBBB b1;
b1.process();

В момент вызова метода process компилятор однозначно понимает, какую функцию нужно позвать. Почему бы не использовать это знание? Более того, компилятор msvc так и делает. Я тут не вижу проблем.
Это все отлично в теории, но меня всегда радовали люди, которые о производительности рассуждают на уровне «ну вот здесь будет замедление». Во сколько раз? В каких ситуациях? В каком соотношении нормальное исполнение — брошенное исключение?

Я не говорю, что Вы неправы. Просто то, что написано в статье должно идти последней главой под названием «Разберемся, почему так» в большом 5-ти главном исследовании.

Поймите, что производительность — это чистая наука. Сделал — померил, еще сделал — еще померил, сравнил, выбрал.
Автор же написал — речь идёт о встраиваемых системах. Т.е. всякого рода контроллеров. Там узкие места нужно заранее в уме держать, чтобы через месяц разработки не оказалось, что система просто не успевает. И измерить производительность там тоже нетривиальное дело. Работа идёт больше частью с железом и система получается недетерминированной. Измерять, как привило, приходится косвенными методами.
Речь идёт не о встраиваемой с системе, а о костыльном трансляторе и этим всё сказано.
Речь идёт именно встраиваемых системах. Для десктопа это всё вообще слабо-акутально и сплошная переоптимизация. И нужно быть специфичным человеком, чтобы применять на десктопе подобные инструменты.
А для встраиваемых систем вполне нормально. Архитектор много и писать полноценный набор компиляторов долго и сложно. Часто производители пишут/заказывают компилятор C и к нему вот такие костыли.
Как-то погрустнело от кода с исключениями. И это код, не делающий ничего полезного. Если бы я писал под МК на С++, то мой проект, переделанный на С с исключениями, занял бы 2 MБайта и влезал бы наверное в притирку.
P.S. Напишите исходный размер, а то непонятно во сколько раз увеличение происходит.
Only those users with full accounts are able to leave comments. Log in, please.