Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.03 22:02
Оценка: 179 (25)
#Имя: FAQ.dotnet.PerfCounter
Utils.PerfCounter — простенький классик для точного замера производительности в дотнете.

Измеряет значительно точнее чем Environment.TickCount. Environment.TickCount имеет точность ~ 10 милисекунд, что для измерения коротких участков неприемлимо. Использование QueryPerformanceCounter позволяет обеспечить очень высокую точность.

Использовать так:

// Где нибудь объявляем переменную...
PerfCounter timer = new PerfCounter();

timer.Start(); // Начало замера

// тестируемый код...

// Выводим результат в консоль.
Console.WriteLine("Время выполнения в секундах: {0:### ### ##0.0000}"
    timer.Finish());
// Одну переменную можно использовать многократно.


Код класса:
using System;
using System.Runtime.InteropServices;

namespace Utils
{
    /// <summary>
    /// Эта структура позволяет подсчитать скорость выполнения кода одним из
    /// наиболее точным способов. Фактически вычисления производятся в тактах
    /// процессора, а потом переводятся в милисекунд (десятичная часть 
    /// является долями секунды).
    /// </summary>
    public struct PerfCounter
    {
        Int64 _start;

        /// <summary>
        /// Начинает подсчет вермени выполнения.
        /// </summary>
        public void Start()
        {
            _start = 0;
            QueryPerformanceCounter(ref _start);
        }

        /// <summary>
        /// Завершает полсчет вермени исполнения и возвращает время в секундах.
        /// </summary>
        /// <returns>Время в секундах потраченое на выполнение участка
        /// кода. Десятичная часть отражает доли секунды.</returns>
        public float Finish()
        {
            Int64 finish = 0;
            QueryPerformanceCounter(ref finish);

            Int64 freq = 0;
            QueryPerformanceFrequency(ref freq);
            return (((float)(finish - _start) /(float)freq));
        }

        [DllImport("Kernel32.dll")]
        static extern bool QueryPerformanceCounter(ref Int64 performanceCount);

        [DllImport("Kernel32.dll")]
        static extern bool QueryPerformanceFrequency(ref Int64 frequency);
    }
}
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Точное измерение производительности в дотнете
От: Tom Россия http://www.RSDN.ru
Дата: 23.04.03 12:25
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Utils.PerfCounter — простенький классик для точного замера производительности в дотнете.

Ээээ. А почему структура?
... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re[2]: Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.03 18:13
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Ээээ. А почему структура?


А почему нет? Так бысрее. Структура создается простым сдвигом счетчка стека и не использует GC, т.е. почти не занимает времени.
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Точное измерение производительности в дотнете
От: unprogrammer Россия  
Дата: 24.04.03 03:25
Оценка: +1 -2 :))) :)))
Здравствуйте, VladD2, Вы писали:

VD>Utils.PerfCounter — простенький классик для точного замера производительности в дотнете.


VD>Измеряет значительно точнее чем Environment.TickCount. Environment.TickCount имеет точность ~ 10 милисекунд, что для измерения коротких участков неприемлимо. Использование QueryPerformanceCounter позволяет обеспечить очень высокую точность.


Wrap'ы по осени считают. Целый класс всего для двух Win32API функций, которые все и так знают.

Добавил бы для приличия поддержку нескольких таймеров. Через System.Collections.Hashtable(для именованных таймеров) или самопальный heap(чтоб быстрее было ), или хотя бы просто массив. Для пущего приличия должны кидаться exception'ы собственного типа по случаю тайм-аута(в перегруженный start надо добавить аргумент time-out) или если не произошло замыкающего QueryPerfomanceCounter и был вызван start с этим же ключом. PerfCounterException


Можно сделать также следящий за тайм-аутами и ругающийся thread, динамический список типов таймеров, статистику по отдельным видам таймеров, вывод отчет в xml, поддержку вложенных таймеров, отчет по процентному отношению времени вложенных таймеров к родителю, статистику по всему приложению, загрузка из xml отчета и сверка отчетов

Если все сделаешь, я тогда этот класс буду использовать(это шутка была).
Re[2]: Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.03 17:56
Оценка:
Здравствуйте, unprogrammer, Вы писали:

Ну, вот круг задач ты обозначил. Так что дерзай.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Точное измерение производительности в дотнете
От: WFrag США  
Дата: 02.05.03 02:10
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Измеряет значительно точнее чем Environment.TickCount. Environment.TickCount имеет точность ~ 10 милисекунд, что для измерения коротких участков неприемлимо. Использование QueryPerformanceCounter позволяет обеспечить очень высокую точность...

