Visual Studio - влияние условных и отключенных точек останова во время выполнения
Потратив немного времени на размышления о том, почему мое приложение запускает определенный сценарий очень медленно с подключенным отладчиком, я обнаружил, что это связано с наличием условной точки останова (условие которой никогда не выполнялось). Это кажется разумным, поскольку ЦП будет сигнализировать точку останова, а VS должен будет оценить условие, прежде чем продолжить выполнение. Эти переходы должны быть дорогостоящими.
Я предполагаю, что точка останова в пути кода, которая не выполняется, не влияет на время выполнения.
Итак, мой вопрос состоит из двух частей:
- Существуют ли какие-либо ресурсы, которые могут дать количественную оценку стоимости, связанной с условными контрольными точками, и если да, то можно ли что-то сделать, чтобы уменьшить их стоимость оценки времени выполнения?
- Есть ли какие-либо затраты, связанные с "отключенной" точкой останова? Под отключенным я имею в виду, что VS отображает маркер точки останова в желобе с полым кружком.
Конечно, если что-то, что я упомянул выше, не имеет смысла, пожалуйста, укажите мне правильное направление.
5 ответов
Трудно определить стоимость условной точки останова. Выражение в условной точке останова оценивается с использованием точно такой же семантики, как если бы вы ввели его в часы или в непосредственное окно. Выражения такого рода на самом деле не выполняются в клиентской программе, а обрабатываются оценщиком выражений для конкретного языка. На самом деле не представляется возможным профилировать эти типы оценок значимым образом.
Однако я могу перечислить несколько вещей, которые, как известно, медленнее в eval окна отладки
- Вызовы функций: это самая медленная вещь, которую вы можете сделать, потому что вызов функции требует перезапуска процесса отладки, чтобы в процессе могла произойти функция.
- Сравнение строк: под капотом они возвращаются к функциональным целям
Что касается отключенных точек останова, то они не влияют на работу приложения.
Одна вещь, на которую следует обратить внимание (я усвоил сложный путь), это убедиться, что вы ставите == при сравнении переменной со значением, а не с единственным =
Редактор точек останова не предупреждает вас, но когда точка останова вычисляется, переменная изменяется! Мне потребовалось время, чтобы отладить мой код с этим!
Кроме того, если я действительно нуждаюсь в условной точке останова, чтобы обмануть код; Я добавляю условие в код, затем добавляю что-то вроде string stop = "here"; и поставить нормальную точку останова - я считаю, что код работает быстрее.
Попробуйте установить точку останова в своем коде, чтобы проверить производительность. НАПРИМЕР
Stopwatch st = new Stopwatch(); st.Start(); if(my condition) { st.Stop(); Debugger.Break(); }
Нет, не совсем то же самое, но достаточно близко.
Нет - отключенная точка останова отсутствует в исполняемой программе. Это просто хранится в метаданных VS для вашего удобства.
Я где-то читал, что есть аппаратная поддержка для этих точек останова, так что использование менее чем x условных точек останова определенного вида, по сути, бесплатно, но, кроме того, ему нужно больше программного обеспечения. (OTOH, это было для нативных приложений, не уверенный в этих новомодных вещах JIT.)
Отключенные точки останова должны влиять на вещи вообще, они просто копируют некоторую память и ресурсы GUI в IDE.
Я также заметил, что условные контрольные точки дороги и пришли к тому же выводу, что и вы. Я не могу представить себе причину, по которой отключенная точка останова вызовет какое-либо замедление, поскольку я ожидаю, что это будет только редактор, ярлык для включения точки останова, если она вам понадобится.
Когда я нахожусь в такой ситуации, я делаю макрос assert. (Вы можете использовать макрос assert, который предоставляет Visual Studio, но мне это не нравится). Пусть ваш макрос проверит нужное вам состояние, а затем вызовет DebugBreak в случае сбоя. При выпуске или не проверенной сборке вашего приложения не нужно ничего оценивать, так что на ваш код это никак не повлияет.
Простой макрос assert может выглядеть так:
#ifdef _DEBUG
#define assert(x)\
do{\
if(!(x)){DebugBreak();}\
}while(0)
#else
#define assert(x)
#endif
и назовите это как:
assert(pValue != NULL && "A bad parameter was passed to the function");
Вы можете добавить больше кода к ошибке перед DebugBreak (например, распечатать условие, которое не удалось с помощью #x, и / или номер строки / файла с помощью ____FILE____ и ____LINE____, чтобы вы могли дважды щелкнуть сообщение). Вы можете записывать сообщения в журнал отладки с помощью OutputDebugString и даже проверять, подключен ли отладчик с IsDebuggerPresent, чтобы еще больше адаптировать ваше утверждение. Мне также нравится использовать формат строки &&, чтобы дать немного больше информации о конкретном утверждении.
Есть несколько вещей, которые нужно соблюдать при использовании assert. Во-первых, не помещайте код, который ДОЛЖЕН выполняться в макросе, так как он будет удален в не отладочной сборке. По тем же причинам не вставляйте код, имеющий побочные эффекты. Кроме того, вы не хотите вызывать DebugBreak(), когда отладчик не подключен, поскольку он, по сути, генерирует исключение, которое, если его не перехватить, завершит работу приложения.