Java - Как да измерваме времето с точност до микросекунди в Java

Видях в мрежата, че трябва да използвам System.nanoTime(), но това не работи за мен - дава ми времето с точност до милисекунди. Просто ми трябват микросекунди преди и след изпълнението на моята функция, за да знам колко време ще отнеме. Използвам Windows XP.

По принцип имам този код, който е например 1 милион до 10 милиона вмъквания в свързана Java връзка. Проблемът е, че не мога да измеря правилно точността; понякога отнема по-малко време, за да вмъкнете всичко в по-малък списък.

Правил съм това много пъти - външният цикъл е правил това 20 пъти за всяко k, но резултатът не е много добър. Понякога отнема по-малко време, за да направя 10 милиона вмъквания, отколкото 1 милион, защото не получавам правилното измерено време с това, което използвам в момента (System.nanoTime())

Редактиране 2: Да, използвам Sun JVM.

Редактиране 3: Може да съм направил нещо грешно в кода, ще видя дали ще промени това, което искам.

Редактиране 4: Грешката ми изглежда е, че изпълнявам System.nanoTime(). уф.

Моето предположение е, че тъй като System.nanoTime() използва „най-точния наличен системен таймер“, който изглежда има само милисекунди точност на вашата система, не можете да получите по-добър.

Не ми е ясно какво точно сравнявате, но като общо правило всеки тест, който отнема толкова кратко време, че точността под 50 милисекунди е уместна, ще бъде много предразположен към други нарушения.

Обикновено се опитвам да изпълнявам тестове за поне 10 секунди. Структурата, която пиша в момента, ще познае колко итерации се изпълняват, така че да отнеме 30 секунди. Това означава, че няма да получите просто коренно различни резултатизащото някой друг процес е откраднал процесора за няколко милисекунди.

Бягането по-дълго почти винаги е по-добър подход от опитите за измерване с по-голяма точност.

System.nanoTime() използва брояч в процесора и обикновено е с точност до 1 микросекунда в Windows XP и Linux.

Забележка. Windows XP често е по-малко точен на многопроцесорни машини, защото не компенсира различните процесори, които имат различни броячи. Linux го прави. Бележка 2: Ще се отклони спрямо System.currentTimeMillis(), защото се основава на точността на часовника за вашия процесор (който не трябва да е толкова точен за определен период от време), а не на часовника, който трябва да получите за времето. (който се движи по-малко на ден, но има по-малка детайлност).

Във вашия тест вие основно тествате скоростта, с която можете да създавате нови обекти. Не е изненадващо, че вашите резултати ще варират значително в зависимост от настройките на GC и колко наскоро е извършен GC.

Опитайте да проведете тестове със следните настройки и ще видите много различни резултати.

-verbosegc -XX:NewSize=128m -mx256m

това е странно System.nanoTime() трябва да работи. Използвате ли Sun JVM?

Можете ли просто да повторите операцията си 1000 пъти и да разделите времето на 1000, за да видите какво трябва да знаете?

Трябва да повтаряте тестовете хиляди пъти. Има много неща, които ще повлияят на вашите измервания, като събиране на отпадъци, I/O, пейджинг I/O, размер на нишките на готовата опашка и т.н.

Използване на java.time

За информация, Java 9 и по-нови версии имат нова реализация на часовника, която може да показва текущия момент до наносекунда резолюция.

Класът Instant представлява момент от времевата линия в UTC с наносекунда разделителна способност (до девет (9) десетични цифри).

Обадете се на Instant.now, за да заснемете текущия момент.

    В Java 9 и по-нови засега получавате наносекунди резолюция.

В Java 8 текущият момент се улавя само до милисекунда (вие наистина можете да съхранявате стойности с наносекунди, но да улавяте текущия момент само в милисекунди).

Моментален момент = Instant.now();

Представлява период от време, който не е обвързан с времева линия с класа Duration. Съдържа времето в секунди и наносекунди.

За да бъде ясно, разделителната способност в микросекунди, дадена във въпроса, е между детайли от милисекунди и наносекунди. Броят знаци в десетичната запетая: милис е 3 (0,123), микроните са 6 (0,123456), нано е 9 (0,123456789).

