Отладка и производительность выпуска

132

Я наткнулся на следующий абзац:

«Настройка отладки и выпуска в среде IDE при компиляции кода в Visual Studio почти не влияет на производительность… сгенерированный код практически не отличается. Компилятор C # на самом деле не выполняет никакой оптимизации. Компилятор C # просто выдает IL… а во время выполнения всю оптимизацию выполняет JITer. JITer имеет режим отладки / выпуска, и это имеет огромное значение для производительности. Но это не влияет на то, запускаете ли вы конфигурацию Debug или Release вашего проекта, это не влияет на то, подключен ли отладчик ».

Источник здесь, а подкаст здесь .

Может ли кто-нибудь направить меня к статье Microsoft, которая действительно может это доказать?

Поиск в Google « Отладка C # против производительности выпуска » в основном возвращает результаты, в которых говорится: « Отладка сильно снижает производительность », « выпуск оптимизирован » и « не развертывать отладку в производственной среде ».

sagie
источник
возможный дубликат различий
Ханс Пассант,
С .Net4 на Win7-x86 у меня есть программа с ограниченным ЦП, которую я написал, которая работает почти в 2 раза быстрее в выпуске, чем отладка без asserts / etc в основном цикле.
Bengie
Кроме того, если вы заботитесь об использовании памяти, могут быть большие различия. Я видел случай, когда многопоточная служба Windows, скомпилированная в режиме отладки, использовала 700 МБ на поток по сравнению с 50 МБ на поток в сборке Release. Сборка отладки быстро исчерпала память при типичных условиях использования.
о. nate
@Bengie - вы проверили, что если вы подключите отладчик к сборке релиза, он все равно будет работать в 2 раза быстрее? Обратите внимание, что в приведенной выше цитате говорится, что на JIT-оптимизацию влияет то, подключен ли отладчик.
ToolmakerSteve

Ответы:

99

Частично верно. В режиме отладки компилятор выдает символы отладки для всех переменных и компилирует код как есть. В режиме выпуска включены некоторые оптимизации:

  • неиспользуемые переменные вообще не компилируются
  • некоторые переменные цикла удаляются компилятором из цикла, если доказано, что они инварианты
  • код, написанный в соответствии с директивой #debug, не включается и т. д.

Остальное зависит от JIT.

Полный список оптимизаций здесь любезно предоставлен Эриком Липпертом .

Адриан Занеску
источник
10
И не забывайте про Debug.Asserts! В сборке DEBUG, если они потерпят неудачу, они остановят поток и появится окно сообщения. В выпуске они вообще не компилируются. Это применимо ко всем методам, имеющим [ConditionalAttribute].
Иван Златанов
13
Компилятор C # не выполняет оптимизацию хвостового вызова; джиттер делает. Если вам нужен точный список того, что делает компилятор C # при включенном
Эрик Липперт
63

Нет статьи, которая что-либо «доказывает» по вопросу производительности. Способ доказать утверждение о влиянии изменения на производительность - это попробовать оба способа и протестировать в реальных, но контролируемых условиях.

Вы задаете вопрос о производительности, поэтому очевидно, что вы заботитесь о производительности. Если вам важна производительность, то правильным решением будет установить некоторые цели производительности, а затем написать себе набор тестов, который отслеживает ваш прогресс в достижении этих целей. Если у вас есть такой набор тестов, вы можете легко использовать его, чтобы проверить на себе истинность или ложность таких утверждений, как «отладочная сборка выполняется медленнее».

Более того, вы сможете получить значимые результаты. «Медленнее» не имеет смысла, потому что неясно, на одну микросекунду медленнее или на двадцать минут медленнее. «На 10% медленнее в реальных условиях» имеет большее значение.

Потратьте время, которое вы бы потратили на изучение этого вопроса в Интернете, на создание устройства, которое отвечает на этот вопрос. Так вы получите гораздо более точные результаты. Все, что вы читаете в Интернете, является лишь предположением о том, что может произойти. Основание на фактах, которые вы собрали сами, а не на предположениях других людей о том, как могла бы себя вести ваша программа.

Эрик Липперт
источник
2
Я думаю, вы можете заботиться о производительности, но при этом иметь желание использовать «отладку». Например, если большая часть вашего времени находится в ожидании зависимостей, я не думаю, что сборка в режиме отладки будет иметь большое значение, но у вас есть дополнительное преимущество в виде получения номеров строк в трассировках стека, что может помочь быстрее исправить ошибки и сделать более довольные пользователи. Дело в том, что вам нужно взвесить все «за» и «против», и для принятия решения достаточно одного оператора «работа в режиме отладки медленнее, но только если вы ограничены процессором».
Джош Муч
11

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

Конрад Рудольф
источник
Я согласен с вами в этом вопросе, но это не ответ на главный вопрос
sagie
5
@sagie: да, я знаю об этом, но я думал, что об этом все же стоит сказать.
Конрад Рудольф
6

Из соцсети msdn

