Точное измерение времени в Java
Java предоставляет доступ к двум методам для получения текущего времени: System.nanoTime()
и System.currentTimeMillis()
. Первый дает результат в наносекундах, но фактическая точность намного хуже (много микросекунд).
Является ли JVM уже предоставлением наилучшего возможного значения для каждой конкретной машины?
В противном случае существует ли какая-то библиотека Java, которая может дать более точные измерения, возможно, привязавшись к определенной системе?
Ответы
Ответ 1
Проблема получения сверхточных измерений времени заключается в том, что некоторые процессоры не могут/не обеспечивают такие крошечные приращения.
Насколько я знаю, System.currentTimeMillis()
и System.nanoTime()
- лучшее измерение, которое вы сможете найти.
Обратите внимание, что оба возвращают значение long
.
Ответ 2
Это немного бессмысленно в Java, измеряющем время до наносекундного масштаба; случайный удар GC легко уничтожит любую точность, которую это могло бы дать. В любом случае в документации указывается, что, хотя она дает наносекундную точность, это не то же самое, что наносекундная точность; и есть операционные системы, которые в любом случае не сообщают о наносекундах (именно поэтому вы найдете ответы, квантованные до 1000 при доступе к ним, это не удача, это ограничение).
Не только это, но в зависимости от того, как функция фактически реализована ОС, вы можете найти квантованные результаты, которые все равно пройдут (например, ответы, которые всегда заканчиваются на 64 или 128 вместо промежуточных значений).
Также стоит отметить, что цель метода состоит в том, чтобы найти две временные различия между некоторым (ближайшим) временем начала и сейчас; если вы запустите System.nanoTime() в начале долговременного приложения, а затем запустите System.nanoTime() уже долгое время, возможно, он довольно далеко от реального времени. Поэтому вы должны использовать его только в периоды менее 1 с; если вам требуется более длительное время работы, миллисекунды должны быть достаточными. (И если это не так, то составьте последние несколько чисел, вы, вероятно, произведете впечатление на клиентов, и результат будет таким же правильным.)
Ответ 3
К сожалению, я не думаю, что в настоящий момент java RTS достаточно зрелый.
Время Java пытается обеспечить наилучшее значение (они фактически делегируют собственный код, чтобы вызвать получение времени ядра). Однако спецификации JVM делают это грубое исключение времени измерения главным образом для таких вещей, как деятельность GC и поддержка базовой системы.
- Некоторые действия GC будут блокировать все потоки, даже если вы используете параллельный GC.
- Значение по умолчанию для таймера синхронизации по умолчанию составляет всего 10 мс. Java не может сделать его лучше, если Linux-сервер не поддерживает.
Я не понял, как обращаться к № 1, если вашему приложению не нужно делать GC. Порядочное приложение и размер медикаментов, возможно, время от времени тратят на GC-паузы в десятки миллисекунд. Вам, вероятно, не повезло, если ваши требования к точности ниже 10 мс.
Что касается # 2, вы можете настроить ядро linux, чтобы повысить точность. Тем не менее, вы также получаете меньше из своей коробки, потому что теперь переключиться на контекст ядра чаще.
Возможно, мы должны смотреть на него разным углом. Есть ли причина, по которой OPS нуждается в точности 10 мс ниже? Можно ли сказать Ops, что точность составляет 10 мс, а также посмотреть на журнал GC в то время, так что они знают, что время + -10 мс без учета активности GC в это время?
Ответ 4
Если вы хотите записать какое-то явление в порядке порядка наносекунд, то вам действительно нужна операционная система в режиме реального времени, Точность таймера будет в значительной степени зависеть от реализации операционной системы своего таймера высокого разрешения и основного оборудования.
Однако вы все равно можете оставаться с Java, поскольку доступны версии RTOS.
Ответ 5
JNI:
Создайте простую функцию для доступа к инструкции Intel RDTSC или реестру PMCCNTR сопроцессора p15 в ARM.
Чистая Java:
Вы можете получить более качественные значения, если вы готовы отложить до тех пор, пока не начнется отсчет такта. Вы можете проверять систему System.nanoTime(), пока значение не изменится. Если вы знаете, например, что значение System.nanoTime() меняет каждые 10000 циклов на вашей платформе по сумме DELTA, тогда фактическое время события было finalNanoTime-DELTA * ITERATIONS/10000. Вам нужно будет "разогреть" код перед выполнением фактических измерений.
Взлом (только для профилирования и т.д.):
Если сбор мусора отбрасывает вас, вы всегда можете измерить время, используя поток с высоким приоритетом, выполняющийся во втором jvm, который не создает объекты. Имейте это вращение, увеличивая длинную в общей памяти, которую вы используете в качестве часов.