Что на самом деле делает опция "Оптимизировать код" в Visual Studio?
Название опции говорит о чем-то, но что на самом деле делает Visual Studio / компилятор и каковы реальные последствия?
Изменить: Если вы ищете Google, вы можете найти этот адрес, но это не совсем то, что я ищу. Интересно, что происходит на самом деле. Например, почему циклы получают меньше времени и т. Д.
3 ответа
Без оптимизации компилятор создает очень тупой код - каждая команда компилируется очень простым способом, так что она выполняет предназначенную задачу. По умолчанию в сборках Debug оптимизации отключены, поскольку без оптимизаций созданный исполняемый файл напрямую соответствует исходному коду.
Переменные хранятся в регистрах
Как только вы включите оптимизацию, компилятор применяет множество различных методов, чтобы заставить код работать быстрее, в то же время делая то же самое. Наиболее очевидное различие между оптимизированными и неоптимизированными сборками в Visual C++ состоит в том, что значения переменных хранятся в регистрах как можно дольше в оптимизированных сборках, в то время как без оптимизации они всегда сохраняются в памяти. Это влияет не только на скорость кода, но и на отладку. В результате этой оптимизации отладчик не может надежно получить значение переменной, когда вы шагаете по коду.
Другие оптимизации
Есть несколько других оптимизаций, применяемых компилятором, как описано в документах MSDN "Параметры / O (Оптимизировать код)". Для общего описания различных методов оптимизации см. http://en.wikipedia.org/wiki/Compiler_optimization.
Из блога Пола Вика:
Он удаляет все инструкции NOP, которые мы в противном случае могли бы использовать для отладки. Когда оптимизация выключена (и включена информация об отладке), компилятор будет выдавать инструкции NOP для строк, с которыми не связан фактический IL, но для которых вы, возможно, захотите установить точку останова. Наиболее распространенным примером чего-то подобного является "End If" в выражении "If" - фактическое значение IL не выдается для End If, поэтому мы не испускаем NOP, отладчик не позволит установить точку останова в теме. Включение оптимизации заставляет компилятор не генерировать NOP.
Мы делаем простой базовый анализ блоков сгенерированного IL, чтобы удалить любые блоки мертвого кода. То есть мы разбиваем каждый метод на блоки IL, разделенные инструкциями ветвления. Сделав быстрый анализ того, как блоки взаимосвязаны, мы можем определить любые блоки, в которых нет ответвлений. Таким образом, мы можем выяснить блоки кода, которые никогда не будут выполнены и могут быть опущены, делая сборку немного меньше. Мы также делаем небольшую оптимизацию ветвления на этом этапе - например, если вы переходите к другому оператору GoTo, мы просто оптимизируем первый GoTo, чтобы перейти к цели второго GoTo.
Мы генерируем атрибут DebuggableAttribute с IsJITOptimizerDisabled, установленным в False. По сути, это позволяет JIT во время выполнения оптимизировать код так, как он считает нужным, включая переупорядочение и встраивание кода. Это даст более эффективный и меньший код, но это означает, что попытка отладки кода может быть очень сложной (как скажет любой, кто попробовал ее). Фактический список того, что такое JIT-оптимизация, - это то, чего я не знаю - может быть, кто-то, как Крис Брамм, в какой-то момент включится в это. Суть в том, что переключатель оптимизации обеспечивает оптимизацию, которая может усложнить установку точек останова и пошаговое выполнение кода.
Короткий ответ: используйте -Ox и позвольте компилятору делать свою работу.
Длинный ответ: эффект различного рода оптимизаций невозможно предсказать точно. Иногда оптимизация для быстрого кода на самом деле дает меньший код, чем при оптимизации по размеру. Если вы действительно хотите получить последние 0,01% производительности (по скорости или по размеру), вы должны сравнить различные комбинации параметров.
Кроме того, в последних версиях Visual Studio есть опции для более продвинутых оптимизаций, таких как оптимизация во время соединения и оптимизация на основе профилей.