/**
* 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.alibaba.jstorm.common.metric.codahale;
import com.alibaba.jstorm.utils.JStormUtils;
import com.codahale.metrics.Metered;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author wange
* @since 2.1.1
*/
public class JMeter implements Metered {
private static final long TICK_INTERVAL = TimeUnit.SECONDS.toMillis(5);
private final EWMA m1Rate = EWMA.oneMinuteEWMA();
private final EWMA m5Rate = EWMA.fiveMinuteEWMA();
private final EWMA m15Rate = EWMA.fifteenMinuteEWMA();
private final LongAdder count = new LongAdder();
private final long startTime;
private final AtomicLong lastTick;
/**
* Creates a new {@link JMeter}.
*/
public JMeter() {
this.startTime = System.currentTimeMillis();
this.lastTick = new AtomicLong(startTime);
}
/**
* Mark the occurrence of an event.
*/
public void mark() {
mark(1);
}
/**
* Mark the occurrence of a given number of events.
*
* @param n the number of events
*/
public void mark(long n) {
tickIfNecessary();
count.add(n);
m1Rate.update(n);
m5Rate.update(n);
m15Rate.update(n);
}
private void tickIfNecessary() {
final long oldTimeMs = lastTick.get();
final long newTimeMs = System.currentTimeMillis();
final long age = newTimeMs - oldTimeMs;
if (age > TICK_INTERVAL) {
final long newIntervalStartTick = newTimeMs - age % TICK_INTERVAL;
if (lastTick.compareAndSet(oldTimeMs, newIntervalStartTick)) {
final long requiredTicks = age / TICK_INTERVAL;
for (long i = 0; i < requiredTicks; i++) {
m1Rate.tick();
m5Rate.tick();
m15Rate.tick();
}
}
}
}
@Override
public long getCount() {
return count.sum();
}
@Override
public double getFifteenMinuteRate() {
tickIfNecessary();
return m15Rate.getRate(TimeUnit.SECONDS);
}
@Override
public double getFiveMinuteRate() {
tickIfNecessary();
return m5Rate.getRate(TimeUnit.SECONDS);
}
@Override
public double getMeanRate() {
if (getCount() == 0) {
return 0.0;
} else {
final double elapsed = (System.currentTimeMillis() - startTime);
return getCount() / elapsed * TimeUnit.SECONDS.toMillis(1);
}
}
@Override
public double getOneMinuteRate() {
tickIfNecessary();
return m1Rate.getRate(TimeUnit.SECONDS);
}
public static void main(String[] args) {
int[] speeds = new int[]{0, 0, 0};
// Meter meter = new Meter();
// for (int i = 0; i < speeds.length; i++) {
// for (int j = 0; j < 60; j++) {
// JStormUtils.sleepMs(1000);
// }
// meter.mark(973);
//
// System.out.println(String.format("m1:%.2f, m5:%.2f, m15:%.2f, mean:%.2f",
// meter.getOneMinuteRate(), meter.getFiveMinuteRate(),
// meter.getFifteenMinuteRate(), meter.getMeanRate()));
// }
JMeter jmeter = new JMeter();
for (int i = 0; i < speeds.length; i++) {
for (int j = 0; j < 60; j++) {
JStormUtils.sleepMs(1000);
}
jmeter.mark(973);
System.out.println(String.format("m1:%.2f, m5:%.2f, m15:%.2f, mean:%.2f",
jmeter.getOneMinuteRate(), jmeter.getFiveMinuteRate(),
jmeter.getFifteenMinuteRate(), jmeter.getMeanRate()));
}
/*
int[] speeds = new int[]{50, 40, 30, 20, 10, 10, 10, 10};
for (int i = 0; i < speeds.length; i++) {
for (int j = 0; j < 60; j++) {
JStormUtils.sleepMs(1000);
}
meter.mark(973);
System.out.println(String.format("m1:%.2f, m5:%.2f, m15:%.2f, mean:%.2f",
meter.getOneMinuteRate(), meter.getFiveMinuteRate(),
meter.getFifteenMinuteRate(), meter.getMeanRate()));
}
*/
}
}