/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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 com.leansoft.luxun.mx;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
/**
* statistic tools
*
* @author bulldog
*
*/
public class SnapshotStats {
private final long monitorDurationNs;
private final AtomicReference<Stats> complete = new AtomicReference<Stats>(new Stats());
private final AtomicReference<Stats> current = new AtomicReference<Stats>(new Stats());
private final AtomicLong total = new AtomicLong(0);
private final AtomicLong numCumulatedRequests = new AtomicLong(0);
public SnapshotStats(long monitorDurationNs) {
this.monitorDurationNs = monitorDurationNs;
}
public SnapshotStats() {
this(TimeUnit.MINUTES.toNanos(10));
}
public void recordRequestMetric(long requestNs) {
Stats stats = current.get();
stats.add(requestNs);
total.getAndAdd(requestNs);
numCumulatedRequests.getAndAdd(1);
long ageNs = System.nanoTime() - stats.start;
// if the current stats are too old it is time to swap
if (ageNs >= monitorDurationNs) {
boolean swapped = current.compareAndSet(stats, new Stats());
if (swapped) {
complete.set(stats);
stats.end.set(System.nanoTime());
}
}
}
public void recordThroughputMetric(long data) {
Stats stats = current.get();
stats.addData(data);
long ageNs = System.nanoTime() - stats.start;
// if the current stats are too old it is time to swap
if (ageNs >= monitorDurationNs) {
boolean swapped = current.compareAndSet(stats, new Stats());
if (swapped) {
complete.set(stats);
stats.end.set(System.nanoTime());
}
}
}
public long getNumRequests() {
return numCumulatedRequests.get();
}
public double getRequestsPerSecond() {
Stats stats = complete.get();
return stats.numRequests / stats.durationSeconds();
}
public double getThroughput() {
Stats stats = complete.get();
return stats.totalData / stats.durationSeconds();
}
public double getAvgMetric() {
Stats stats = complete.get();
if (stats.numRequests == 0) {
return 0;
} else {
return stats.totalRequestMetric / stats.numRequests;
}
}
public long getTotalMetric() {
return total.get();
}
public double getMaxMetric() {
return complete.get().maxRequestMetric;
}
//================================================================
class Stats {
final long start = System.nanoTime();
static final double SECOND2NANO = 1000.0 * 1000.0 * 1000.0;
static final double MILLISECOND2NANO = 1000.0 * 1000.0;
AtomicLong end = new AtomicLong(-1);
int numRequests = 0;
long totalRequestMetric = 0L;
long maxRequestMetric = 0L;
long totalData = 0L;
private Object lock = new Object();
long addData(long data) {
synchronized (lock) {
totalData += data;
return totalData;
}
}
long add(long requestNs) {
synchronized (lock) {
numRequests += 1;
totalRequestMetric += requestNs;
maxRequestMetric = Math.max(maxRequestMetric, requestNs);
return maxRequestMetric;
}
}
double durationSeconds() {
return (end.get() - start) / SECOND2NANO;
}
double durationMs() {
return (end.get() - start) / MILLISECOND2NANO;
}
}
}