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 }