package org.cache2k.benchmark.jmh.suite.eviction.symmetrical;

/*
 * #%L
 * Benchmarks: JMH suite.
 * %%
 * Copyright (C) 2013 - 2017 headissue GmbH, Munich
 * %%
 * 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.
 * #L%
 */

import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.results.AggregationPolicy;

import static org.cache2k.benchmark.jmh.MiscResultRecorderProfiler.*;

/**
 * Thread state that counts hit, miss and total operations and adds the results to
 * the recorded metrics.
 *
 * <p>Its expected that the miss counter is incremented always. The hit counter
 * or the operations counter (total number of operations) may be incremented
 * alternatively.
 *
 * @author Jens Wilke
 */
@State(Scope.Thread)
public class HitCountRecorder {

  private static final Object LOCK = new Object();

  public long hitCount;
  public long missCount;
  public long opCount;

  @TearDown(Level.Iteration)
  public void tearDown() {
    synchronized (LOCK) {
      if (hitCount > 0) {
        addCounterResult("hitCount", hitCount, "hit", AggregationPolicy.AVG);
      }
      if (missCount > 0) {
        addCounterResult("missCount", missCount, "miss", AggregationPolicy.AVG);
      }
      if (opCount == 0) {
        opCount = hitCount + missCount;
      }
      addCounterResult("opCount", opCount, "op", AggregationPolicy.AVG);
      updateHitrate();
      hitCount = missCount = opCount = 0;
    }
  }

  public static void recordOpCount(long _opCount) {
    synchronized (LOCK) {
      addCounterResult(
        "opCount", _opCount, "op", AggregationPolicy.AVG
      );
      updateHitrate();
    }
  }

  public static void recordMissCount(long _missCount) {
    synchronized (LOCK) {
      addCounterResult(
        "missCount", _missCount, "op", AggregationPolicy.AVG
      );
      updateHitrate();
    }
  }

  /** Called for each thread */
  private static void updateHitrate() {
    long _missCountSum = getCounterResult("missCount");
    long _opCountSum = getCounterResult("opCount");
    if (_opCountSum == 0L) {
      return;
    }
    double _hitRate = 100.0 - _missCountSum * 100.0 / _opCountSum;
    System.err.println(Thread.currentThread() + " hitRate: " + _hitRate);
    setResult("hitrate", _hitRate, "percent", AggregationPolicy.AVG);
  }

}

@@ -1990,24 +1990,112 @@
 dateHitrate(
+%22tearDown(), hitCount=%22 + hitCount + %22, missCount=%22 + missCount + %22, opCount=%22 + opCount
 );%0A      hit
@@ -2318,32 +2318,49 @@
   updateHitrate(
+%22ops=%22 + _opCount
 );%0A    %7D%0A  %7D%0A%0A  
@@ -2553,16 +2553,36 @@
 Hitrate(
+%22miss=%22 + _missCount
 );%0A    %7D
@@ -2655,16 +2655,24 @@
 Hitrate(
+String s
 ) %7B%0A    
@@ -2944,16 +2944,85 @@
  + %22
+ %22 + s + %22, opSum=%22 + _opCountSum + %22, missSum=%22 + _missCountSum + %22,
  hitRate
 : %22 
@@ -3017,18 +3017,17 @@
  hitRate
-: 
+=
 %22 + _hit

add more debug output, so we see when threads are not equally utilized