/**
* Copyright 2008 - 2009
*
* Licensed 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.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.1
*/
package org.ripple.power.timer;
public class NanoTimer extends SystemTimer {
private static final int NUM_TIMERS = 8;
private static final long ONE_SEC = 1000000000L;
private static final long MAX_DIFF = ONE_SEC;
private static final long NEVER_USED = -1;
private static final long DEFAULT_FAIL_RESET_TIME = ONE_SEC;
private long[] lastTimeStamps = new long[NUM_TIMERS];
private long[] timeSinceLastUsed = new long[NUM_TIMERS];
private long virtualNanoTime;
private int timesInARowNewTimerChosen;
private long lastDiff;
private long failTime;
private long failResetTime;
public NanoTimer() {
virtualNanoTime = 0;
failResetTime = DEFAULT_FAIL_RESET_TIME;
reset();
}
private void reset() {
failTime = 0;
lastDiff = 0;
timesInARowNewTimerChosen = 0;
for (int i = 0; i < NUM_TIMERS; i++) {
timeSinceLastUsed[i] = NEVER_USED;
}
}
private long nanoTime() {
long diff;
if (timesInARowNewTimerChosen >= NUM_TIMERS) {
long nanoTime = System.currentTimeMillis() * 1000000;
diff = nanoTime - lastTimeStamps[0];
failTime += diff;
if (failTime >= failResetTime) {
reset();
failResetTime *= 2;
}
} else {
long nanoTime = System.nanoTime();
int bestTimer = -1;
long bestDiff = 0;
for (int i = 0; i < NUM_TIMERS; i++) {
if (timeSinceLastUsed[i] != NEVER_USED) {
long t = lastTimeStamps[i] + timeSinceLastUsed[i];
long timerDiff = nanoTime - t;
if (timerDiff > 0 && timerDiff < MAX_DIFF) {
if (bestTimer == -1 || timerDiff < bestDiff) {
bestTimer = i;
bestDiff = timerDiff;
}
}
}
}
if (bestTimer == -1) {
diff = lastDiff;
bestTimer = 0;
for (int i = 0; i < NUM_TIMERS; i++) {
if (timeSinceLastUsed[i] == NEVER_USED) {
bestTimer = i;
break;
} else if (timeSinceLastUsed[i] > timeSinceLastUsed[bestTimer]) {
bestTimer = i;
}
}
timesInARowNewTimerChosen++;
} else {
timesInARowNewTimerChosen = 0;
failResetTime = DEFAULT_FAIL_RESET_TIME;
diff = nanoTime - lastTimeStamps[bestTimer]
- timeSinceLastUsed[bestTimer];
if (timeSinceLastUsed[bestTimer] == 0) {
lastDiff = diff;
}
}
lastTimeStamps[bestTimer] = nanoTime;
timeSinceLastUsed[bestTimer] = 0;
for (int i = 0; i < NUM_TIMERS; i++) {
if (i != bestTimer && timeSinceLastUsed[i] != NEVER_USED) {
timeSinceLastUsed[i] += diff;
}
}
if (timesInARowNewTimerChosen >= NUM_TIMERS) {
lastTimeStamps[0] = System.currentTimeMillis() * 1000000;
}
}
virtualNanoTime += diff;
return virtualNanoTime;
}
public long getTimeMillis() {
return nanoTime() / 1000000;
}
public long getTimeMicros() {
return nanoTime() / 1000;
}
}