ere goes the measured code stopwatch.stop(); System.out.println("Result: " + stopwatch); // not really necessary This can be used for simple micro-benchmarking, critical section monitoring, in web filter to measure request times, etc. All these cases ensures that start and stop occurs in the same thread. ThreadLocal is used under the hood for start/stop methods without parameters.
Notice that it is possible to use {@code start} method directly after {@code getStopwatch(...)} because itreturns this. {@link org.javasimon.SimonManager} should always be used to get the stopwatch before using it,because otherwise the code will not reflect enable/disable of the whole API. Method {@code stop}should always be used on the obtained stopwatch instance.
Stopwatch with arbitrary keys
Default thread-local behavior is not sufficient in some cases:
- There is a need to measure multiple splits in a single thread at the moment.
- Start and stop might be called in different threads.
In both cases a particular object is often available that one split measurement can be bound to. Following example shows how to sum up life-spans of all SQL statements. In some cases there are more statements open at the same moment. In that case the particular statement can be used as the split-key. Example code (sorry for no exception handling and SQL injecting):
Stopwatch stopwatch = SimonManager.getStopwatch("all-stmts"); Statement stmt = c.createStatement(); stopwatch.start(stmt); rs = stmt.executeQuery("select * from foo"); while (rs.next()) { Statement stmt2 = c.createStatement(); stopwatch.start(stmt2); stmt2.execute("delete from bar where foo_id=" + rs.getInt("id")); stopwatch.stop(stmt2); stmt2.close(); } stopwatch.stop(stmt); stmt.close();
This is not quite a real-life example, but it should demonstrate the point. Better example is measuring HTTP session life-spans. Session is typically started and ended in different requests - those are processed in random threads. Hence session itself should be used as the split-key. Keyed start/stop is always safe if one split is measured for the object used as the key at a time (which is mostly exactly what is needed). This method can be used anytime even for single-threaded environment if lifespan of a particular object is measured as the key nicely indicate directly in the code what is measured.
Using {@code this} as a key is not always safe as it might seem. While sometimes it is exactlywhat is needed it should not be used if {@code this} is not related to the time split. Ifmethod execution time is measured default start/stop should be used. When the method is later moved into different helper class and it is called from multiple threads it is still valid, while using {code this} would cause troubles. On the other hand, keyed methods are preferred if there is a clear relation between the key object and the split - best case is measuring life-span of the object.
Disable/enable considerations
While Counter's usage is atomic, Stopwatch measures splits and every measurement involves two calls (start/stop) over a period of time. It's important to know how various management actions affect measurement:
- If start OR stop is called on disabled Simon, nothing is measured. That means that if stopwatch is disabled or enabled between these calls, stop always returns 0 and totals are not updated.
- If stopwatch is obtained from enabled Manager (API is enabled) and Manager is later disabled before stop, this split is measured because real stopwatch instance was obtained. If it's other way around then the split is not measured because obtained instance is "null" Simon.
- If Simon instance is obtained again from the Manager in order to call stop method the result is not guaranteed. It is deterministic though, but this is not considered official use case and might change in the future. (For example: One call {@code start} on the real stopwatch, then{@code stop} on the NullSimon because the instance was obtained from disabled API, then again{@code start} on disabled API and finally - after the API is enabled again - the last {@code stop}might pair up with the first start - which would "measure" unrealistic long split. Simply - don't do this. ;-))
While API disable causes that the code works with "null" Simons, state of the real Simon is perfectly preserved. Disabling particular Simon on the other hand resets some of its state. When the stopwatch is disabled, its active count is set to 0 and before it is enabled again both its thread-local split map and keyed-object split map is cleared. Of course, all totals/counts are preserved.
Other usages
Reset of the stopwatch resets all stats except usages that are rather management related and should not be reset. Reset is used often for various sampling purposes which requires that only cumulative stats are reset, but all running splits are preserved. Running splits will be added to the stopwatch after reset when respective stop methods are called.
@author
Richard "Virgo" Richter
@created Aug 4, 2008