...но иногда с глюками
MSDN: Q274323
... << RSDN@Home 1.0 beta 6a >>
Re[2]: Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.05.03 23:19
Оценка:
Здравствуйте, WFrag, Вы писали:

WF>...но иногда с глюками

WF>MSDN: Q274323

Ну, это же при глючном железе. По кройне мере я такого не встречал.
... << RSDN@Home 1.0 beta 7a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Точное измерение производительности в дотнете
От: WFrag США  
Дата: 13.05.03 00:45
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, WFrag, Вы писали:


WF>>...но иногда с глюками

WF>>MSDN: Q274323

VD>Ну, это же при глючном железе. По кройне мере я такого не встречал.


Видимо, я везучий. У меня именно такое железо, похоже.
7. О чем невозможно говорить, о том следует молчать.
Re: Точное измерение производительности в дотнете
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 29.05.03 06:35
Оценка: -1
Здравствуйте, VladD2, Вы писали:

VD>Utils.PerfCounter — простенький классик для точного замера производительности в дотнете.


VD>Измеряет значительно точнее чем Environment.TickCount. Environment.TickCount имеет точность ~ 10 милисекунд, что для измерения коротких участков неприемлимо. Использование QueryPerformanceCounter позволяет обеспечить очень высокую точность.


VD>Использовать так:


Для больших кусков кода лучше дополнитеьно вызывать GetThreadTimes.
А для маленьких — rdtsc буде в разы порядков точнее, ибо один вызов этого каунтера занимает в среднем 4000 тактов. Потому и точность у него малая — 8 микросекунд.
Нужно участок кода гонять обязательно несколько раз.

Но для rdtsc нужно дллку писать, иногда это неудобно.
Re[2]: Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.05.03 21:20
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>А для маленьких — rdtsc буде в разы порядков точнее, ибо один вызов этого каунтера занимает в среднем 4000 тактов. Потому и точность у него малая — 8 микросекунд.


Какой ассемблер под дотнетом? А QueryPerformanceCounter его скорее всего и использует.

PE>Нужно участок кода гонять обязательно несколько раз.


Я бы сказал желательно. Так как в 90% случаев разницы нет (проверено).

PE>Но для rdtsc нужно дллку писать, иногда это неудобно.


QueryPerformanceCounter
... << RSDN@Home 1.0 beta 8 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.05.03 21:20
Оценка:
Здравствуйте, WFrag, Вы писали:

WF>Видимо, я везучий. У меня именно такое железо, похоже.


Я пробовал машинах на 40. Все разные, но проблем не встречал.
... << RSDN@Home 1.0 beta 8 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Точное измерение производительности в дотнете
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.06.03 07:06
Оценка:
Здравствуйте, VladD2, Вы писали:

PE>>А для маленьких — rdtsc буде в разы порядков точнее, ибо один вызов этого каунтера занимает в среднем 4000 тактов. Потому и точность у него малая — 8 микросекунд.


VD>Какой ассемблер под дотнетом? А QueryPerformanceCounter его скорее всего и использует.



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

PE>>Нужно участок кода гонять обязательно несколько раз.


VD>Я бы сказал желательно. Так как в 90% случаев разницы нет (проверено).


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

Зачастую повторный вызо сделать нелегко — другая ситуация.
Пример — посылка сообщения окну. Первый вызов выпоняется очень долго, на несколько порядков дольше последующих. Таких примеров тыщи. А QPC тут ничего не покажет.

А на тех платформах, где нет rdtsc преимущество невелико — Perfomance counter аппаратно реализован в основном на x86. На других он эмулируется и точность имеет не лучше чем GetTickCount.
А было бы это не так, то тебе не пришлось бы имплементить классик — он был бы встроен ву фрэймворк.
Re[4]: Точное измерение производительности в дотнете
От: Аноним  
Дата: 19.07.04 15:24
Оценка:
это всё конечно хорошо, но вот если мне дают прогу без сорсов или просто не хочется ничего дополнительно в код писать, то что тогда ? Только Profiling API. Я вот просто мечтаю о проге типа prime.exe, которая меряла все тайминги в Java классах.
Re[5]: Точное измерение производительности в дотнете
От: Igor Sukhov  
Дата: 21.07.04 19:38
Оценка: 8 (1)
Здравствуйте, Аноним, Вы писали:

А>это всё конечно хорошо, но вот если мне дают прогу без сорсов или просто не хочется ничего дополнительно в код писать, то что тогда ? Только Profiling API. Я вот просто мечтаю о проге типа prime.exe, которая меряла все тайминги в Java классах.


