Комментарии 11
Спасибо за статью! Давно на C#, но как то упустил этот момент!
На счёт HPET'а есть несколько вопросов:
1) как в C# узнать, есть ли вообще этот HPET?
2) какой драйвер отвечает за HPET (в линуксе и в винде)? Можно ли настроить HPET в Линуксе+Mono? (Или если это продукция Microsoft, то типа нельзя...)
3*) что будет, если драйвер HPET'а будет настроен некорректно? в функциях класса Stopwatch есть try тела или же ждёт нас fotal error? (Больше всего интересно для Линукса...)
4) какова погрешность «замера» с учётом различных проверок в самом Stopwatch?
5) Верно ли я понимаю, что в многопроцессорных системах HPET не используется? Если используется, то как решаются «проблема гонок»? Или каждый проц имеет свой HPET?..
На счёт HPET'а есть несколько вопросов:
1) как в C# узнать, есть ли вообще этот HPET?
2) какой драйвер отвечает за HPET (в линуксе и в винде)? Можно ли настроить HPET в Линуксе+Mono? (Или если это продукция Microsoft, то типа нельзя...)
3*) что будет, если драйвер HPET'а будет настроен некорректно? в функциях класса Stopwatch есть try тела или же ждёт нас fotal error? (Больше всего интересно для Линукса...)
4) какова погрешность «замера» с учётом различных проверок в самом Stopwatch?
5) Верно ли я понимаю, что в многопроцессорных системах HPET не используется? Если используется, то как решаются «проблема гонок»? Или каждый проц имеет свой HPET?..
Попробую ответить на Ваши вопросы:
1) У Stopwatch есть статическое свойство IsHighResolution — которое как раз определяет используется ли HPET;
2) Вики говорит, что следующие операционные системы поддерживают и используют HPET:
Windows Vista, Windows 2008, Windows 7, Windows 8
Mac OS X (версия для x86)
Linux версий 2.6 (драйвер rtc-cmos вместо rtc)
FreeBSD;
3) Если он будет настроен некорректно, я думаю, что он просто не будет использоваться, функция QueryPerformanceFrequency вернет false, ни один метод класса Stopwatch не имеет блоков try/catch;
4) Сложный вопрос. В общем все методы класса очень просты, поэтому замеры должны быть весьма точные;
5) На многопроцессорных системах HPET есть у каждого процессора и как я понял они не синхронизированны… Проблемы возникали на первых многоядерных процессорах, но сейчас производители исправили их. Кстати у класса Stopwatch есть на этот случай проверка в методе Stop, я писал о ней.
Вот нашел документацию от Intel по HPET: www.intel.com/content/www/us/en/software-developers/software-developers-hpet-spec-1-0a.html?wapkw=hpet
1) У Stopwatch есть статическое свойство IsHighResolution — которое как раз определяет используется ли HPET;
2) Вики говорит, что следующие операционные системы поддерживают и используют HPET:
Windows Vista, Windows 2008, Windows 7, Windows 8
Mac OS X (версия для x86)
Linux версий 2.6 (драйвер rtc-cmos вместо rtc)
FreeBSD;
3) Если он будет настроен некорректно, я думаю, что он просто не будет использоваться, функция QueryPerformanceFrequency вернет false, ни один метод класса Stopwatch не имеет блоков try/catch;
4) Сложный вопрос. В общем все методы класса очень просты, поэтому замеры должны быть весьма точные;
5) На многопроцессорных системах HPET есть у каждого процессора и как я понял они не синхронизированны… Проблемы возникали на первых многоядерных процессорах, но сейчас производители исправили их. Кстати у класса Stopwatch есть на этот случай проверка в методе Stop, я писал о ней.
Вот нашел документацию от Intel по HPET: www.intel.com/content/www/us/en/software-developers/software-developers-hpet-spec-1-0a.html?wapkw=hpet
Использовать или не использовать класс Stopwatch решать Вам. Однако как мне кажется преимуществ у данного класса, все же больше чем недостатков.
А что тут решать — альтернатив-то нет. По крайней мере это самый точный способ замера времени, опирающийся на аппаратные особенности. И по крайней мере лично у меня ни разу не было случая, чтобы его разрешающей точности не хватило. Если с ElapsedMilliseconds это случалось, то вот с тиками все всегда точно считается.
Кстати, про точность — у Stopwatch метод ElapsedMilliseconds грубый, т.к. выдаёт long,
и часто удобнее пользоваться методом Elapsed.TotalMilliseconds (он выдаёт double).
Главное — не наступить на известные грабли, написав по-ошибке Elapsed.Milliseconds — это может прекрасно работать (по опыту выгребания багов — годами), но только до тех пор, пока измеряемый интервал не превысит 1 секунду :)
и часто удобнее пользоваться методом Elapsed.TotalMilliseconds (он выдаёт double).
Главное — не наступить на известные грабли, написав по-ошибке Elapsed.Milliseconds — это может прекрасно работать (по опыту выгребания багов — годами), но только до тех пор, пока измеряемый интервал не превысит 1 секунду :)
Лично мне работать со Stapwatch классом показалось не очень удобно. Написал простую оболочку StopwatchOperation задача которой быстро обвернуть код и вывести в трейс (как пример) результат замера.
Пример использования:
Код:
Пример использования:
using (new StopwatchOperation("TODO: Ваше имя тут"))
{
// Мой код тут
}
Код:
public class StopwatchOperation: IDisposable
{
public string Name { get; set; }
protected Stopwatch InnerStopwatch { get; set; }
public StopwatchOperation(string name)
{
this.InnerStopwatch = new Stopwatch();
this.Name = name;
this.InnerStopwatch.Start();
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if(this.InnerStopwatch!=null)
{
this.InnerStopwatch.Stop();
Trace.WriteLine(string.Format("Duration of '{0}' is {1} milliseconds.", this.Name, this.InnerStopwatch.ElapsedMilliseconds));
this.InnerStopwatch = null;
}
}
}
#endregion
}
не знаю, мне Extension всегда хватало, тем более, что время можно вернуть, а не просто писать в Trace:
используем
в случае Action можно вызыать и просто как Extension:
public static class StopwatchExtension
{
public static TimeSpan GetElapsedTime(this Action action)
{
var sw = Stopwatch.StartNew();
action();
sw.Stop();
return sw.Elapsed;
}
}
используем
var elapsed = StopwatchExtension.GetElapsedTime(() =>
{
for (int i = 0; i < 1000; i++)
{
Debug.WriteLine(i);
}
});
Console.WriteLine(elapsed);
в случае Action можно вызыать и просто как Extension:
Action action = () =>
{
for (int i = 0; i < 1000; i++)
{
Debug.WriteLine(i);
}
};
var elapsed = action.GetElapsedTime();
Console.WriteLine(elapsed);
А сам автор сталкивался хоть раз с «ошибкой в BIOS/HAL»? :) Я боюсь, это какие-то совсем пограничные и не интересные случаи.
А касательно точности, тут всё ещё проще: если вы замеряете отработку «a + b», она пролетает за мгновения мысли. Соотв. измерения такой величины грешат больше, чем сама величина. Поэтому если речь о бенчмарках, там ставят циклы по тысяче/миллионам операций и измеряют уже в секундах. А раз секунды, тут хоть DateTime меряй.
А касательно точности, тут всё ещё проще: если вы замеряете отработку «a + b», она пролетает за мгновения мысли. Соотв. измерения такой величины грешат больше, чем сама величина. Поэтому если речь о бенчмарках, там ставят циклы по тысяче/миллионам операций и измеряют уже в секундах. А раз секунды, тут хоть DateTime меряй.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Под капотом у Stopwatch