/*
* Copyright 2014 NAVER Corp.
*
* 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.
*/
package com.navercorp.pinpoint.web.util;
import com.navercorp.pinpoint.common.util.MathUtils;
import com.navercorp.pinpoint.web.vo.Range;
/**
* @author hyungil.jeong
*/
public class TimeWindowSlotCentricSampler implements TimeWindowSampler {
private static final long ONE_SECOND = 1000L;
static final long DEFAULT_MINIMUM_TIMESLOT = 5 * ONE_SECOND;
static final long DEFAULT_IDEAL_NUM_TIMESLOTS = 200;
private final long minTimeslot;
private final long idealNumTimeslots;
public TimeWindowSlotCentricSampler() {
this.minTimeslot = DEFAULT_MINIMUM_TIMESLOT;
this.idealNumTimeslots = DEFAULT_IDEAL_NUM_TIMESLOTS;
}
public TimeWindowSlotCentricSampler(long minTimeslot, long idealNumTimeslots) {
this.minTimeslot = minTimeslot;
this.idealNumTimeslots = idealNumTimeslots;
}
/**
* <p>This implementation returns the window size that would generate the number of timeslots closest to
* <tt>idealNumTimeslots</tt> for a given <tt>range</tt>.
* <p>Additionally, the window size is generated in multiples of
* <tt>minTimeslot</tt>.
*
* @param range range to calculate the time window over
* @return size of the ideal time window
*/
@Override
public long getWindowSize(Range range) {
final long periodMs = range.getRange();
final long idealTimeslotSize = periodMs / this.idealNumTimeslots;
if (idealTimeslotSize < this.minTimeslot) {
return this.minTimeslot;
}
if (idealTimeslotSize % this.minTimeslot == 0) {
return idealTimeslotSize;
} else {
final long nearestMultipleOfMinTimeslotSize = MathUtils.roundToNearestMultipleOf(idealTimeslotSize, this.minTimeslot);
return findOptimalWindowSize(periodMs, nearestMultipleOfMinTimeslotSize);
}
}
private long findOptimalWindowSize(long periodMs, long nearestMultipleOfMinTimeslotSize) {
final double idealTimeslotSize = (double)periodMs / this.idealNumTimeslots;
final long timeslotSizeToCompare = nearestMultipleOfMinTimeslotSize < idealTimeslotSize ?
nearestMultipleOfMinTimeslotSize + this.minTimeslot : nearestMultipleOfMinTimeslotSize - this.minTimeslot;
if (Math.abs(nearestMultipleOfMinTimeslotSize - idealTimeslotSize) / ((double)nearestMultipleOfMinTimeslotSize / this.minTimeslot) <
Math.abs(timeslotSizeToCompare - idealTimeslotSize) / ((double)timeslotSizeToCompare / this.minTimeslot)) {
return nearestMultipleOfMinTimeslotSize;
} else {
return timeslotSizeToCompare;
}
}
}