Home | History | Annotate | Download | only in util
      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 }