content: /**
   * 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()));
          }
          */
  
      }
  }
  