Это Система.nanoTime() совершенно бесполезно?



как описано в блоге остерегайтесь системы.nanoTime() в Java, на системах x86, система Java.nanoTime() возвращает значение времени с помощью CPU конкретного счетчика. Теперь рассмотрим следующий случай, который я использую для измерения времени вызова:



long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;


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



учитывая этот случай, разве это не та система.nanotime практически бесполезны сейчас?



Я знаю, что изменение системного времени не влияет на nanotime. Это не та проблема, которую я описываю выше. Проблема в том, что каждый процессор будет держать другой счетчик, так как он был включен. Этот счетчик может быть ниже на втором процессоре по сравнению с первым процессором. Поскольку поток может быть запланирован ОС на второй процессор после получения time1, значение timeSpent может быть неправильным и даже отрицательным.

332   14  

14 ответов:

этот пост неправильный, и nanoTime безопасно. Есть комментарий к сообщению, которое ссылается на сообщение в блоге Дэвида Холмса, в реальном времени и параллелизм парень на Солнце. Он говорит:

система.nanoTime () реализуется с помощью API QueryPerformanceCounter/QueryPerformanceFrequency [...] Механизм по умолчанию, используемый QPC, определяется уровнем аппаратной абстракции (HAL) [...] Это значение по умолчанию изменяется не только в аппаратных средствах, но и в версиях ОС. Для пример Windows XP Service Pack 2 изменил вещи, чтобы использовать таймер управления питанием (PMTimer), а не счетчик времени процессора (TSC) из-за проблем с TSC не синхронизируется на разных процессорах в системах SMP, и из-за того, что его частота может варьироваться (и, следовательно, его отношение к прошедшему времени) на основе параметров управления питанием.

Итак, на Windows, это был проблема до WinXP SP2, но это не сейчас.

Я не могу найдите Часть II (или больше), которая говорит о других платформах, но эта статья включает замечание о том, что Linux столкнулся и решил ту же проблему таким же образом, со ссылкой на часто задаваемые вопросы при успешном выполнении функции clock_gettime(CLOCK_REALTIME), который говорит:

  1. является ли clock_gettime(CLOCK_REALTIME) последовательным для всех процессоров/ядер? (Имеет ли значение арка? например, ppc, arm, x86, amd64, sparc).

Это должны или это считается багги.

однако на x86 / x86_64 можно увидеть несинхронизированные или переменные freq TSCs вызывают временные несоответствия. 2.4 ядра действительно не имели никакой защиты от этого, и ранние 2.6 ядра тоже не слишком хорошо справлялись здесь. Начиная с 2.6.18 и выше логика для обнаружения этого лучше, и мы обычно возвращаемся к безопасному источнику часов.

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

Итак, если ссылка Холмса может следует читать как подразумевающий, что nanoTime звонки clock_gettime(CLOCK_REALTIME), то это безопасно - иш как ядра 2.6.18 на x86, и всегда на PowerPC (потому что IBM и Motorola, в отличие от Intel, на самом деле знают, как проектировать микропроцессоры).

там нет никакого упоминания о SPARC или Solaris, к сожалению. И конечно, мы понятия не имеем, что делают IBM JVMs. Но Sun JVMs на современных Windows и Linux получают это право.

EDIT: этот ответ основан на источниках, которые он цитирует. Но я все равно беспокоюсь, что это может быть совершенно неправильный. Более свежая информация была бы действительно ценной. Я только что наткнулся на ссылку на четыре года новая статья о часах Linux что может быть полезным.

Я немного поискал и обнаружил, что если кто-то педантичен, то да, это можно было бы рассмотреть useless...in в частности situations...it зависит от того, насколько чувствительны ваши требования ко времени...

проверить эта цитата С сайта Java Sun:

часы реального времени и Система.nanoTime() основаны на тот же системный вызов и так же часы.

с Java RTS, все основанные на времени API (например, Таймеры Периодические Темы, мониторинг сроков и т. д далее) основаны на том таймер высокого разрешения. И, вместе с приоритетами в реальном времени, они могут убедитесь, что соответствующий код будет быть выполнены в нужное время ограничения в реальном времени. В отличие от, обычные API Java SE предлагают всего несколько методы, способные к обработке времена высоко-разрешения, без гарантия исполнения по заданному адресу время. использование системы.nanoTime() между различные точки в коде для выполнения измерения прошедшего времени должны всегда будьте точны.

Java также имеет предостережение для nanoTime () способ:

этот метод можно использовать только для измерьте затраченное время и нет связанные с любым другим понятием системы или настенные часы. Возвращаемое значение представляет наносекунды, так как некоторые фиксированное, но произвольное время (возможно, в будущее, поэтому ценности могут быть негативный.) Этот метод обеспечивает наносекундная точность, но не обязательно наносекундная точность. Нет гарантии сделаны о том, как часто значения меняются. Различия в последовательных вызовах, которые охватывают больше чем примерно 292,3 года (263 наносекунды) не будет точно вычислить затраченное время из-за численного переполнение.

Итак, чтобы ответить на ваш question...no nanoTime() не бесполезен....его просто не самый разумный метод, чтобы использовать в любой ситуации.

Не нужно спорить, просто используйте источник. Здесь, SE 6 для Linux, сделайте свои собственные выводы:

