Coverage Report - org.dishevelled.timer.Timer
 
Classes in this File Line Coverage Branch Coverage Complexity
Timer
100%
73/73
100%
22/22
1.545
 
 1  
 /*
 2  
 
 3  
     dsh-timer  Timer with nanosecond resolution and summary statistics
 4  
     on recorded elapsed times.
 5  
     Copyright (c) 2004-2013 held jointly by the individual authors.
 6  
 
 7  
     This library is free software; you can redistribute it and/or modify it
 8  
     under the terms of the GNU Lesser General Public License as published
 9  
     by the Free Software Foundation; either version 3 of the License, or (at
 10  
     your option) any later version.
 11  
 
 12  
     This library is distributed in the hope that it will be useful, but WITHOUT
 13  
     ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
 14  
     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 15  
     License for more details.
 16  
 
 17  
     You should have received a copy of the GNU Lesser General Public License
 18  
     along with this library;  if not, write to the Free Software Foundation,
 19  
     Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
 20  
 
 21  
     > http://www.fsf.org/licensing/licenses/lgpl.html
 22  
     > http://www.opensource.org/licenses/lgpl-license.php
 23  
 
 24  
 */
 25  
 package org.dishevelled.timer;
 26  
 
 27  
 import java.util.Map;
 28  
 import java.util.List;
 29  
 import java.util.ArrayList;
 30  
 import java.util.Random;
 31  
 import java.util.HashMap;
 32  
 import java.util.Collections;
 33  
 
 34  
 import org.apache.commons.math.stat.descriptive.SummaryStatistics;
 35  
 
 36  
 /**
 37  
  * Timer class with nanosecond resolution and summary
 38  
  * statistics on recorded elapsed times.  This class provides
 39  
  * nanosecond precision but not necessarily nanosecond accuracy
 40  
  * (see the javadoc for <code>System.nanoTime()</code> for more
 41  
  * details).  The recorded times themselves are not preserved,
 42  
  * however, only the statistics.  As a consequence <code>start()</code>
 43  
  * and <code>stop()</code> can be called many number of times
 44  
  * without requiring large amounts of memory.
 45  
  *
 46  
  * <h4>Special cases</h4>
 47  
  * <p>When <code>size() == 0</code>,
 48  
  * <pre>
 49  
  * min() == Double.NaN
 50  
  * max() == Double.NaN
 51  
  * mean() == Double.NaN
 52  
  * standardDeviation() == Double.NaN
 53  
  * </pre>
 54  
  * </p>
 55  
  * <p>When <code>size() == 1</code>,
 56  
  * <pre>
 57  
  * standardDeviation() == 0.0d
 58  
  * </pre>
 59  
  * </p>
 60  
  *
 61  
  * <h4>Static methods</h4>
 62  
  * <p>Execution time can be sensitive to various factors, such
 63  
  * as order of execution, runtime optimization from the just-in-time compiler
 64  
  * (JIT), and garbage collection.  This class provides static methods
 65  
  * to help deal with these factors.</p>
 66  
  *
 67  
  * <p>Given a few benchmarks to run, wrap them in Runnable objects
 68  
  * <pre>
 69  
  * Runnable r0 = new Runnable() { public void run() { ... } };
 70  
  * Runnable r1 = new Runnable() { public void run() { ... } };
 71  
  * Runnable r2 = new Runnable() { public void run() { ... } };
 72  
  * List&lt;Runnable&gt; benchmarks = Arrays.asList(new Runnable[] { r0, r1, r2 });
 73  
  * </pre>
 74  
  * Prime the JIT by running the benchmarks several times
 75  
  * <pre>
 76  
  * Timer.prime(benchmarks, 1000);
 77  
  * </pre>
 78  
  * Then measure the execution times of the benchmarks by running
 79  
  * them several times in random execution order
 80  
  * <pre>
 81  
  * Map&lt;Runnable, Timer&gt; result = Timer.shuffle(benchmarks, 100, 100);
 82  
  * </pre>
 83  
  * Summary statistics on recorded execution times are captured by the
 84  
  * timer returned for each Runnable benchmark
 85  
  * <pre>
 86  
  * for (Map.Entry&lt;Runnable, Timer&gt; e : result.entrySet()) {
 87  
  *   Runnable r = e.getKey();
 88  
  *   Timer t = e.getValue();
 89  
  *   System.out.println("runnable=" + r + " mean execution time=" + t.mean() + "ns");
 90  
  * }
 91  
  * </pre></p>
 92  
  *
 93  
  * @see java.lang.System#nanoTime
 94  
  * @author  Michael Heuer
 95  
  */
 96  
 public final class Timer
 97  
 {
 98  
     /** Summary statistics. */
 99  
     private final SummaryStatistics summaryStatistics;
 100  
 
 101  
     /** Last start time, in nanoseconds. */
 102  
     private double startTime;
 103  
 
 104  
     /** Flag indicating this timer has been started at least once. */
 105  
     private boolean started;
 106  
 
 107  
 
 108  
     /**
 109  
      * Create a new timer.
 110  
      */
 111  
     public Timer()
 112  52
     {
 113  52
         summaryStatistics = new SummaryStatistics();
 114  52
         started = false;
 115  52
     }
 116  
 
 117  
 
 118  
     /**
 119  
      * Reset the record of elapsed times from this timer.  After
 120  
      * the timer has been reset, it must be started at least once
 121  
      * before <code>stop()</code> is called.
 122  
      */
 123  
     public void reset()
 124  
     {
 125  5
         summaryStatistics.clear();
 126  5
         started = false;
 127  5
     }
 128  
 
 129  
     /**
 130  
      * Start the timer.  The timer must be started at least once
 131  
      * before <code>stop()</code> is called.
 132  
      */
 133  
     public void start()
 134  
     {
 135  1348
         started = true;
 136  1348
         startTime = System.nanoTime();
 137  1348
     }
 138  
 
 139  
     /**
 140  
      * Stop the timer and record the time elapsed in nanoseconds
 141  
      * since <code>start()</code> was last called.
 142  
      *
 143  
      * @throws TimerException if <code>start()</code> has not been called
 144  
      *    at least once before this method was called
 145  
      */
 146  
     public void stop()
 147  
     {
 148  1355
         if (started)
 149  
         {
 150  1353
             double currentTime = System.nanoTime();
 151  1353
             double elapsedTime = currentTime - startTime;
 152  1353
             summaryStatistics.addValue(elapsedTime);
 153  1353
         }
 154  
         else
 155  
         {
 156  2
             throw new TimerException("timer was never started");
 157  
         }
 158  1353
     }
 159  
 
 160  
     /**
 161  
      * Return the minimum elapsed time recorded by this timer
 162  
      * in nanoseconds.
 163  
      *
 164  
      * @return the minimum elapsed time recorded by this timer
 165  
      *    in nanoseconds
 166  
      */
 167  
     public double min()
 168  
     {
 169  39
         return summaryStatistics.getMin();
 170  
     }
 171  
 
 172  
     /**
 173  
      * Return the maximum elapsed time recorded by this timer
 174  
      * in nanoseconds.
 175  
      *
 176  
      * @return the maximum elapsed time recorded by this timer
 177  
      *    in nanoseconds
 178  
      */
 179  
     public double max()
 180  
     {
 181  39
         return summaryStatistics.getMax();
 182  
     }
 183  
 
 184  
     /**
 185  
      * Return the number of elapsed times recorded by this timer.
 186  
      *
 187  
      * @return the number of elapsed times recorded by this timer
 188  
      */
 189  
     public long size()
 190  
     {
 191  45
         return summaryStatistics.getN();
 192  
     }
 193  
 
 194  
     /**
 195  
      * Return the sum of the elapsed times recorded by this timer
 196  
      * in nanoseconds.
 197  
      *
 198  
      * @return the sum of the elapsed times recorded by this timer
 199  
      */
 200  
     public double sum()
 201  
     {
 202  39
         return summaryStatistics.getSum();
 203  
     }
 204  
 
 205  
     /**
 206  
      * Return the arithmetic mean of the elapsed times recorded by this
 207  
      * timer in nanoseconds.
 208  
      *
 209  
      * @return the arithmetic mean of the elapsed times recorded by this
 210  
      *    timer in nanoseconds
 211  
      */
 212  
     public double mean()
 213  
     {
 214  39
         return summaryStatistics.getMean();
 215  
     }
 216  
 
 217  
     /**
 218  
      * Return the standard deviation of the elapsed times recorded by this
 219  
      * timer in nanoseconds.
 220  
      *
 221  
      * @return the standard deviation of the elapsed times recorded by this
 222  
      *    timer in nanoseconds
 223  
      */
 224  
     public double standardDeviation()
 225  
     {
 226  39
         return summaryStatistics.getStandardDeviation();
 227  
     }
 228  
 
 229  
 
 230  
     /**
 231  
      * Time the specified code block.
 232  
      *
 233  
      * @param codeBlock code block to execute
 234  
      * @return timer used to measure execution time
 235  
      */
 236  
     public static Timer time(final Runnable codeBlock)
 237  
     {
 238  3
         return time(codeBlock, new Timer());
 239  
     }
 240  
 
 241  
     /**
 242  
      * Time the specified code block with the specified timer.
 243  
      *
 244  
      * @param codeBlock code block to execute
 245  
      * @param t timer to use to measure execution time
 246  
      * @return timer used to measure execution time
 247  
      */
 248  
     public static Timer time(final Runnable codeBlock, final Timer t)
 249  
     {
 250  1338
         t.start();
 251  1338
         codeBlock.run();
 252  1338
         t.stop();
 253  1338
         return t;
 254  
     }
 255  
 
 256  
     /**
 257  
      * Prime the just-in-time compiler (JIT) by executing the
 258  
      * specified code block <code>n</code> times.
 259  
      *
 260  
      * @param codeBlock code block to execute
 261  
      * @param n number of times to execute code block
 262  
      */
 263  
     public static void prime(final Runnable codeBlock, final int n)
 264  
     {
 265  1451
         for (int i = 0; i < n; i++)
 266  
         {
 267  1441
             codeBlock.run();
 268  
         }
 269  10
     }
 270  
 
 271  
     /**
 272  
      * Prime the just-in-time compiler (JIT) by executing each
 273  
      * code block in the specified list of code blocks <code>n</code> times.
 274  
      *
 275  
      * @param codeBlocks list of code blocks to execute
 276  
      * @param n number of times to execute each code block
 277  
      */
 278  
     public static void prime(final List<? extends Runnable> codeBlocks, final int n)
 279  
     {
 280  3
         for (Runnable codeBlock : codeBlocks)
 281  
         {
 282  7
             prime(codeBlock, n);
 283  7
         }
 284  3
     }
 285  
 
 286  
     /**
 287  
      * Loop over the specified code block <code>n</code> times.
 288  
      *
 289  
      * @param codeBlock code block to execute
 290  
      * @param n number of times to execute code block
 291  
      * @return timer used to measure execution time
 292  
      */
 293  
     public static Timer loop(final Runnable codeBlock, final int n)
 294  
     {
 295  45
         return loop(codeBlock, n, new Timer());
 296  
     }
 297  
 
 298  
     /**
 299  
      * Loop over the specified code block <code>n</code> times
 300  
      * with the specified timer.
 301  
      *
 302  
      * @param codeBlock code block to execute
 303  
      * @param n number of times to execute code block
 304  
      * @param t timer to use to measure execution time
 305  
      * @return timer used to measure execution time
 306  
      */
 307  
     public static Timer loop(final Runnable codeBlock, final int n, final Timer t)
 308  
     {
 309  1392
         for (int i = 0; i < n; i++)
 310  
         {
 311  1332
             time(codeBlock, t);
 312  
         }
 313  60
         return t;
 314  
     }
 315  
 
 316  
     /**
 317  
      * For each of the code blocks in the specified list of code blocks,
 318  
      * loop over the code block <code>n</code> times.
 319  
      *
 320  
      * @param codeBlocks list of code blocks to execute
 321  
      * @param n number of times to execute each code block
 322  
      * @return map of code blocks to timers used to measure execution time
 323  
      */
 324  
     public static Map<Runnable, Timer> loop(final List<? extends Runnable> codeBlocks, final int n)
 325  
     {
 326  15
         Map<Runnable, Timer> map = new HashMap<Runnable, Timer>(codeBlocks.size());
 327  15
         for (Runnable codeBlock : codeBlocks)
 328  
         {
 329  27
             map.put(codeBlock, loop(codeBlock, n));
 330  27
         }
 331  15
         return Collections.unmodifiableMap(map);
 332  
     }
 333  
 
 334  
     /**
 335  
      * Loop over the code blocks in the specified list of code blocks
 336  
      * <code>n</code> times, executing each code block <code>m</code> times.
 337  
      *
 338  
      * @param codeBlocks list of code blocks to execute
 339  
      * @param n number of times to loop over the list of code blocks
 340  
      * @param m number of times to execute each code block
 341  
      * @return map of code blocks to timers used to measure execution time
 342  
      */
 343  
     public static Map<Runnable, Timer> loop(final List<? extends Runnable> codeBlocks, final int n, final int m)
 344  
     {
 345  2
         Map<Runnable, Timer> map = new HashMap<Runnable, Timer>(codeBlocks.size());
 346  5
         for (int i = 0; i < n; i++)
 347  
         {
 348  3
             for (Runnable codeBlock : codeBlocks)
 349  
             {
 350  7
                 if (map.containsKey(codeBlock))
 351  
                 {
 352  3
                     Timer t = map.get(codeBlock);
 353  3
                     loop(codeBlock, m, t);
 354  3
                     map.put(codeBlock, t);
 355  3
                 }
 356  
                 else
 357  
                 {
 358  4
                     map.put(codeBlock, loop(codeBlock, m));
 359  
                 }
 360  7
             }
 361  
         }
 362  2
         return Collections.unmodifiableMap(map);
 363  
     }
 364  
 
 365  
     /**
 366  
      * For each of the code blocks in the specified list of code blocks,
 367  
      * executed in random order, loop over the code block <code>n</code> times.
 368  
      *
 369  
      * @param codeBlocks list of code blocks to execute
 370  
      * @param n number of times to execute each code block
 371  
      * @return map of code blocks to timers used to measure execution time
 372  
      */
 373  
     public static Map<Runnable, Timer> shuffle(final List<? extends Runnable> codeBlocks, final int n)
 374  
     {
 375  4
         return shuffle(codeBlocks, n, new Random());
 376  
     }
 377  
 
 378  
     /**
 379  
      * For each of the code blocks in the specified list of code blocks,
 380  
      * executed in random order using the specified source of randomness,
 381  
      * loop over the code block <code>n</code> times.
 382  
      *
 383  
      * @param codeBlocks list of code blocks to execute
 384  
      * @param n number of times to execute each code block
 385  
      * @param random source of randomness
 386  
      * @return map of code blocks to timers used to measure execution time
 387  
      */
 388  
     public static Map<Runnable, Timer> shuffle(final List<? extends Runnable> codeBlocks, final int n, final Random random)
 389  
     {
 390  7
         List<Runnable> codeBlocksCopy = new ArrayList<Runnable>(codeBlocks);
 391  7
         Collections.shuffle(codeBlocksCopy, random);
 392  7
         return loop(codeBlocksCopy, n);
 393  
     }
 394  
 
 395  
     /**
 396  
      * Loop over the code blocks in the specified list of code blocks
 397  
      * <code>n</code> times, in random order, executing each code block
 398  
      * <code>m</code> times.
 399  
      *
 400  
      * @param codeBlocks list of code blocks to execute
 401  
      * @param n number of times to loop over the list of code blocks
 402  
      * @param m number of times to execute each code block
 403  
      * @return map of code blocks to timers used to measure execution time
 404  
      */
 405  
     public static Map<Runnable, Timer> shuffle(final List<? extends Runnable> codeBlocks, final int n, final int m)
 406  
     {
 407  3
         return shuffle(codeBlocks, n, m, new Random());
 408  
     }
 409  
 
 410  
     /**
 411  
      * Loop over the code blocks in the specified list of code blocks
 412  
      * <code>n</code> times, in random order using the specified source of
 413  
      * randomness, executing each code block <code>m</code> times.
 414  
      *
 415  
      * @param codeBlocks list of code blocks to execute
 416  
      * @param n number of times to loop over the list of code blocks
 417  
      * @param m number of times to execute each code block
 418  
      * @param random source of randomness
 419  
      * @return map of code blocks to timers used to measure execution time
 420  
      */
 421  
     public static Map<Runnable, Timer> shuffle(final List<? extends Runnable> codeBlocks,
 422  
                                                final int n,
 423  
                                                final int m,
 424  
                                                final Random random)
 425  
     {
 426  5
         List<Runnable> codeBlocksCopy = new ArrayList<Runnable>(codeBlocks);
 427  5
         Map<Runnable, Timer> map = new HashMap<Runnable, Timer>(codeBlocksCopy.size());
 428  13
         for (int i = 0; i < n; i++)
 429  
         {
 430  8
             Collections.shuffle(codeBlocksCopy, random);
 431  8
             for (Runnable codeBlock : codeBlocksCopy)
 432  
             {
 433  20
                 if (map.containsKey(codeBlock))
 434  
                 {
 435  9
                     Timer t = map.get(codeBlock);
 436  9
                     loop(codeBlock, m, t);
 437  9
                     map.put(codeBlock, t);
 438  9
                 }
 439  
                 else
 440  
                 {
 441  11
                     map.put(codeBlock, loop(codeBlock, m));
 442  
                 }
 443  20
             }
 444  
         }
 445  5
         return Collections.unmodifiableMap(map);
 446  
     }
 447  
 }