Это плохо документировано, вот что я знаю. Компилятор генерирует экземпляр атрибута System.Diagnostics.DebuggableAttribute. В отладочной версии свойство IsJitOptimizerEnabled имеет значение True, в версии выпуска - False. Вы можете увидеть этот атрибут в манифесте сборки с помощью ildasm.exe

Компилятор JIT использует этот атрибут для отключения оптимизаций, которые затрудняют отладку. Те, которые перемещают код как инвариантный к циклам подъем. В некоторых случаях это может иметь большое значение для производительности. Хотя обычно не так.

Отображение точек останова на адреса выполнения - это работа отладчика. Он использует файл .pdb и информацию, сгенерированную JIT-компилятором, который предоставляет инструкцию IL для кодового сопоставления адресов. Если бы вы написали свой собственный отладчик, вы бы использовали ICorDebugCode :: GetILToNativeMapping ().

В основном развертывание отладки будет медленнее, так как оптимизация компилятора JIT отключена.

Нил
источник
3

То, что вы читаете, вполне справедливо. Выпуск обычно более скудный из-за JIT-оптимизации, не включая отладочный код (#IF DEBUG или [Conditional («DEBUG»)]), минимальной загрузки отладочных символов и часто не учитывается меньшая сборка, которая сокращает время загрузки. Различия в производительности более очевидны при запуске кода в VS из-за более обширных загружаемых PDB и символов, но если вы запускаете его независимо, различия в производительности могут быть менее очевидными. Определенный код оптимизируется лучше, чем другой, и в нем используются те же эвристические методы оптимизации, что и в других языках.

У Скотта есть хорошее объяснение по оптимизации встроенных методов здесь

См. Эту статью, в которой дается краткое объяснение того, почему в среде ASP.NET различаются параметры отладки и выпуска.

Фадриан Судаман
источник
3

Следует отметить одну вещь, касающуюся производительности и того, подключен ли отладчик или нет, что нас удивило.

У нас был фрагмент кода, включающий множество жестких циклов, отладка которого, казалось, занимала целую вечность, но работала сама по себе. Другими словами, ни у одного клиента нет проблем, но когда мы отлаживали его, казалось, что все работает как меласса.

Виновник был Debug.WriteLineв одном из узких циклов, которые выплевывали тысячи сообщений журнала, оставшихся после сеанса отладки некоторое время назад. Кажется, что когда отладчик подключен и прослушивает такой вывод, возникают накладные расходы, которые замедляют работу программы. Для этого конкретного кода время автономной работы составляло порядка 0,2-0,3 секунды, а при подключении отладчика - более 30 секунд.

Простое решение: просто удалите отладочные сообщения, которые больше не нужны.

Лассе В. Карлсен
источник
2

На сайте msdn ...

Конфигурации выпуска и отладки

Пока вы все еще работаете над своим проектом, вы обычно создаете свое приложение, используя конфигурацию отладки, поскольку эта конфигурация позволяет вам просматривать значение переменных и управлять выполнением в отладчике. Вы также можете создавать и тестировать сборки в конфигурации выпуска, чтобы убедиться, что вы не внесли никаких ошибок, которые проявляются только в одном типе сборки или в другом. В программировании .NET Framework такие ошибки очень редки, но могут возникать.

Когда вы будете готовы распространить свое приложение среди конечных пользователей, создайте сборку выпуска, которая будет намного меньше и обычно будет иметь гораздо лучшую производительность, чем соответствующая конфигурация отладки. Вы можете установить конфигурацию сборки на панели «Сборка» конструктора проектов или на панели инструментов «Сборка». Для получения дополнительной информации см. Конфигурации сборки.

Хэлли
источник
1

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

Майк Данлэйви
источник
1

Недавно я столкнулся с проблемой производительности. Полный список продуктов занимал слишком много времени, около 80 секунд. Настроил БД, улучшил запросы, разницы не было. Я решил создать TestProject и обнаружил, что тот же процесс выполняется за 4 секунды. Затем я понял, что проект находится в режиме отладки, а тестовый проект находится в режиме выпуска. Я переключил основной проект в режим выпуска, и полный список продуктов занял всего 4 секунды, чтобы отобразить все результаты.

Сводка: режим отладки намного медленнее, чем режим выполнения, поскольку в нем сохраняется отладочная информация. Вы всегда должны выполнять развертывание в режиме Relase. У вас все еще может быть отладочная информация, если вы включите файлы .PDB. Таким образом вы можете регистрировать ошибки, например, с номерами строк.

Франсиско Гольденштейн
источник
Под «режимом выполнения» вы имеете в виду «выпуск»?
Ron Klein
Да, точно. В выпуске нет всех накладных расходов на отладку.
Francisco Goldenstein
1

Режимы отладки и выпуска имеют различия. Существует инструмент Fuzzlyn : это фаззер, который использует Roslyn для генерации случайных программ C #. Он запускает эти программы на ядре .NET и гарантирует, что они дают одинаковые результаты при компиляции в режиме отладки и выпуска.

С помощью этого инструмента было обнаружено и сообщено о множестве ошибок.

Сергей Пономарев
источник