001 /*
002 Galois, a framework to exploit amorphous data-parallelism in irregular
003 programs.
004
005 Copyright (C) 2010, The University of Texas at Austin. All rights reserved.
006 UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS SOFTWARE
007 AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR ANY
008 PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF PERFORMANCE, AND ANY
009 WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF DEALING OR USAGE OF TRADE.
010 NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH RESPECT TO THE USE OF THE
011 SOFTWARE OR DOCUMENTATION. Under no circumstances shall University be liable
012 for incidental, special, indirect, direct or consequential damages or loss of
013 profits, interruption of business, or related expenses which may arise from use
014 of Software or Documentation, including but not limited to those resulting from
015 defects in Software and/or Documentation, or loss or inaccuracy of data of any
016 kind.
017
018 File: ThreadTimer.java
019
020 */
021
022
023
024 package util;
025
026 import java.lang.management.GarbageCollectorMXBean;
027 import java.lang.management.ManagementFactory;
028 import java.util.List;
029
030 /**
031 * Class that allows per-thread timing that excludes GC time. This class is
032 * thread safe.
033 *
034 * The class is used by instantiating a new object at each "tick" The time
035 * between two ticks (exclusive of GC time) can then be calculated using the
036 * static method elapsedTime().
037 *
038 * Note that this class requires the use of a stop-the-world collector (as it
039 * assumes that no mutator activity occurs while the GC is running)
040 *
041 */
042 public final class ThreadTimer {
043 private final static List<GarbageCollectorMXBean> garbageCollectorMXBeans;
044
045 static {
046 garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
047 }
048
049 /**
050 * Creates a new tick, fixing the start time of the current event
051 *
052 * @return a tick object
053 */
054 public static Tick tick() {
055 return new Tick();
056 }
057
058 /**
059 * A moment in time
060 */
061 public static class Tick {
062 private long sysTime;
063 private long gcTime;
064
065 private Tick() {
066 /*
067 * Here is the problem: we want to make sure that we mark the system
068 * time and the gc time consistently. However, between recording the
069 * system time and recording the GC time, a garbage collection might
070 * occur, which would make the numbers inconsistent with each other.
071 *
072 * What we will do is record the number of GCs executed, then record
073 * the system time and GC time, then re-check the number of GCs
074 * executed. If the two numbers agree, then we have recorded
075 * consistent times. Otherwise, we must re-do the measurement.
076 */
077 long gcCountBegin, gcCountEnd;
078 do {
079 gcCountBegin = numGCs();
080 sysTime = milliTime(); // don't want a GC between this line
081 gcTime = milliGcTime(); // and this one
082 gcCountEnd = numGCs();
083 } while (gcCountBegin != gcCountEnd);
084 }
085
086 /**
087 * Returns the elapsed time between the two Ticks. The returned value does
088 * not include any time spent by the JVM in garbage collection.
089 *
090 * @param withoutGc true if garbage collection time should not be included in result
091 * @param end the tick marking the end time
092 * @return elapsed time in milliseconds.
093 */
094 public long elapsedTime(boolean withoutGc, Tick end) {
095 return (end.sysTime - sysTime) - (withoutGc ? (end.gcTime - gcTime) : 0);
096 }
097
098 private long milliTime() {
099 return System.nanoTime() / 1000000;
100 }
101
102 private long milliGcTime() {
103 long result = 0;
104 for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeans) {
105 // the collection time is already in milliseconds,
106 result += Math.max(0, garbageCollectorMXBean.getCollectionTime());
107 }
108 return result;
109 }
110
111 private long numGCs() {
112 long result = 0;
113 for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeans) {
114 result += garbageCollectorMXBean.getCollectionCount();
115 }
116 return result;
117 }
118 }
119 }