jlong os::javaTimeMillis() {
  timeval time;
  int status = gettimeofday(&time, NULL);
  assert(status != -1, "linux error");
  return jlong(time.tv_sec) * 1000  +  jlong(time.tv_usec / 1000);
}


jlong os::javaTimeNanos() {
  if (Linux::supports_monotonic_clock()) {
    struct timespec tp;
    int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
    assert(status == 0, "gettime error");
    jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
    return result;
  } else {
    timeval time;
    int status = gettimeofday(&time, NULL);
    assert(status != -1, "linux error");
    jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
    return 1000 * usecs;
  }
}

отказ от ответственности: я разработчик этой библиотеки

вам может понравиться это лучше:

http://juliusdavies.ca/nanotime/

но он копирует файл DLL или Unix .so (shared object) в домашний каталог текущего пользователя, чтобы он мог вызывать JNI.

справочная информация на моем сайте по ссылке:

http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html

Linux исправляет расхождения между процессорами, но Windows этого не делает. Я предлагаю вам принять систему.nanoTime() является точным только около 1 микросекунды. Простой способ получить более длительное время-вызвать foo () 1000 или более раз и разделить время на 1000.

абсолютно не бесполезно. Любители синхронизации правильно указывают на многоядерную проблему, но в приложениях реального слова она часто радикально лучше, чем currentTimeMillis().

при вычислении графических позиций в кадре обновление nanoTime () приводит к гораздо более плавному движению в моей программе.

и я тестирую только на многоядерных машинах.

Я видел отрицательный истек времени с использованием системы.nanoTime(). Чтобы быть ясным, код, о котором идет речь:

    long startNanos = System.nanoTime();

    Object returnValue = joinPoint.proceed();

    long elapsedNanos = System.nanoTime() - startNanos;

и переменная 'elapsedNanos' имела отрицательное значение. (Я уверен, что промежуточный вызов также занял менее 293 лет, что является точкой переполнения для nanos, хранящихся в longs:)

Это произошло с помощью IBM v1.5 JRE 64bit на аппаратном обеспечении IBM P690 (многоядерном) под управлением AIX. Я видел эту ошибку только один раз, так что это кажется, крайне редко. Я не знаю причину - это аппаратная проблема, дефект JVM-я не знаю. Я тоже не знаю последствий для точности nanoTime() в целом.

чтобы ответить на исходный вопрос, я не думаю, что nanoTime бесполезно - она обеспечивает суб-миллисекунды времени, но есть реальный (не теоретический) риск неточности, которые нужно учитывать.

я ссылаюсь на то, что по существу является той же дискуссией, где Питер Лоури дает хороший ответ. почему я получаю отрицательное затраченное время с помощью системы.nanoTime()?

многие люди упоминали, что в системе Java.nanoTime() может вернуть отрицательное время. Я прошу прощения за повторение того, что уже сказали другие люди.

  1. nanoTime () - это не часы, а счетчик циклов процессора.
  2. возвращаемое значение делится на частоту, чтобы выглядеть так время.
  3. частота процессора может меняться.
  4. когда ваш поток запланирован на другом процессоре, есть шанс получить nanoTime (), что приводит к отрицательной разницы. Это логично. Счетчики между процессорами не синхронизируются.
  5. во многих случаях вы можете получить довольно обманчивые результаты, но вы не сможете сказать, потому что дельта не отрицательна. Думать об этом.
  6. (неподтвержденные) я думаю, что вы можете получить отрицательный результат даже на том же процессоре, если инструкции переупорядочиваются. Чтобы предотвратить это, вам придется вызвать барьер памяти, сериализующий ваши инструкции.

было бы здорово, если бы система.nanoTime () вернул coreID, где он выполнялся.

Это не кажется проблемой на Core 2 Duo под управлением Windows XP и JRE 1.5.0_06.

в тесте с тремя потоками я не вижу системы.nanoTime() идет в обратном направлении. Процессоры оба заняты, и потоки иногда засыпают, чтобы спровоцировать перемещение потоков вокруг.

[EDIT] я бы предположил, что это происходит только на физически отдельных процессорах, т. е. что счетчики синхронизируются для нескольких ядер на одном кристалле.

Java является кроссплатформенной, а nanoTime зависит от платформы. Если вы используете Java - когда не используйте nanoTime. Я нашел реальные ошибки в разных реализациях JVM с этой функцией.

нет, это не так... Это просто зависит от вашего процессора, проверьте Таймер Событий Высокой Точности для того, как / почему вещи по-разному обрабатываются в соответствии с CPU.

в основном, прочитайте источник вашей Java и проверьте, что ваша версия делает с функцией, и если она работает против процессора, вы будете запускать ее.

IBM даже предлагает вы используете его для бенчмаркинга производительности (сообщение 2008 года, но обновлено).

документация Java 5 также рекомендует использовать этот метод для той же цели.

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

Java 5 API Doc

и System.currentTimeMillies() изменения при изменении системных часов, в то время как System.nanoTime() не делает, поэтому последний безопаснее для измерения длительности.

nanoTime крайне небезопасно для синхронизации. Я попробовал его на своих основных алгоритмах тестирования примитивности, и он дал ответы, которые были буквально в одной секунде друг от друга для одного и того же ввода. Не используйте этот нелепый метод. Мне нужно что-то более точное, чем время Миллис, но не так плохо, как nanoTime.

Comments

    Ничего не найдено.