Является ли DateTime.Now лучшим способом измерения производительности функции?

Мне нужно найти узкое место и нужно точно измерить время.

Является ли следующий фрагмент кода наилучшим способом измерения производительности?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

Ответ 1

Нет, нет. Используйте StopwatchSystem.Diagnostics)

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

Секундомер автоматически проверяет наличие высокоточных таймеров.

Стоит отметить, что DateTime.Now часто довольно медленнее, чем DateTime.UtcNow из-за работы, которая должна выполняться с помощью часовых поясов, DST и т.д.

DateTime.UtcNow обычно имеет разрешение 15 мкс. См. сообщение в блоге Джона Чапмана о точности DateTime.Now для большого резюме.

Интересные мелочи: секундомер возвращается на DateTime.UtcNow, если ваше оборудование не поддерживает высокочастотный счетчик. Вы можете проверить, использует ли секундомер аппаратное обеспечение для достижения высокой точности, посмотрев на статическое поле Stopwatch.IsHighResolution.

Ответ 2

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

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

В качестве альтернативы, если вам нужно что-то более сложное, вам, вероятно, следует рассмотреть возможность использования стороннего профилировщика, например ANTS.

Ответ 3

В этой статье говорится, что в первую очередь вам нужно сравнить три альтернативы: Stopwatch, DateTime.Now AND DateTime.UtcNow.

Это также показывает, что в некоторых случаях (когда счетчик производительности не существует), секундомер использует DateTime.UtcNow + некоторую дополнительную обработку. Из-за этого очевидно, что в этом случае DateTime.UtcNow является лучшим вариантом (потому что другие используют его + некоторые обработки)

Однако, как оказалось, счетчик почти всегда существует - см. Пояснение о счетчике производительности высокого разрешения и его существовании, связанном с.NET Stopwatch? ,

Вот график производительности. Обратите внимание на то, как низкая стоимость использования UtcNow сравнима с альтернативами:

Enter image description here

Ось X - это размер данных выборки, а ось Y - относительное время примера.

Одна Stopwatch лучше, чем Stopwatch заключается в том, что он обеспечивает более высокие измерения времени. Другим является его более характерный характер. Однако создание OO-оболочки вокруг UtcNow не может быть трудным.

Ответ 4

Полезно подтолкнуть ваш бенчмаркинг к полезному классу/методу. Класс StopWatch не должен быть Disposed или Stopped при ошибке. Таким образом, простейший код времени для некоторого действия

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

Пример кода вызова

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat("Did action in {0} ms.", time);
}

Вот версия расширения

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }
}

И пример кода вызова

public void Execute(Action action)
{
    var time = action.Benchmark()
    log.DebugFormat("Did action in {0} ms.", time);
}

Ответ 5

Функция DotTrace и ANTS - это те, которые я использовал больше всего... бесплатная пробная версия для DotTrace полностью функциональна и не нарывается, как некоторые из других).

Ответ 6

Используйте класс System.Diagnostics.Stopwatch.

Stopwatch sw = new Stopwatch();
sw.Start();

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

Ответ 7

Donto Секундомер, это лучше.

Что касается измерения производительности, вы должны также проверить, является ли ваш "//Некоторый процесс выполнения" очень коротким процессом.

Также имейте в виду, что первый запуск вашего "//Some Execution Process" может быть медленнее последующих прогонов.

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

Ответ 8

Все это отличные способы измерения времени, но это лишь очень косвенный способ найти узкие места.

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

Здесь более полное объяснение того, как и почему оно работает

Ответ 9

@Шон Чамберс

FYI, класс .NET Timer не предназначен для диагностики, он генерирует события в заданный интервал, как это (из MSDN):

System.Timers.Timer aTimer;
public static void Main()
{
    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();
}

// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}

Так что это действительно не поможет вам понять, как долго что-то заняло, просто прошло определенное количество времени.

Таймер также отображается как элемент управления в System.Windows.Forms... вы можете найти его в своем окне инструментов разработчика в VS05/VS08

Ответ 10

В Visual Studio Team System есть некоторые функции, которые могут помочь с этой проблемой. По сути, вы можете писать модульные тесты и смешивать их в разных сценариях, чтобы работать против вашего программного обеспечения как часть теста на нагрузку или нагрузку. Это может помочь определить области кода, которые наиболее сильно влияют на производительность ваших приложений.

Группа Microsoft "Модели и практики" имеет некоторые рекомендации в Руководство по тестированию производительности Team Team Team Visual Studio.

Ответ 11

Это правильный способ:

using System;
using System.Diagnostics;

class Program
{
    public static void Main()
    {
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
    }
}

Для получения дополнительной информации перейдите Используйте секундомер вместо DataTime для получения точного счетчика производительности.

Ответ 12

Я только что нашел сообщение в блоге Vance Morrison о классе CodeTimer, он написал, что упрощает использование StopWatch и делает некоторые аккуратные вещи на сторона.

Ответ 13

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

В Google обнаружено много ресурсов/статей для проверки производительности.

Многие упоминают использование pinvoke для получения информации о производительности. Многие материалы, которые я изучаю, действительно упоминают с использованием perfmon.

Edit:

Видите переговоры о StopWatch. Приятно! Я кое-чему чему научился:)

Это выглядит как хорошая статья

Ответ 14

Как я использую в своих программах, используется класс StopWatch, как показано здесь.

Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

Ответ 15

Это недостаточно профессионально:

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

Более надежная версия:

PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat);

В моем реальном коде я добавлю вызов GC.Collect, чтобы изменить управляемую кучу в известное состояние, и добавьте вызов сна, чтобы разные интервалы кода можно было легко разделить в профиле ETW.