1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2011-2012, Google, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.dev.util; 10 11 import com.ibm.icu.text.DecimalFormat; 12 import com.ibm.icu.text.NumberFormat; 13 import com.ibm.icu.util.ULocale; 14 15 public final class Timer { 16 public static final long SECONDS = 100000000; 17 18 private long startTime; 19 private long duration; 20 private boolean timing = false; 21 private int iterations; 22 private long timingPeriod = 5*SECONDS; 23 { 24 start(); 25 } 26 27 public Timer start() { 28 startTime = System.nanoTime(); 29 timing = true; 30 duration = Long.MIN_VALUE; 31 return this; 32 } 33 34 public long getDuration() { 35 if (timing) { 36 duration = System.nanoTime() - startTime; 37 timing = false; 38 } 39 return duration; 40 } 41 42 public long stop() { 43 return getDuration(); 44 } 45 46 public int getIterations() { 47 return iterations; 48 } 49 50 public long getTimingPeriod() { 51 return timingPeriod; 52 } 53 54 public Timer setTimingPeriod(long timingPeriod) { 55 this.timingPeriod = timingPeriod; 56 return this; 57 } 58 59 public DecimalFormat getNumberFormat() { 60 return nf; 61 } 62 63 public DecimalFormat getPercentFormat() { 64 return pf; 65 } 66 67 public String toString() { 68 return nf.format(getDuration()) + "\tns"; 69 } 70 public String toString(Timer other) { 71 return toString(1L, other.getDuration()); 72 } 73 public String toString(long iterations) { 74 return nf.format(getDuration()/iterations) + "\tns"; 75 } 76 77 public String toString(long iterations, long other) { 78 return nf.format(getDuration()/iterations) + "\tns\t" + pf.format((double)getDuration()/other - 1D) + ""; 79 } 80 81 private DecimalFormat nf = (DecimalFormat) NumberFormat.getNumberInstance(ULocale.ENGLISH); 82 private DecimalFormat pf = (DecimalFormat) NumberFormat.getPercentInstance(ULocale.ENGLISH); 83 84 { 85 pf.setMaximumFractionDigits(1); 86 pf.setPositivePrefix("+"); 87 } 88 89 public abstract static class Loop { 90 public void init(Object... params) {} 91 abstract public void time(int repeat); 92 } 93 94 public long timeIterations(Loop loop, Object... params) { 95 // Timing on Java is very tricky, especially when you count in garbage collection. This is a simple strategy for now, we might improve later. 96 // The current strategy is to warm up once, then time it until we reach the timingPeriod (eg 5 seconds), increasing the iterations each time 97 // At first, we double the iterations. 98 // Once we get to within 1/4 of the timingPeriod, we change to adding 33%, plus 1. We also remember the shortest duration from this point on. 99 // We return the shortest of the durations. 100 loop.init(params); 101 System.gc(); 102 start(); 103 loop.time(1); 104 stop(); 105 iterations = 1; 106 long shortest = Long.MAX_VALUE; 107 while (true) { 108 System.gc(); 109 start(); 110 loop.time(iterations); 111 stop(); 112 if (duration >= timingPeriod) { 113 duration /= iterations; 114 return Math.min(duration, shortest); 115 } else if (duration >= timingPeriod / 4) { 116 duration /= iterations; 117 shortest = Math.min(duration, shortest); 118 iterations = (iterations * 4) / 3 + 1; 119 } else { 120 iterations = iterations * 2; 121 } 122 } 123 } 124 }