Java използва вашия хардуерен часовник. Както други съобщиха, това оборудване почти сигурно ще улавя времето смного по-малка прецизност имного по-ниска разделителна способност от наносекунди.

Сравнителният анализ на такива фини детайли е изпълнен с проблеми и като цялоне се препоръчва.

Предлага се да се добави инструмент за микро-бенчмаркинг към платформата Java в JEP 230: Microbenchmark Suite. Базиран на Java Microbenchmark Harness (JMH).

Относно java.time

Структурата java.time е вградена в Java 8 и по-нови версии. Тези класове изместват неприятните стари класове за време като java.util.Date, Calendar и SimpleDateFormat.

За да научите повече, вижте ръководството за Oracle. И потърсете в Stack Overflow много примери и обяснения. JSR 310 спецификация.

Къде да получа класове по java.time?

  • Java SE 8 иSE 9 и по-нови версии
  • вградена.
  • Част от стандартния Java API с обединено изпълнение.
  • Java 9 добавя някои незначителни функции и поправки.
  • Java SE 6 иSE 7
  • Голяма част от функционалността на java.time е пренесена към Java 6 и 7 вThreeTen-Backport.
  • Android
  • ПроектътThreeTenABP адаптира ThreeTen-Backport (споменат по-горе) специално за Android.
  • Вижте как да използвате ThreeTenABP. .
  • Проектът ThreeTen-Extra разширява java.time с допълнителни класове. Този проект е доказателство за възможни бъдещи допълнения към java.time. Тук можете да намерите полезни класове като Interval, YearWeek, YearQuarter и други.

    Ако искате да получите надеждни резултати, използвайте профайлър. Предлагам VisualVM, който е лесен за инсталиране и идва с JDK от версия 1.6.0_07. Това е лесен за използване визуален инструмент, който съчетава няколко JDK инструмента от командния ред и леки възможности за профилиране.

    Може би основната операционна система не предоставя таймери с наносекунда точност.

    Да, точността и прецизността на System.nanoTime обикновено е много по-добра от System.currentTimeMillis, но няма гаранция: може да стане също толкова лошо в най-лошия случай.

    ThreadMXBean.getCurrentThreadCpuTime обикновено дава по-малко време, но неговата резолюция е неясна и има допълнителни недостатъци (наистина ли искате процесорно време?, семантика, зависима от платформата, поддържана на вашата платформа?).

    Измерването на времето и с трите метода също има известна цена, т.е. изисква време, което може да изкриви измерванията. Разходите са силно зависими отплатформи, но често струва (System.currentTimeMillis)

    „Бързото и мръсно“ решение, с което се спрях:

    Първоначално използвах System.nanoTime, но след това разбрах, че трябва да се използва само за изминало време, в крайна сметка промених кода си, за да работи с милисекунди или на някои места:

    но това просто ще добави нули в края на стойността (микро = мили * 1000)

    Оставете този отговор тук като „предупредителен знак“, ако някой друг се сети за nanoTime :)

    За скорошното ни профилиране открих, че ThreadMXBean.getCurrentThreadCpuTime() и опцията -XX: + UseLinuxPosixThreadCPUClocks направиха това, от което се нуждаехме.

    Такъв критерий, който разчита на кратък интервал от време, ви дава ненадеждни резултати. Винаги ще получавате различни резултати поради външни фактори като I/O, Swapping, Process Switches, Cache, Garbage Collection и др. Освен това JVM оптимизира вашите повиквания, така че шансовете първите измерени неща да са по-бавни, отколкото по-късно, ще бъдат изчислени. JVM работи все повече и повече, за да оптимизира командите, които изпълнявате.

    Освен това метод като System.nanoTime() зависи от таймерите на основната система. Те може (и най-вероятно ще) нямат детайлността, за да измерват с такава точност. За да донесете API:

    Този метод осигурява наносекунда точност, но не непременно наносекунда точност. Няма гаранции за това колко често се променят стойностите.

    За да измервате наистина с висока точност, трябва да имате достъп до външен таймер с гарантирана точност.

    За да направите теста си по-стабилен, трябва да го изпълнявате повече от веднъж и да измервате повече времеви интервали от простомилисекунди.