Программа запускается медленнее при запуске за пределами Visual Studio
Я замечаю какое-то странное поведение в отношении моей программы. Я пишу его на С++ с помощью Visual Studio Professional 2013 Update 1 и состоит из приложения exe, которое ссылается на несколько DLL и вызывает функции, определенные в этих DLL.
В моей основной программе (состоящей из нескольких тысяч строк кода) я вызываю DLL-функцию (пусть ее называют DLLFunction()
), и я вычисляю время, затраченное на этот вызов, например:
auto beginTime = std::chrono::high_resolution_clock::now();
DllFunction();
auto endTime = std::chrono::high_resolution_clock::now();
long long totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
Что я замечаю, так это то, что для запуска за пределами Visual Studio требуется гораздо больше времени. Например:
Запуск в отладки в Visual Studio с прикрепленным отладчиком → ~50 ms
Запуск в release в Visual Studio с прикрепленным отладчиком --- > ~25 ms
Запуск в release в Visual Studio без отладочного приложения --- > ~20 ms
Запуск вне Visual Studio (выпуск) --- > ~80 ms
Как вы можете видеть, запуск его в выпуске за пределами Visual Studio на самом деле занимает больше времени, чем запуск сборки отладки с прикрепленным отладчиком!
Оскорбительная DLL встроена в одно и то же решение одним и тем же компилятором, и я дважды проверил, что все DLL файлы в каталоге, откуда я запускаю приложение, являются правильными.
Что может быть причиной такого поведения?
РЕДАКТИРОВАТЬ 5:
Основное приложение запускает другое консольное приложение и связывается с ним с использованием именованных каналов. Оказалось, что нерест этого другого приложения вызывает быстрый вызов DLL за пределами Visual Studio.
Однако одно и то же приложение создается как внутри, так и снаружи Visual Studio, поэтому я не понимаю, почему он замедляет другие вызовы, которые находятся за пределами Visual Studio.
РЕДАКТИРОВАТЬ 4:
Оказалось, что это медленное поведение появляется только в том случае, если я помещаю вызов функции в какую-то часть кода моей основной программы, поэтому это должна быть проблема, связанная с этим. Это много строк, но я продолжу исследования.
Спасибо за предложения в любом случае, они были полезны для идентификации проблемы.
РЕДАКТИРОВАТЬ 3:
Измерения с помощью QueryPerfomanceCounter:
Циклы процессора, измеренные внутри Visual Studio (~ 50k), составляют половину от внешних (~ 110k) (кстати, возвращаются QueryPerfomanceCounter() фактические циклы CPU).
Разделение по частоте показывает аналогичные результаты для std:: chrono.
EDIT 2:
Я проверил с помощью проводника процессов, как было предложено, DLL, загруженные в VS и вне VS, идентичны.
РЕДАКТИРОВАТЬ 1: по запросу я пробовал это:
auto beginTime = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000; ++i)
{
DllFunction();
}
auto endTime = std::chrono::high_resolution_clock::now();
long long totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
И результаты:
Запуск его в выпуске в Visual Studio с прикрепленным отладчиком --- > ~19 seconds
Запуск вне Visual Studio (выпуск) --- > ~40 seconds
Ответы
Ответ 1
DLL не загружается в программу, пока вы не вызовете ее в первый раз. Если эта функция очень мала, программа может тратить большую часть времени, просто загружая DLL.
Попытайтесь изменить это:
DllFunction();
auto beginTime = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000; ++i)
{
DllFunction();
}
auto endTime = std::chrono::high_resolution_clock::now();
long long totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
Таким образом, время загрузки не учитывается.
Ответ 2
Код нарушения не загружается до тех пор, пока вы не запустите его в первый раз, после чего он извлечет DLL и загрузит его в память. Поскольку вы работали в Visual Studio, он, скорее всего, будет загружать все, как только вы запустите отладчик, отрицая это накладные расходы первого вызова. Это предотвращает необходимость использования кода дополнительным пространством для загруженной DLL, пока он не будет абсолютно уверен, что он нужен, и может экономить пространство и время, если некоторые ссылки никогда не вызываются.
При тестировании времени доступа, такого как это, вы должны ВСЕГДА ставить такие тесты через цикл и запускать их много раз, так как такие условия сильно влияют на первый вызов, но не на последующие вызовы и другие условия системы (например, ресурсы, требуемые другим процессом) могут вызвать колебания, которые вы хотите сгладить для хорошего теста. Никогда не доверяйте времени при выполнении одного экземпляра.
Ответ 3
Я также попытался бы удалить оптимизацию кода. Может быть, некоторые встроенные функции поведения дают больше производительности в отладчике VS.
Попробуйте оптимизировать, щелкните правой кнопкой мыши по вашему проекту → Свойства → Свойства конфигурации → C/С++ → Оптимизация → Оптимизация = Отключено.