001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.wake.metrics; 020 021import java.util.concurrent.TimeUnit; 022import java.util.concurrent.atomic.AtomicLong; 023 024/** 025 * Meter that monitors mean throughput and ewma (1m, 5m, 15m) throughput. 026 */ 027public class Meter { 028 029 private static final long TICK_INTERVAL = TimeUnit.SECONDS.toNanos(5); 030 031 private final AtomicLong count = new AtomicLong(); 032 private final long startTime; 033 private final AtomicLong lastTick; 034 035 private final EWMA m1Thp; 036 private final EWMA m5Thp; 037 private final EWMA m15Thp; 038 039 private final String name; 040 041 /** 042 * Constructs a meter. 043 * 044 * @param name the name of the meter 045 */ 046 public Meter(final String name) { 047 this.name = name; 048 this.m1Thp = new EWMA(EWMAParameters.M1_ALPHA, EWMAParameters.INTERVAL, TimeUnit.SECONDS); 049 this.m5Thp = new EWMA(EWMAParameters.M5_ALPHA, EWMAParameters.INTERVAL, TimeUnit.SECONDS); 050 this.m15Thp = new EWMA(EWMAParameters.M15_ALPHA, EWMAParameters.INTERVAL, TimeUnit.SECONDS); 051 this.startTime = getTick(); 052 this.lastTick = new AtomicLong(startTime); 053 } 054 055 /** 056 * Gets the name of the meter. 057 * 058 * @return the meter name 059 */ 060 public String getName() { 061 return name; 062 } 063 064 /** 065 * Marks the number of events. 066 * 067 * @param n the number of events 068 */ 069 public void mark(final long n) { 070 tickIfNecessary(); 071 count.addAndGet(n); 072 m1Thp.update(n); 073 m5Thp.update(n); 074 m15Thp.update(n); 075 } 076 077 /** 078 * Gets the count. 079 * 080 * @return the count 081 */ 082 public long getCount() { 083 return count.get(); 084 } 085 086 /** 087 * Gets the mean throughput. 088 * 089 * @return the mean throughput 090 */ 091 public double getMeanThp() { 092 if (getCount() == 0) { 093 return 0.0; 094 } else { 095 final double elapsed = getTick() - startTime; 096 return getCount() / elapsed * TimeUnit.SECONDS.toNanos(1); 097 } 098 } 099 100 /** 101 * Gets the 1-minute EWMA throughput. 102 * 103 * @return the 1-minute EWMA throughput 104 */ 105 public double get1mEWMAThp() { 106 tickIfNecessary(); 107 return m1Thp.getRate(TimeUnit.SECONDS); 108 } 109 110 /** 111 * Gets the 5-minute EWMA throughput. 112 * 113 * @return the 5-minute EWMA throughput 114 */ 115 public double get5mEWMAThp() { 116 tickIfNecessary(); 117 return m5Thp.getRate(TimeUnit.SECONDS); 118 } 119 120 /** 121 * Gets the 15-minute EWMA throughput. 122 * 123 * @return the 15-minute EWMA throughput 124 */ 125 public double get15mEWMAThp() { 126 tickIfNecessary(); 127 return m15Thp.getRate(TimeUnit.SECONDS); 128 } 129 130 private long getTick() { 131 return System.nanoTime(); 132 } 133 134 private void tickIfNecessary() { 135 final long oldTick = lastTick.get(); 136 final long newTick = getTick(); 137 final long age = newTick - oldTick; 138 if (age > TICK_INTERVAL && lastTick.compareAndSet(oldTick, newTick)) { 139 final long requiredTicks = age / TICK_INTERVAL; 140 for (long i = 0; i < requiredTicks; i++) { 141 m1Thp.tick(); 142 m5Thp.tick(); 143 m15Thp.tick(); 144 } 145 } 146 } 147}