package org.cache2k.benchmark.util;
/*
* #%L
* Benchmarks: utilities
* %%
* 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.junit.Test;
import static org.junit.Assert.*;
import java.util.HashSet;
import java.util.Set;
/**
* @author Jens Wilke; created: 2013-11-14
*/
public class OptimumReplacementCalculationTest {
int calcHits(int _size, int[] _trace) {
OptimumReplacementCalculation c = new OptimumReplacementCalculation(_size, _trace);
return c.getHitCount();
}
@Test
public void test3_3() {
int v = calcHits(1, new int[] {1, 2, 3});
assertEquals(0, v);
}
@Test
public void test2_2() {
int v = calcHits(1, new int[] {1, 1});
assertEquals(1, v);
}
@Test
public void test2_6() {
int v = calcHits(1, new int[] {1, 1, 1, 0, 0, 0});
assertEquals(4, v);
}
@Test
public void test4_4() {
int v = calcHits(1, new int[] {1, 2, 3, 2});
assertEquals(0, v);
}
@Test
public void test2_4() {
int v = calcHits(1, new int[] {1, 1, 0, 1});
assertEquals(1, v);
}
@Test
public void test4_6() {
int v = calcHits(2, new int[] {2, 3, 1, 3, 0, 1});
assertEquals(2, v);
}
@Test
public void test7_11() {
int v = calcHits(3, new int[] {0, 4, 2, 6, 4, 1, 5, 0, 3, 1, 1});
assertEquals(4, v);
}
@Test
public void test3_6() {
int v = calcHits(2, new int[] {1, 1, 1, 0, 0, 0, 2, 2, 2, 1, 0, 0});
assertEquals(8, v);
}
@Test
public void testCompareToStraightForward() throws Exception {
final int[] _VALUE_RANGE = new int[]{44, 77, 111, 22, 777};
final int[] _TRACE_SIZE = new int[]{987, 876, 3712, 555, 7897};
for (int i = 0; i < _VALUE_RANGE.length; i++) {
AccessTrace t =
new AccessTrace(new RandomAccessPattern(_VALUE_RANGE[i]), _TRACE_SIZE[i]);
assertEquals(optTraceHits(t.getArray(), _VALUE_RANGE[i]/2), t.getOptHitCount(_VALUE_RANGE[i]/2));
}
}
@Test
public void testOptCalcMiss1K() {
AccessTrace t = new AccessTrace(Patterns.sequence(1000));
assertEquals(0, t.getOptHitCount(500));
}
@Test
public void testOptCalcMiss10K() {
AccessTrace t = new AccessTrace(Patterns.sequence(10 * 1000));
assertEquals(0, t.getOptHitCount(500));
}
@Test
public void testOptCalcMiss50K() {
AccessTrace t = new AccessTrace(Patterns.sequence(10 * 1000));
assertEquals(0, t.getOptHitCount(500));
}
@Test
public void testOptCalcMiss100K() {
AccessTrace t = new AccessTrace(Patterns.sequence(100 * 1000));
assertEquals(0, t.getOptHitCount(500));
}
@Test
public void testOptCalcMiss200K() {
AccessTrace t = new AccessTrace(Patterns.sequence(200 * 1000));
assertEquals(0, t.getOptHitCount(500));
}
@Test
public void testUpDownTrace() {
final AccessTrace upDownTrace = new AccessTrace(
Patterns.loop(
Patterns.concat(Patterns.sequence(1000), Patterns.revert(Patterns.sequence(1000))),
1000));
assertEquals(1000, upDownTrace.getValueCount());
assertEquals(999, upDownTrace.getHighValue());
assertEquals(2000 * 1000 , upDownTrace.getTraceLength());
assertEquals(50, upDownTrace.getOptHitRate(500).getPercent());
assertEquals(500, upDownTrace.getOptHitRate(500).get3digit());
assertEquals(4998, upDownTrace.getOptHitRate(500).get4digit());
}
/**
* Calculate hit percentage according to Beladys optimal algorithm.
*/
static double optTrace(int[] _trace, int _cacheSize) {
return optTraceHits(_trace, _cacheSize) * 1.0D / _trace.length;
}
/**
* Calculate number of hits according to Beladys optimal algorithm.
*/
static int optTraceHits(int[] _trace, int _cacheSize) {
Set<Integer> _cache = new HashSet<>();
int hit = 0;
int miss = 0;
for (int i = 0; i < _trace.length; i++) {
int key = _trace[i];
if (_cache.contains(key)) {
hit++;
continue;
}
miss++;
if (_cache.size() == _cacheSize) {
_cache.remove(findEvictKey(_trace, i, _cache));
}
_cache.add(key);
}
return hit;
}
/**
* Find the key that should evicted that has a future use that is longest away
* from the current position. This is really slow, than we do a nested loop
* over the cache and over the rest of the trace.
*/
static int findEvictKey(int[] _trace, int _currentPos, Set<Integer> _cache) {
int _futurePos = 0;
int _selectedValue = -1;
for (int v : _cache) {
int p = futurePosition(_trace, _currentPos, v);
if (p > _futurePos) { _selectedValue = v; _futurePos = p; }
}
return _selectedValue;
}
/**
* Next usage of the value in the trace.
*/
static int futurePosition(int[] ia, int _currentPos, int v) {
for (int i = _currentPos; i < ia.length; i++) {
if (ia[i] == v) {
return i;
}
}
return Integer.MAX_VALUE;
}
}