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 }