это форум "Исходники" — т.е. для тех у кого они есть или им хочется писать. А для твоего случая нужен, как ты правильно догадался — профайлер. В форуме "Инструменты разработки" он обсуждался дня 3 назад.
* thriving in a production environment *
Re[2]: Точное измерение производительности в дотнете
От: fddima  
Дата: 11.08.04 12:48
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Для больших кусков кода лучше дополнитеьно вызывать GetThreadTimes.

PE>А для маленьких — rdtsc буде в разы порядков точнее, ибо один вызов этого каунтера занимает в среднем 4000 тактов. Потому и точность у него малая — 8 микросекунд.
PE>Нужно участок кода гонять обязательно несколько раз.
rdtsc идет в сад по другой причине — измерится общее прошедшее число тактов процессора. А нам нужно измерять время проведенное в _потоке_ (система может вообще его усыпить на 20 минут, и отработает он всего 33мс) вот и мы и должны получить 30-40мс, а не 20 минут
... << RSDN@Home 1.1.4 beta 2 revision 144 >>
Re: Точное измерение производительности в дотнете
От: MShura  
Дата: 16.08.04 09:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Utils.PerfCounter — простенький классик для точного замера производительности в дотнете.


VD>Измеряет значительно точнее чем Environment.TickCount. Environment.TickCount имеет точность ~ 10 милисекунд, что для измерения коротких участков неприемлимо. Использование QueryPerformanceCounter позволяет обеспечить очень высокую точность.


QueryPerformaceCounter и QueryPerformanceFrequency — обе функции это "обертки" вокруг Nt(Zw)QueryPerformanceCounter. Почему не использовать именно её чтобы уменьшить overhead? А так получается обертка вокруг обертки...
Re[2]: Точное измерение производительности в дотнете
От: fddima  
Дата: 16.08.04 10:44
Оценка:
Здравствуйте, MShura, Вы писали:

MS>QueryPerformaceCounter и QueryPerformanceFrequency — обе функции это "обертки" вокруг Nt(Zw)QueryPerformanceCounter. Почему не использовать именно её чтобы уменьшить overhead? А так получается обертка вокруг обертки...

Думаю потому что это класс для .NET, а не обертка над API, да еще такими "нестандартными".
... << RSDN@Home 1.1.4 beta 2 rev. 157>>
Re[2]: Точное измерение производительности в дотнете
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.08.04 11:26
Оценка:
Здравствуйте, MShura, Вы писали:

MS>QueryPerformaceCounter и QueryPerformanceFrequency — обе функции это "обертки" вокруг Nt(Zw)QueryPerformanceCounter. Почему не использовать именно её чтобы уменьшить overhead? А так получается обертка вокруг обертки...


Птому-то это не документированные функции. И мотому что в этом нет нужды.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Точное измерение производительности в дотнете
От: vitaly_spb Россия  
Дата: 01.08.05 12:53
Оценка:
Написал на VB.NET:


Public Structure PerfCounter
        Private _start As Int64

        Public Sub Start()
            _start = 0
            QueryPerformanceCounter(_start)
        End Sub

        Public Function Finish() As Double
            Dim fin As Int64 = 0
            QueryPerformanceCounter(fin)

            Dim freq As Int64 = 0
            QueryPerformanceFrequency(freq)

            Return ((CType((Finish - _start), Single) / CType(freq, Single)))
        End Function


        Declare Function QueryPerformanceCounter Lib "Kernel32.dll" (ByVal performanceCount As Int64) As Boolean

        Declare Function QueryPerformanceFrequency Lib "Kernel32.dll" (ByVal frequency As Int64) As Boolean
End Structure


Но он ругается:

System.NullReferenceException : Object reference not set to an instance of an object.
at PerfCounter.QueryPerformanceFrequency(Int64 frequency)

На таком коде:

Dim a As New PerfCounter
a.Start()
Console.WriteLine(a.Finish())


В чем может быть проблема?!
...Ei incumbit probatio, qui dicit, non qui negat...
Re[2]: Точное измерение производительности в дотнете
От: vitaly_spb Россия  
Дата: 01.08.05 13:17
Оценка:
Исправляем


Public Structure PerfCounter
        Private _start As Int64

        Public Sub Start()
            _start = 0
            QueryPerformanceCounter(_start)
        End Sub

        Public Function Finish() As Single
            Dim fin As Int64 = 0
            QueryPerformanceCounter(fin)

            Dim freq As Int64 = 0
            QueryPerformanceFrequency(freq)

            Return CType(fin - _start, Single) / CType(freq, Single)
        End Function


        Declare Function QueryPerformanceCounter Lib "Kernel32.dll" (ByRef performanceCount As Int64) As Boolean

        Declare Function QueryPerformanceFrequency Lib "Kernel32.dll" (ByRef frequency As Int64) As Boolean
End Structure
...Ei incumbit probatio, qui dicit, non qui negat...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.