Оптимизация gcc приводит к сбою приложения
У меня действительно странная проблема с использованием GCC для ARM с включенной оптимизацией. Компиляция моего приложения C++ без оптимизации приводит к выполнению исполняемого файла, который во время выполнения выдает ожидаемые результаты. Как только я включаю оптимизацию - то есть -O1 - мое приложение не дает ожидаемых результатов. Я пытался пару дней, чтобы определить проблему, но я ничего не понимаю. Я удалил все неинициализированные переменные из своего кода, исправил места, где строгое псевдонимы могли вызвать проблемы, но все же у меня не было правильных результатов.
Я использую GCC 4.2.0 для ARM(процессор ARM926ej-s) и запускаю приложение в дистрибутиве Montavista Linux.
Ниже приведены флаги, которые я использую:
-O1 -fno-unroll-loops fno-merge-constants -fno-omit-frame-pointer -fno-toplevel-reorder \
-fno-defer-pop -fno-function-cse -Wuninitialized -Wstrict-aliasing=3 -Wstrict-overflow=3 \
-fsigned-char -march=armv5te -mtune=arm926ej-s -ffast-math
Как только я убираю флаг -O1 и перекомпилирую / перекомпоновываю приложение, я получаю правильные результаты вывода. Как вы можете видеть из флагов, я пытался отключить любую оптимизацию, я думал, что это может вызвать проблемы, но все же не повезло.
У кого-нибудь есть указания на то, как я мог бы в дальнейшем решить эту проблему?
Спасибо
4 ответа
Вообще говоря, если вы говорите: "Оптимизация ломает мою программу", ваша программа ломается на 99,9%. Включение оптимизации только раскрывает ошибки в вашем коде.
Вы также должны быть спокойны за варианты оптимизации. Только в очень определенных обстоятельствах вам понадобится что-то еще, кроме стандартных опций -O0, -O2, -O3 и, возможно, -Os. Если вам кажется, что вам нужны более конкретные настройки, обратите внимание на мантру оптимизаций:
Измеряй, оптимизируй, измеряй.
Никогда не проходите мимо "чувства кишки" здесь. Докажите, что определенная нестандартная опция оптимизации приносит значительную пользу вашему приложению, и поймите, почему (то есть точно понимаете, что делает эта опция и почему она влияет на ваш код).
Это не очень хорошее место для навигации с завязанными глазами.
Видя, как вы используете наиболее защищенный вариант (-O1), затем отключаете полдюжины оптимизаций и затем добавляете -ffast-math, я могу предположить, что вы в настоящее время делаете именно это.
Ну, возможно, одноглазый.
Но суть в следующем: если включение оптимизации нарушает ваш код, скорее всего, это ошибка вашего кода.
РЕДАКТИРОВАТЬ: Я только что нашел это в руководстве GCC:
-ffast-math
: Эта опция никогда не должна включаться никаким параметром -O, так как это может привести к неправильному выводу для программ, которые зависят от точной реализации правил / спецификаций IEEE или ISO для математических функций.
Это говорит, в основном, что ваш -O1 -ffast-math
действительно может сломать правильный код. Тем не менее, даже если отнять -ffast-math
удаляет вашу текущую проблему, вы должны хотя бы понять, почему. В противном случае вы могли бы просто заменить свою проблему сейчас на проблему в более неудобный момент позже (например, когда ваш продукт ломается на месте вашего клиента). Это действительно -ffast-math
в этом была проблема, или вы сломали математический код, который -ffast-math
?
-ffast-math
следует избегать, если это возможно. Просто используйте -O1
а пока отбросим все остальные переключатели оптимизации. Если вы все еще видите проблемы, то пришло время начать отладку.
Не видя ваш код, трудно быть более конкретным, чем "у вас, вероятно, есть ошибка".
Существует два сценария, в которых включение оптимизации меняет семантику программы:
- в компиляторе есть ошибка, или
- в вашем коде есть ошибка
Последнее, вероятно, наиболее вероятно. В частности, вы, вероятно, полагаетесь на неопределенное поведение где-то в вашей программе. Вы полагаетесь на то, что просто так происходит, когда вы компилируете с помощью этого компилятора на этом компьютере с этими флагами компилятора, но это не гарантируется языком. И поэтому, когда вы включаете оптимизацию, GCC не обязан сохранять такое поведение.
Покажите нам свой код. Или переходите через него в отладчике, пока не дойдете до точки, где все пойдет не так.
Я не могу быть более конкретным. Это может быть висячий указатель, неинициализированные переменные, нарушение правил наложения имен или даже выполнение одной из многих вещей, которые дают неопределенные результаты (например, i = i++
)
Попробуйте сделать минимальный тестовый пример. Перепишите программу, удалив вещи, которые не влияют на ошибку. Вероятно, вы сами обнаружите ошибку в процессе, но если вы этого не сделаете, у вас должна быть примерная программа на одном экране, которую вы можете опубликовать.
Кстати, если, как и предполагали другие, это -ffast-math
что вызывает ваши проблемы (т.е. компиляция с помощью просто -O1
работает отлично), тогда, скорее всего, у вас есть математика, которую вы должны переписать в любом случае. Это немного упрощение, но -ffast-math
позволяет компилятору существенно переставлять вычисления, поскольку вы можете абстрагировать математические числа - даже если это происходит на реальном оборудовании, результаты могут немного отличаться, поскольку числа с плавающей запятой не точны. Полагаться на такого рода детализацию с плавающей точкой, скорее всего, будет непреднамеренно.
Если вы хотите понять ошибку, минимальный тестовый случай является критическим в любом случае.