Переворачивается ли когда-нибудь Stopwatch.Gettimestamp? Или откатиться?

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

Это ожидаемое поведение?

Цель этого в производственном коде - иметь системное время с точностью до микросекунды.

Этот метод включает вызов DateTime.UtcNow, а также вызов Stopwatch.GetTimestamp() как originalUtcNow и originalTimestamp соответственно.

С этого момента приложение просто вызывает Stopwatch.GetTimestamp() и с помощью Stopwatch.Frequency вычисляет разницу между исходной переменной Timestamp, а затем добавляет эту разницу к originalUtcNow.

Затем вуаля... эффективный и точный микросекундный DateTime.

Но мы обнаруживаем, что иногда Stopwatch.GetTimestamp() возвращает меньшее число.

Бывает довольно редко. Наше мышление состоит в том, чтобы просто «сбросить», когда это произойдет, и продолжить.

ОДНАКО это заставляет нас сомневаться в точности Stopwatch.GetTimestamp() или подозревать, что в библиотеке .Net есть ошибка.

Если вы можете пролить свет на это, пожалуйста.

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

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


person Wayne    schedule 24.01.2012    source источник
comment
Как у вас может быть системное время с точностью до микросекунды, если UtcNow не является точным в микросекундах? Это число можно использовать только для точного определения времени интервалов.   -  person Groo    schedule 24.01.2012
comment
Прости. Вы мое объяснение читали? Он вызывает UtcNow только один раз при запуске приложения. С этого момента он использует системные часы и вычисляет разницу, чтобы получить текущее время.   -  person Wayne    schedule 24.01.2012
comment
Секундомер использует таймеры с высоким разрешением, когда он имеет к ним доступ или если они существуют на компьютере.   -  person Peter Ritchie    schedule 19.12.2013
comment
Получение отметок времени с высоким разрешением содержит подробное описание. на отметке времени высокопроизводительного счетчика, с иллюстрациями и часто задаваемыми вопросами.   -  person Evgeniy Berezovsky    schedule 12.06.2014


Ответы (4)


Возможно, вы получаете скачок во времени, потому что ваш поток перескакивает ядра. См. «примечание» на этой странице: http://msdn.microsoft.com/en-us/library/ebf7z0sw.aspx

person 500 - Internal Server Error    schedule 24.01.2012
comment
Спасибо! Это следует логике, поскольку это многопоточное приложение. И ваша ссылка подтверждает, что это может быть вызвано аппаратной проблемой и проблемой BIOS. Я отдаю вам должное за ответ. Любое предложение о том, как решить эту проблему? Мы просто сохраняем lastClockTime и сравниваем, оно меньше, чем мы сбрасываем. - person Wayne; 24.01.2012
comment
@Wayne: Environment.TickCount, по-видимому, не страдает от этой проблемы, но он менее точен и переполняется менее чем за месяц. - person Groo; 24.01.2012
comment
Мы уже пострадали от переполнения. Было больно. И это слишком далеко менее точно для наших нужд. В любом случае, спасибо за предложение. - person Wayne; 24.01.2012
comment
@Groo 1) Вы уверены? 2) Какая точность? Это 1мс? Или 15,6 мс? (если вы не увеличите разрешение таймера) - person Eugen Dück; 04.06.2014
comment
@Eugen: нет, я был не прав, комментируя это. Environment.TickCount имеет разрешение ~16 мс, поэтому единственный способ получить лучшее разрешение — это использовать QueryPerformanceCounter (или Stopwatch, который использует это под капотом, при условии, что в этой системе доступны счетчики с высоким разрешением). - person Groo; 05.06.2014

Поведение класса Stopwatch будет варьироваться от системы к системе в зависимости от аппаратной поддержки.

См.: http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.ishighresolution.aspx

Кроме того, я считаю, что базовый эквивалентный вызов win32 (QueryPerformanceCounter) содержит полезную документацию: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx

person Nick    schedule 24.01.2012

Я не знаю точно, что такое бег в обратном направлении (что звучит как небольшое изменение назад), но до сих пор я трижды испытал, что значение Stopwatch.GetTimestamp() может измениться настолько сильно, что вызывает исключения переполнения в некоторых дальнейших вычислениях примерно такого вида:
(Stopwatch.GetTimestamp() - ProgramStartStopwatchTimestamp) * n
где n — какое-то большое значение, но достаточно маленькое, чтобы, если бы секундомер не Если бы не было слишком много прыжков, программа могла бы работать годами без исключения переполнения. Также обратите внимание, что эти исключения произошли через много часов после запуска программы, поэтому проблема не только в том, что секундомер сразу после запуска работал немного назад. Он просто прыгнул в совершенно другой диапазон, в любом направлении.

По поводу переворачивания Секундомера, в одном из вышеперечисленных случаев он (не разница, а Секундомер) получил значение чего-то а-ля 0xFF4? ???? ???? ????, так что он подскочил до диапазона, который был очень близок к переворачиванию. После многократного перезапуска программы этот новый диапазон все еще оставался в силе. Если это имеет значение, учитывая необходимость обрабатывать прыжки в любом случае...

Если нужно было дополнительно определить, на каком ядре была взята временная метка, то, вероятно, полезно знать номер исполняемого ядра. Для этого существуют функции под названием GetCurrentProcessorNumber (доступны, начиная с Server 2003 и Vista) и GetCurrentProcessorNumberEx (доступны, начиная с Server 2008 R2 и Windows 7). См. также ответы на этот вопрос для получения дополнительных опций (включая Windows XP).
Обратите внимание, что номер ядра может быть изменен планировщиком в любое время. Но когда читаешь номер ядра до чтения временной метки Секундомера и после, а номер ядра остался прежним, то, пожалуй, можно предположить, что чтение Секундомера тоже выполнялось на этом ядре...

person Roland Pihlakas    schedule 19.12.2013

Чтобы конкретно ответить на вопрос высокого уровня Как часто Stopwatch.GetTimestamp() переворачивается?, ответ Microsoft:

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

person erdomke    schedule 30.11.2020