Skip to content

Instantly share code, notes, and snippets.

@vladimirdolzhenko
Created June 9, 2016 08:16
Show Gist options
  • Save vladimirdolzhenko/d8e6a1431352b7e639bdd798c2665b26 to your computer and use it in GitHub Desktop.
Save vladimirdolzhenko/d8e6a1431352b7e639bdd798c2665b26 to your computer and use it in GitHub Desktop.
package com.markit.n6platform.cache;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @author vladimir.dolzhenko
* @since 2016-01-07
*/
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Threads(8)
@Fork(3)
public class CHMvsCOWHMRunner {
private static final Unsafe UNSAFE = fetchInstance();
public static Unsafe fetchInstance() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (Throwable e){
throw new RuntimeException(e);
}
}
@State(Scope.Benchmark)
public static class BenchmarkState {
final HMap<String, String> c1 = new CHM<>();
final HMap<String, String> c2 = new COWHM<>();
final List<String> keys;
public BenchmarkState() {
final int size = 10 << 10;
String[] keys = new String[size];
for (int i = 0; i < size; i++) {
final String key = UUID.randomUUID().toString();
final String value = UUID.randomUUID().toString();
keys[i] = key;
if (i % 500 != 0){ // < 10% missed keys
c1.put(key, value);
c2.put(key, value);
}
}
final List<String> strings = new ArrayList<>(Arrays.asList(keys));
Collections.shuffle(strings);
this.keys = strings;
}
}
private int measureReading(List<String> keys, HMap<String, String> map) {
int c = 0;
for (String key : keys) {
if (map.get(key) != null){
c++;
}
}
return c;
}
@Benchmark
public int measureReadingCHM(BenchmarkState state) {
return measureReading(state.keys, state.c1);
}
@Benchmark
public int measureReadingCOWHM(BenchmarkState state) {
return measureReading(state.keys, state.c2);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(CHMvsCOWHMRunner.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(5)
.build();
new Runner(opt).run();
}
private static interface HMap<K, V> {
V get(K key);
V put(K key, V value);
}
private static class CHM<K, V> implements HMap<K, V> {
private volatile ConcurrentHashMap<K, V> map = new ConcurrentHashMap();
@Override
public V get(K key) {
return map.get(key);
}
@Override
public V put(K key, V value) {
return map.put(key, value);
}
}
private static class COWHM<K, V> implements HMap<K, V> {
private volatile HashMap<K, V> map;
private final Object lock = new Object();
private final long offset;
public COWHM() {
this.map = new HashMap<>();
try {
offset = UNSAFE.objectFieldOffset(getClass().getDeclaredField("map"));
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
@Override
public V get(K key) {
//return ((HashMap<K, V>)UNSAFE.getObjectVolatile(this, offset)).get(key);
return map.get(key);
}
@Override
public V put(K key, V value) {
synchronized (lock){
HashMap<K, V> copy = new HashMap<>(map);
final V oldValue = copy.put(key, value);
map = copy;
return oldValue;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment