Точное измерение времени в Java

Java предоставляет доступ к двум методам получения текущего времени: System.nanoTime() и System.currentTimeMillis(). Первый дает результат в наносекундах, но реальная точность намного хуже (много микросекунд).

Обеспечивает ли JVM наилучшую возможную ценность для каждой конкретной машины? В противном случае, есть ли какая-нибудь библиотека Java, которая может дать более точные измерения, возможно, за счет привязки к конкретной системе?


person penpen    schedule 30.09.2009    source источник
comment
В какой операционной системе вы доказали, что System.nanoTime() выдает результат, который отличается на много микросекунд?   -  person James Jones    schedule 01.10.2009
comment
Это было в системе Linux на двухъядерном компьютере, но это была довольно старая установка (с начала 2007 года...). Может быть, это было причиной. Я проверю что-нибудь более свежее. Кроме того, насколько я помню, у меня были последовательные вызовы, возвращающие одно и то же значение, а затем прыгали на несколько микросекунд.   -  person penpen    schedule 01.10.2009


Ответы (5)


Проблема с получением сверхточных измерений времени заключается в том, что некоторые процессоры не могут/не обеспечивают такие крошечные приращения.

Насколько я знаю, System.currentTimeMillis() и System.nanoTime() — лучшее измерение, которое вы сможете найти.

Обратите внимание, что оба возвращают значение long.

person jjnguy    schedule 30.09.2009
comment
Современные процессоры (> 1 ГГц) работают быстрее, чем 1 наносекунда, поэтому технически они вполне способны. - person James Jones; 01.10.2009
comment
Они могли бы отслеживать время, но это не значит, что они сообщают время так точно. - person jjnguy; 01.10.2009
comment
Не забывайте, что есть накладные расходы: задействован системный вызов, который обычно составляет порядка микросекунд (просто для перехода к ядру и обратно, но это дорогостоящая часть для чтения часов). Тогда у вас может быть загруженная система с включенным упреждением, что означает, что какой-то другой процесс может быть запланирован. Даже если это не так, это означает, что вам все равно придется прыгать в JVM, и даже с JIT-кодом будут небольшие накладные расходы. В нативном режиме вы можете использовать API clock_gettime & friends для изучения точности таймеров с высоким разрешением. - person Vitali; 01.10.2009
comment
Действительно, я только что попробовал на своей домашней машине, похоже, что нановремя действительно занимает больше одной микросекунды (среднее значение равно 1,2, измерено путем вызова его 100000 раз). - person penpen; 01.10.2009
comment
Точность тика времени в Linux по умолчанию составляет 10 мс, поэтому запрос наносекунды бесполезен, если вы не настроите ядро ​​​​для его поддержки (URL-адрес того, как настроить, находится в моем ответе) - person Oscar Chan; 01.10.2009

В Java немного бессмысленно измерять время до наносекундного масштаба; случайное попадание GC легко уничтожит любую точность, которую это могло бы дать. В любом случае, в документации указано, что, хотя это дает точность в наносекундах, это не то же самое, что точность в наносекундах; и есть операционные системы, которые в любом случае не сообщают о наносекундах (поэтому при доступе к ним вы найдете ответы, квантованные до 1000; это не удача, это ограничение).

Не только это, но и в зависимости от того, как эта функция на самом деле реализована в ОС, вы все равно можете обнаружить квантованные результаты (например, ответы, которые всегда заканчиваются на 64 или 128 вместо промежуточных значений).

Также стоит отметить, что цель метода состоит в том, чтобы найти две разницы во времени между некоторым (близким) временем начала и сейчас; если вы берете System.nanoTime() в начале долго работающего приложения, а затем используете System.nanoTime() много времени спустя, это может быть довольно далеко от реального времени. Таким образом, вы должны действительно использовать его только в течение периодов менее 1 с; если вам нужно более длительное время работы, миллисекунд должно быть достаточно. (А если это не так, то придумайте последние несколько цифр; вы, вероятно, произведете впечатление на клиентов, и результат будет таким же достоверным.)

person AlBlue    schedule 30.09.2009
comment
Таким образом, вы должны действительно использовать его только в течение периодов менее 1 с. Это для небольшого повторяющегося явления. А если нет, то составить последние несколько цифр. Нет, они могут попытаться воспроизвести это :) - person penpen; 01.10.2009

К сожалению, я не думаю, что на данный момент Java RTS достаточно развита.

Время Java пытается обеспечить наилучшее значение (они фактически делегируют собственный код для вызова получения времени ядра). Тем не менее, спецификации JVM делают это грубое измерение времени отказом от ответственности в основном для таких вещей, как действия GC и поддержка базовой системы.

  • Некоторые действия сборщика мусора будут блокировать все потоки, даже если вы выполняете параллельный сборщик мусора.
  • Точность тика часов по умолчанию в Linux составляет всего 10 мс. Java не может сделать его лучше, если ядро ​​​​linux не поддерживает.

Я не понял, как обратиться к #1, если только вашему приложению не нужно выполнять GC. Приличное приложение среднего размера, вероятно, иногда тратит десятки миллисекунд на паузы GC. Вам, вероятно, не повезло, если ваше требование к точности ниже 10 мс.

Что касается № 2, вы можете настроить ядро ​​Linux на дать больше точности. Тем не менее, вы также получаете меньше из своей коробки, потому что теперь контекст ядра переключается чаще.

Возможно, стоит взглянуть на это под другим углом. Есть ли причина, по которой OPS требует точности на 10 мс ниже? Можно ли сказать оператору, что точность составляет 10 мс, И также просмотреть журнал GC в это время, чтобы они знали, что время с точностью +-10 мс без активности GC в это время?

person Oscar Chan    schedule 30.09.2009
comment
Некоторые действия сборщика мусора будут блокировать все потоки, даже если вы выполняете параллельный сборщик мусора. Вы правы, но с другой стороны, при некоторой настройке параметров JVM это можно частично облегчить. И как было предложено, да, время, прошедшее в GC, можно учесть и убрать. - person penpen; 01.10.2009
comment
Я не хочу сказать, что мы не можем его настроить. Я хочу сказать, что вы не можете заставить GC снизиться до уровня наносекунд, который вам нравится, даже если вы его настроите. Это было мое определение достойных приложений, которые уже должны быть настроены :) - person Oscar Chan; 01.10.2009

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

Однако вы все равно можете использовать Java, так как доступны версии RTOS.

person James Jones    schedule 30.09.2009

JNI: создайте простую функцию для доступа к инструкции Intel RDTSC или регистру PMCCNTR сопроцессора p15 в ARM.

Чистая Java: вы можете получить лучшие значения, если готовы отложить до тиканья часов. Вы можете вращать проверку System.nanoTime() до тех пор, пока значение не изменится. Если вы знаете, например, что значение System.nanoTime() изменяется каждые 10000 итераций цикла на вашей платформе на величину DELTA, тогда фактическое время события было finalNanoTime-DELTA*ITERATIONS/10000. Вам нужно будет «разогреть» код, прежде чем проводить фактические измерения.

Взлом (только для профилирования и т. д.): если сборка мусора сбивает вас с толку, вы всегда можете измерить время, используя высокоприоритетный поток, работающий во втором jvm, который не создает объекты. Заставьте его вращаться, увеличивая длину в общей памяти, которую вы используете в качестве часов.

person William Deans    schedule 25.01.2017
comment
Интересно, каковы накладные расходы на вызов JNI. Если он близок к нулю, RDTSC действительно будет подходящим вариантом. - person clankill3r; 05.08.2019