Как измерить производительность кода в .NET? - PullRequest
44 голосов
/ 19 января 2009

Я делаю очень быстрый и грязный бенчмаркинг для одной строки кода C #, используя DateTime:

long lStart = DateTime.Now.Ticks;
// do something
long lFinish = DateTime.Now.Ticks;

Проблема в результатах:

Start Time [633679466564559902]
Finish Time [633679466564559902]

Start Time [633679466564569917]
Finish Time [633679466564569917]

Start Time [633679466564579932]
Finish Time [633679466564579932]

... и т. Д.

Учитывая, что время старта и финиша идентично, тики явно недостаточно гранулированы.

Итак, как мне лучше измерить производительность?

Ответы [ 19 ]

62 голосов
/ 19 января 2009

Класс Stopwatch, доступный с .NET 2.0, - лучший способ для этого. Это очень высокопроизводительный счетчик с точностью до долей миллисекунды. Взгляните на документацию MSDN , которая довольно ясна.

РЕДАКТИРОВАТЬ: Как было предложено ранее, также рекомендуется запускать код несколько раз, чтобы получить разумное среднее время.

11 голосов
/ 19 января 2009

Выполните ваш код повторно. Кажется, проблема в том, что ваш код выполняется намного быстрее, чем детализация вашего измерительного прибора. Самое простое решение этого - выполнить ваш код много, много раз (тысячи, может быть, миллионы), а затем вычислить среднее время выполнения.

Редактировать: Кроме того, из-за природы текущих оптимизирующих компиляторов (и виртуальных машин, таких как CLR и JVM), может быть очень обманчиво измерять скорость выполнения отдельных строк кода, так как измерение может влиять на скорость достаточно много. Гораздо лучший подход - профилировать всю систему (или, по крайней мере, более крупные блоки) и проверить, где находятся узкие места.

8 голосов
/ 27 февраля 2009

Я считаю это полезным

http://accelero.codeplex.com/SourceControl/changeset/view/22633#290971 http://accelero.codeplex.com/SourceControl/changeset/view/22633#290973 http://accelero.codeplex.com/SourceControl/changeset/view/22633#290972

TickTimer - это урезанная копия секундомера, которая запускается после создания и не поддерживает перезапуск. Он также уведомит вас, если текущее оборудование не поддерживает синхронизацию с высоким разрешением (секундомер устраняет эту проблему)

Итак, это

var tickTimer = new TickTimer();
//call a method that takes some time
DoStuff();
tickTimer.Stop();
Debug.WriteLine("Elapsed HighResElapsedTicks " + tickTimer.HighResElapsedTicks);
Debug.WriteLine("Elapsed DateTimeElapsedTicks " + tickTimer.DateTimeElapsedTicks);
Debug.WriteLine("Elapsed ElapsedMilliseconds " + tickTimer.ElapsedMilliseconds);
Debug.WriteLine("Start Time " + new DateTime(tickTimer.DateTimeUtcStartTicks).ToLocalTime().ToLongTimeString());

выведет это

Elapsed HighResElapsedTicks 10022886
Elapsed DateTimeElapsedTicks 41896
Elapsed ElapsedMilliseconds 4.18966178849554
Start Time 11:44:58

DebugTimer - это оболочка для TickTimer, которая запишет результат в Debug. (примечание: он поддерживает шаблон Disposable)

Итак, это

using (new DebugTimer("DoStuff"))
{
    //call a method that takes some time
    DoStuff();
}

выведет это в окно отладки

DoStuff: Total 3.6299 ms

IterationDebugTimer предназначен для определения времени, необходимого для многократного запуска операции и записи результата в Debug. Он также выполнит начальный запуск, который не включен, чтобы игнорировать время запуска. (примечание: он поддерживает шаблон одноразового использования)

Итак, это

int x;
using (var iterationDebugTimer = new IterationDebugTimer("Add", 100000))
{
    iterationDebugTimer.Run(() =>
    {
        x = 1+4;
    });
}

Будет выводить это

Add: Iterations 100000 
Total 1.198540 ms 
Single 0.000012 ms
8 голосов
/ 20 января 2009

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

Убедитесь, что вы вызвали свой метод перед измерением. В противном случае вы также измерите время, необходимое для JIT-компиляции кода. Это может существенно исказить ваши цифры.

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

И убедитесь, что вы измеряете то, что действительно хотите измерить. Когда начинается оптимизация, компилятор / JIT-компилятор может переставить код или полностью удалить его, так что вы можете в итоге измерить что-то немного другое, чем предполагалось. По крайней мере, взгляните на сгенерированный код, чтобы убедиться, что код не был удален.

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

На самом деле, лучший совет - измерять реальные системы с реальными данными, поскольку тесты в песочнице могут оказаться очень неточными.

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

Используйте настоящий профилировщик, такой как dotTrace.

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

Вы можете использовать Stopwatch, при условии, что вы используете .NET 2.0 или новее.

System.Diagnostics.Stopwatch.StartNew();

Класс Stopwatch также имеет общедоступное поле только для чтения IsHighResolution, которое позволит вам узнать, основан ли секундомер на счетчике высокого разрешения. Если это не так, он основан на системном таймере.

Я не уверен, что нужно, чтобы секундомер был основан на счетчике производительности с высоким разрешением. Есть некоторые вызовы API, но я полагаю, что если секундомер не использует высокое разрешение, то API, вероятно, там нет.

4 голосов
/ 08 августа 2014

Образец для Stopwatch класса

    using System.Diagnostics;
    ......
    ...
    ..
    Stopwatch sw = new Stopwatch();
    sw.Start();
    //Your Code Here

    sw.Stop();
    Console.WriteLine("Elapsed={0}",sw.Elapsed);
3 голосов
/ 15 декабря 2015

https://andreyakinshin.gitbooks.io/performancebookdotnet/content/science/microbenchmarking.html

https://github.com/PerfDotNet/BenchmarkDotNet

"Действительно, микробенкрининг очень сложен. Если операция занимает 10–100 нс, измерение операции является большой проблемой. Я предлагаю вам использовать BenchmarkDotNet для своих тестов. Это библиотека, которая поможет вам сделать честный тест Получайте измерения с хорошей точностью. Конечно, вы можете написать собственный тест без каких-либо дополнительных библиотек. В этом разделе мы поговорим о том, почему это, вероятно, плохая идея и что вы должны знать перед началом. "

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

См. Ответ на Является ли DateTime.Now лучшим способом измерения производительности функции? для объяснения или прочитайте мой пост в блоге о высокопроизводительных измерениях

Проблема в том, что DateTime имеет разрешение около 15 мс, оно не может быть более точным, чем это. Секундомер, однако, может.

...