Вопрос по .net, c# – Измерьте скорость кода в .net в миллисекундах

10

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

Например,

int GetIterationsForExecutionTime(int ms)
{
    int count = 0;
    /* pseudocode 
    do
        some code here
        count++;
    until executionTime > ms
    */

    return count;
}

Как мне сделать что-то подобное?

DateTime.Now имеет разрешение в миллисекундах (хотя и несколько неточное), вы можете получить приблизительное время(DateTime.Now - startTime).TotalMilliseconds, Насколько точно вы должны быть? mellamokb
DateTime.Now с точностью до 1/64 секунды в большинстве операционных систем, к вашему сведению, это означает, чтоdifference из двух datetime обычно отключается на целых 1/32 секунды, и это может быть намного больше.It is in general far better to use Stopwatch for this purpose. Eric Lippert
Отклонение около -100 / + 100 мс. Shawn Mclean

Ваш Ответ

4   ответа
13
var sw = new Stopwatch();
sw.Start();
...
long  elapsedMilliseconds = sw.ElapsedMilliseconds;
Разве вы не должны остановить SW? :)
Нет, вы можете прочитать это свойство в любое время.
-1

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

                // JIT optimization.
                if (i == 0)
                {
                    // Discard every result you've collected.
                    // And restart the timer.
                    stopwatch.Restart();
                }
28

e x milliseconds to finish.

Во-первых, просто не делайте этого. Если вам нужно подождать определенное количество миллисекундdo not busy-wait in a loop, Скорее,start a timer и вернуться. Когда таймер тикает, пусть он вызывает метод, который возобновляется с того места, где вы остановились.Task.Delay метод может быть хорошим для использования; он заботится о деталях таймера для вас.

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

Сначала вы всегда должны использоватьStopwatch и никогда не использоватьDateTime.Now за эти сроки. Секундомер разработан, чтобы быть высокоточным таймером, чтобы сказать вамhow much time elapsed. DateTime.Now таймер низкой точности, чтобы сказать вам,if it is time to watch Doctor Who yet, Вы не будете использовать настенные часы для измерения времени Олимпийских гонок; Вы бы использовали секундомер с наивысшей точностью, какой только могли. Так что используйте тот, который предоставляется для вас.

Во-вторых, вы должны помнить, чтоC# code is compiled Just In Time, Поэтому первый раз, когда вы проходите цикл, может стоить в сотни или тысячи раз дороже, чем каждый последующий раз, из-за стоимости джиттера, анализирующего код, который вызывает цикл. Если вы намереваетесь измерить «тепло» стоимость цикла, то вам нужно запустить цикл один разbefore Вы начинаете рассчитывать это. Если вы собираетесь измерятьaverage Стоимостьincluding the jit time затем вам нужно решить, сколько раз составляет разумное количество испытаний, чтобы среднее число получилось правильно.

В-третьих, вам нужноmake sure that you are not wearing any lead weights when you are running, Никогда не делайте измерения производительностиwhile debugging, Это удивительное количество людей, которые делают это. Если вы находитесь в отладчике, то время выполнения может бытьtalking back and forth with the debugger чтобы убедиться, что вы получаете необходимый опыт отладки, и эта болтовня требует времени. Джиттер генерируетworse code чем обычно, так что ваш опыт отладки будет более последовательным. Сборщик мусора естьcollecting less aggressively, И так далее. Всегда запускайте измерения производительности вне отладчика и с включенными оптимизациями.

В-четвертых, помните, чтоvirtual memory systems impose costs similar to those of jitters, Если вы уже запускаете управляемую программу или недавно запустили ее, то страницы CLR, которые вам нужны, скорее всего, будут "горячими". - уже в оперативной памяти - где они быстрые. Если нет, то страницы могут быть холодными, на диске и могут быть повреждены. Это может сильно изменить время.

В-пятых, помните, чтоthe jitter can make optimizations that you do not expect, Если вы попробуете время:

// Let's time addition!
for (int i = 0; i < 1000000; ++i) { int j = i + 1; }

джиттерentirely within its rights to remove the entire loop, Он может понять, что цикл не вычисляет значение, которое используется где-либо еще в программе, и полностью удаляет его, давая ему времяzero, Так ли это? Может быть. Возможно, нет. Это зависит от дрожания. Вы должны измерить производительностьrealistic codeгде вычисленные значения фактически используются каким-либо образом; тогда джиттер узнает, что не может их оптимизировать.

В-шестых, сборщик мусора может выбросить время испытаний, которые создают много мусора. Предположим, у вас есть два теста, один из которых создает много мусора, а другой - немного. Стоимость сбора мусора, произведенного в ходе первого теста, может быть «снята» до времени, необходимого для запуска второго теста, если, к счастью, первый тест удается запустить без сбора, но второй тест запускает один. Если ваши тесты приводят к большому количеству мусора, то подумайте (1), реалистичен ли мой тест для начала? Нет смысла измерять производительность нереалистичной программы, потому что вы не можете сделать правильные выводы о том, как будет вести себя ваша настоящая программа. И (2) я должен взимать стоимость сбора мусора для теста, который произвел мусор? Если это так, то убедитесь, что вы форсируете полный сбор данных до того, как закончится время теста.

В-седьмых, вы выполняете свой код в многопоточной, многопроцессорной среде, где потоки могут переключаться по желанию, и где количество потоков (количество времени, которое операционная система даст другому потоку, пока у вас не появится возможность запустить снова), составляет около 16 миллисекунд 16 миллисекунд составляет околоfifty million processor cycles, Получение точного времени выполнения операций с точностью до миллисекунды может быть довольно сложным, если переключение потоков происходит в течение одного из нескольких миллионов циклов процессора, которые вы пытаетесь измерить. Примите это во внимание.

Error: User Rate Limit Exceededif (Debugger.IsAttached) { Console.WriteLine("Debugger is attached, benchmark run invalid (you fool)!"); }Error: User Rate Limit Exceeded
6

Секундомер учебный класс:

int GetIterationsForExecutionTime(int ms)
{
    int count = 0;
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();        
    do
    {
        // some code here
        count++;
    } while (stopwatch.ElapsedMilliseconds < ms);

    stopwatch.Stop();
    return count;
}

Похожие вопросы