001package org.javasimon.clock; 002 003/** 004 * Utils related to timers and Clock class, especially default implementation based on system timers 005 * ({@link SimonClock#SYSTEM}). 006 * 007 * @since 3.5 008 */ 009@SuppressWarnings({"UnusedDeclaration"}) 010public class SimonClockUtils { 011 012 /** 013 * Value of {@link System#nanoTime()} at a particular time, when {@link #INIT_MILLIS} is initialized as well. 014 * Used in {@link #millisForNano(long)}. 015 * 016 * @since 3.3 017 */ 018 public static final long INIT_NANOS = Calibration.initNanos; 019 020 /** 021 * Value of {@link System#currentTimeMillis()} at a particular time, when {@link #INIT_NANOS} is initialized as well. 022 * Used in {@link #millisForNano(long)}. 023 * 024 * @since 3.3 025 */ 026 public static final long INIT_MILLIS = Calibration.initMillis; 027 028 /** 029 * Measured difference in {@link System#currentTimeMillis()} during calibration. 030 * 031 * @since 3.5 032 */ 033 public static final long MILLIS_GRANULARITY = Calibration.millisGranularity; 034 035 /** 036 * Average difference in {@link System#nanoTime()} during calibration. 037 * 038 * @since 3.5 039 */ 040 public static final long NANOS_GRANULARITY = Calibration.nanosGranularity; 041 042 /** 043 * Converts nano timer value into millis timestamp compatible with {@link System#currentTimeMillis()}. Method does not 044 * just divide nanos by one million, but also works with remembered values for milli- and nano-timers at one particular moment. 045 * 046 * @param nanos nano timer value 047 * @return ms timestamp 048 * @since 3.3 (moved from SimonManager where it was since 3.1) 049 */ 050 public static long millisForNano(long nanos) { 051 return INIT_MILLIS + (nanos - INIT_NANOS) / SimonClock.NANOS_IN_MILLIS; 052 } 053 054 private static class Calibration { 055 056 private static final int NANO_CHANGES = 100; 057 058 private static long initNanos; 059 private static long initMillis; 060 private static long nanosGranularity; 061 062 private static long millisGranularity; 063 064 static { 065 initMillis = System.currentTimeMillis(); 066 long oldNanos; 067 while (true) { 068 oldNanos = System.nanoTime(); 069 long nextMillis = System.currentTimeMillis(); 070 if (nextMillis > initMillis) { 071 millisGranularity = nextMillis - initMillis; 072 initMillis = nextMillis; 073 break; 074 } else { 075 // this ensures that we should get the last possible nano value before initMillis 076 initNanos = oldNanos; 077 } 078 } 079 080 long sumOfNanoDiffs = 0; 081 int nanoChanges = 0; 082 int nanoMeasurements = 0; 083 // we will reuse oldNanos from before 084 while (nanoChanges < NANO_CHANGES) { 085 long nextNanos = System.nanoTime(); 086 nanoMeasurements++; 087 if (nextNanos > oldNanos) { 088 nanoChanges++; 089 sumOfNanoDiffs += nextNanos - oldNanos; 090 oldNanos = nextNanos; 091 } 092 } 093 nanosGranularity = sumOfNanoDiffs / nanoChanges; 094 /* 095 Produces funny results when repeated - granularity differences are striking even during a single Maven build: 096 nanosGranularity = 460 (based on 100 changes and 327 measurements) 097 nanosGranularity = 1198 (based on 100 changes and 324 measurements) 098 nanosGranularity = 605 (based on 100 changes and 328 measurements) 099 System.out.println("nanosGranularity = " + nanosGranularity + " (based on " + nanoChanges + " changes and " + nanoMeasurements + " measurements)"); 100 System.out.println("millisGranularity = " + millisGranularity); 101 */ 102 } 103 } 104}