001 /*--------------------------------------------------------------------------+ 002 $Id: PerformanceMonitor.java 26283 2010-02-18 11:18:57Z juergens $ 003 | | 004 | Copyright 2005-2010 Technische Universitaet Muenchen | 005 | | 006 | Licensed under the Apache License, Version 2.0 (the "License"); | 007 | you may not use this file except in compliance with the License. | 008 | You may obtain a copy of the License at | 009 | | 010 | http://www.apache.org/licenses/LICENSE-2.0 | 011 | | 012 | Unless required by applicable law or agreed to in writing, software | 013 | distributed under the License is distributed on an "AS IS" BASIS, | 014 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 015 | See the License for the specific language governing permissions and | 016 | limitations under the License. | 017 +--------------------------------------------------------------------------*/ 018 package edu.tum.cs.commons.system; 019 020 /** 021 * Combines a timer and a memory monitor in a simple utility class. Measures 022 * both total memory and the delta between {@link PerformanceMonitor#start()} 023 * and {@link PerformanceMonitor#stop()}. 024 * <p> 025 * In order to avoid programming mistakes, the calls to the methods 026 * {@link PerformanceMonitor#start()} and {@link PerformanceMonitor#stop()} must 027 * adhere to a simple protocol:<br> 028 * The {@link PerformanceMonitor} can be in on of the three states NOT_RUN, 029 * RUNNING, FINISHED. 030 * <p> 031 * {@link PerformanceMonitor#start()} May only be called in state NOT_RUN and 032 * {@link PerformanceMonitor#stop()} may only be called in state RUNNING. 033 * <p> 034 * All other calls to {@link PerformanceMonitor#start()} and 035 * {@link PerformanceMonitor#stop()} result in {@link IllegalArgumentException}s 036 * 037 * @author Elmar Juergens 038 * @author $Author: juergens $ 039 * 040 * @version $Revision: 26283 $ 041 * @levd.rating GREEN Hash: 11F99E9698215A2906756FE003D9D30A 042 */ 043 public class PerformanceMonitor { 044 045 /** The state the {@link PerformanceMonitor} is currently in */ 046 private EPerformanceMonitorState state = EPerformanceMonitorState.NOT_RUN; 047 048 /** 049 * Timestamp the call to the {@link PerformanceMonitor#start()} method 050 * occurred 051 */ 052 private long startTimeInMillis; 053 054 /** 055 * Timestamp the call to the {@link PerformanceMonitor#stop()} method 056 * occurred 057 */ 058 private long stopTimeInMillis; 059 060 /** {@link MemoryMonitor} used to measure total memory consumption */ 061 private MemoryMonitor memMonitor; 062 063 /** 064 * Flag that determines whether a memory monitor (that uses its own thread) 065 * should be used to get a more exact measurement of maximum memory 066 * consumption. 067 */ 068 private final boolean useMemoryMonitor; 069 070 /** 071 * Memory consumption when the call to {@link PerformanceMonitor#start()} 072 * occurred. 073 */ 074 private long startMemoryInBytes; 075 076 /** 077 * Memory consumption when the call to {@link PerformanceMonitor#stop()} 078 * occurred. 079 */ 080 private long stopMemoryInBytes; 081 082 /** 083 * Convenience factory method: Creates a new {@link PerformanceMonitor} and 084 * starts it. 085 * 086 * @param useMemoryMonitor 087 * detemines whether the PerformanceMonitor internally uses a 088 * {@link MemoryMonitor} to measure memory consumption. This 089 * requires more resources, since the {@link MemoryMonitor} runs 090 * its own thread, but promises more precise measurement of 091 * maximum memory consumption. 092 */ 093 public static PerformanceMonitor create(boolean useMemoryMonitor) { 094 PerformanceMonitor monitor = new PerformanceMonitor(useMemoryMonitor); 095 monitor.start(); 096 return monitor; 097 } 098 099 /** 100 * Convenience factory method: Creates a new {@link PerformanceMonitor} and 101 * starts it. PerformanceMonitor does not use a MemoryMonitor internally 102 */ 103 public static PerformanceMonitor create() { 104 return create(false); 105 } 106 107 /** 108 * Constructor has package level to allow tests to access it, yet enforce 109 * use of factory methods for public use. 110 */ 111 /* package */PerformanceMonitor(boolean useMemoryMonitor) { 112 this.useMemoryMonitor = useMemoryMonitor; 113 } 114 115 /** 116 * Starts the {@link PerformanceMonitor}. It will measure time and maximal 117 * memory consumption until the method {@link PerformanceMonitor#stop()} is 118 * called. 119 * <p> 120 * This method may only be called, if the {@link PerformanceMonitor} is in 121 * state NOT_RUN. (i.e., after it has been created). 122 * <p> 123 * All subsequent calls to this method will result in a 124 * {@link IllegalStateException} 125 */ 126 public void start() { 127 if (state != EPerformanceMonitorState.NOT_RUN) { 128 throw new IllegalStateException( 129 "PerformanceMonitor is already running and cannot be restarted"); 130 } 131 132 state = EPerformanceMonitorState.RUNNING; 133 if (useMemoryMonitor) { 134 memMonitor = new MemoryMonitor(); 135 memMonitor.start(); 136 } 137 startMemoryInBytes = Runtime.getRuntime().totalMemory(); 138 startTimeInMillis = System.currentTimeMillis(); 139 } 140 141 /** 142 * Stops the {@link PerformanceMonitor}. 143 * <p> 144 * This method may only be called, if the {@link PerformanceMonitor} is in 145 * state RUNNING. (i.e., after a call to {@link PerformanceMonitor#start()}). 146 * <p> 147 * If the {@link PerformanceMonitor} is in any other state, a call to this 148 * method results in an {@link IllegalStateException} 149 */ 150 public void stop() { 151 if (state != EPerformanceMonitorState.RUNNING) { 152 throw new IllegalStateException( 153 "PerformanceMonitor can only be stopped if it is running"); 154 } 155 156 stopTimeInMillis = System.currentTimeMillis(); 157 if (useMemoryMonitor) { 158 memMonitor.stop(); 159 } 160 stopMemoryInBytes = Runtime.getRuntime().totalMemory(); 161 state = EPerformanceMonitorState.FINISHED; 162 } 163 164 /** Gets the measured time in seconds. (Fractions of seconds are discarded) */ 165 public long getSeconds() { 166 return getMilliseconds() / 1000; 167 } 168 169 /** Gets the measured time in milliseconds */ 170 public long getMilliseconds() { 171 return stopTimeInMillis - startTimeInMillis; 172 } 173 174 /** Gets the maximal memory consumption in bytes */ 175 public long getMaxMemUsageInBytes() { 176 if (useMemoryMonitor) { 177 return memMonitor.getMaximumMemoryUsage(); 178 } 179 return Math.max(stopMemoryInBytes, startMemoryInBytes); 180 } 181 182 /** Gets the maximal memory consumption in kilobytes */ 183 public long getMaxMemUsageInKBs() { 184 return getMaxMemUsageInBytes() / 1024; 185 } 186 187 /** Gets the delta in memory consumption in bytes */ 188 public long getDeltaMemUsageInBytes() { 189 return getMaxMemUsageInBytes() - startMemoryInBytes; 190 } 191 192 /** Gets the delta in memory consumption in kilobytes */ 193 public long getDeltaMemUsageInKBs() { 194 return getDeltaMemUsageInBytes() / 1024; 195 } 196 197 }