org.elasticsearch.search.profile.Timer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search.profile;
/** Helps measure how much time is spent running some methods.
* The {@link #start()} and {@link #stop()} methods should typically be called
* in a try/finally clause with {@link #start()} being called right before the
* try block and {@link #stop()} being called at the beginning of the finally
* block:
*
* timer.start();
* try {
* // code to time
* } finally {
* timer.stop();
* }
*
*/
public class Timer {
private boolean doTiming;
private long timing, count, lastCount, start;
/** pkg-private for testing */
long nanoTime() {
return System.nanoTime();
}
/** Start the timer. */
public final void start() {
assert start == 0 : "#start call misses a matching #stop call";
// We measure the timing of each method call for the first 256
// calls, then 1/2 call up to 512 then 1/3 up to 768, etc. with
// a maximum interval of 1024, which is reached for 1024*2^8 ~= 262000
// This allows to not slow down things too much because of calls
// to System.nanoTime() when methods are called millions of time
// in tight loops, while still providing useful timings for methods
// that are only called a couple times per search execution.
doTiming = (count - lastCount) >= Math.min(lastCount >>> 8, 1024);
if (doTiming) {
start = nanoTime();
}
count++;
}
/** Stop the timer. */
public final void stop() {
if (doTiming) {
timing += (count - lastCount) * Math.max(nanoTime() - start, 1L);
lastCount = count;
start = 0;
}
}
/** Return the number of times that {@link #start()} has been called. */
public final long getCount() {
if (start != 0) {
throw new IllegalStateException("#start call misses a matching #stop call");
}
return count;
}
/** Return an approximation of the total time spent between consecutive calls of #start and #stop. */
public final long getApproximateTiming() {
if (start != 0) {
throw new IllegalStateException("#start call misses a matching #stop call");
}
// We don't have timings for the last `count-lastCount` method calls
// so we assume that they had the same timing as the lastCount first
// calls. This approximation is ok since at most 1/256th of method
// calls have not been timed.
long timing = this.timing;
if (count > lastCount) {
assert lastCount > 0;
timing += (count - lastCount) * timing / lastCount;
}
return timing;
}
}