Второй запуск управляемого приложения показывает отличную производительность от первого - PullRequest
5 голосов
/ 23 января 2009

У меня есть приложение для тестирования производительности некоторых API, которые я написал. В этом тестовом приложении я в основном использую QueryPerformanceCounter и получаю время путем деления разности значений QPC после и до вызова в API по частоте. Но результаты бенчмаркинга могут отличаться, если я запускаю приложение (один и тот же исполняемый файл, работающий на одном и том же наборе Dll) с разных дисков. Кроме того, на конкретном диске запуск приложения в первый раз, закрытие приложения и его повторный запуск приводит к другим результатам тестирования. Кто-нибудь может объяснить это поведение? Я что-то здесь упускаю?

Еще немного полезной информации:

Поведение выглядит следующим образом: запустите приложение, закройте его и запустите его снова, результаты бенчмаркинга улучшатся на втором прогоне и после этого останутся такими же. Такое поведение более заметно в случае запуска с диска C. Я также хотел бы отметить, что в моем тестовом приложении есть возможность перезапустить / повторно протестировать определенный API, не закрывая приложение. Я понимаю, что это связано с джиттингом, но я не понимаю, что при первом запуске приложения, когда вы перезапускаете API несколько раз, не закрывая приложение, производительность стабилизируется после нескольких запусков, затем при закрытии и повторном запуске тот же тест, производительность, кажется, улучшается.

Кроме того, как вы учитываете изменение производительности при запуске с разных дисков?

[ОБНОВЛЕНИЕ ИНФОРМАЦИИ]

Я сделал ngen , и теперь разница в производительности между различными прогонами из одного и того же места исчезла. Т.е., если я открою приложение для тестирования производительности, запусту его один раз, закрою и перезапущу из того же места, оно показывает те же значения.

Но я столкнулся с другой проблемой сейчас. Когда я запускаю приложение с диска D и запускаю его пару раз (несколько итераций API в рамках одного и того же запуска проги тестов), а затем, начиная с 3-й итерации, производительность всех API падает примерно на 20%. , Затем, если вы закроете и снова запустите приложение и запустите его, для первых 2 итераций оно даст правильные значения (то же самое, что и значение, полученное из C), а затем производительность снова выйдет за пределы этого. Такое поведение не видно при запуске с диска C. С диска C, независимо от того, сколько прогонов вы берете, он довольно последовательный.

Я использую большие двойные массивы для проверки производительности моего API. Я беспокоился, что GC будет вставлять между тестами, поэтому я вызываю GC.Collect () & GC.WaitForPendingFinalizers () явно до и после каждого теста. Так что я не думаю, что это имеет какое-либо отношение к GC.

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

Счетчик производительности as не предлагает никаких забавных операций ввода-вывода.

Спасибо Niranjan

Ответы [ 4 ]

4 голосов
/ 23 января 2009

При запуске приложения его исполняемый и другие файлы переносятся с жесткого диска в кэш-память ОС (в ОЗУ). Если вскоре он снова запустится, многие из этих файлов, вероятно, все еще будут в кеше. Оперативная память намного быстрее дисковой.

И, конечно, один диск может быть быстрее другого.

3 голосов
/ 23 января 2009

Да. Это называется Just-In-Time compiling . По сути, ваше приложение развертывается как MSIL (промежуточный язык Microsoft), и при первом запуске оно преобразуется в собственный код.

Вы всегда можете запустить NGen (см. Вышеупомянутую статью) или иметь период разогрева в ваших сценариях тестирования производительности, где он проходит сценарий пару раз, прежде чем на самом деле сравнить производительность.

1 голос
/ 23 января 2009

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

Лучше всего выполнить несколько тестов (или несколько сотен!) И выполнить усреднение по всему набору, если вы специально не измеряете время холодной загрузки.

1 голос
/ 23 января 2009

Я думаю, что здесь есть комбинация эффектов:

Во-первых, выполнение одной и той же функции в тестовом жгуте несколько раз с одними и теми же данными каждый раз, вероятно, улучшится, потому что:

  • JIT-компиляция оптимизирует код, который запускается наиболее часто, для повышения производительности (как уже упоминалось Кори Фой)
  • Программный код будет в кеше диска (как уже упоминалось Crashwork)
  • Некоторый программный код будет в кеше ЦП, если он достаточно мал и выполняется достаточно часто

Если данные отличаются для каждого запуска функции в тестовом жгуте, это может объяснить, почему закрытие и запуск тестового жгута снова улучшает результаты: теперь данные будут также быть в кеше диска, где это было не в первый раз.

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

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