diff --git a/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java index 6637971f7..ca7d43f3d 100644 --- a/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java @@ -115,7 +115,7 @@ public abstract class AbstractChronicleMapBuilder keyClass, Class valueClass, Alignment alignment) { + AbstractChronicleMapBuilder(Class keyClass, Class valueClass) { keyBuilder = new SerializationBuilder(keyClass, SerializationBuilder.Role.KEY); valueBuilder = new SerializationBuilder(valueClass, SerializationBuilder.Role.VALUE); - this.alignment = alignment; } protected static boolean offHeapReference(Class valueClass) { @@ -318,7 +317,9 @@ public abstract class AbstractChronicleMapBuilder } ChronicleMapBuilder(Class keyClass, Class valueClass) { - super(keyClass, valueClass, getAlignmentFor(valueClass)); - } - - private static Alignment getAlignmentFor(Class valueClass) { - return offHeapReference(valueClass) ? Alignment.OF_4_BYTES : Alignment.NO_ALIGNMENT; + super(keyClass, valueClass); } @Override diff --git a/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java index 5545f86fe..0c7880724 100644 --- a/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java @@ -37,7 +37,7 @@ public final class OffHeapUpdatableChronicleMapBuilder } OffHeapUpdatableChronicleMapBuilder(Class keyClass, Class valueClass) { - super(keyClass, valueClass, Alignment.OF_4_BYTES); + super(keyClass, valueClass); prepareValueBytesOnAcquire(new ZeroOutValueBytes(valueSize())); } @@ -74,7 +74,7 @@ public final class OffHeapUpdatableChronicleMapBuilder * alignment. I. e. if you set {@code entrySize(20)} and {@link Alignment#OF_8_BYTES}, actual * entry size will be 24 (20 aligned to 8 bytes). * - *

Default is {@link Alignment#NO_ALIGNMENT}. + *

Default is {@link Alignment#OF_4_BYTES} for Byteable values. * * @param alignment the new alignment of the maps constructed by this builder * @return this {@code ChronicleMapBuilder} back diff --git a/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java b/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java index 29b618119..7909a0bfb 100644 --- a/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java @@ -575,25 +575,28 @@ public class ChronicleMapTest { throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException, ExecutionException { // int runs = Integer.getInteger("runs", 10); + int procs = Runtime.getRuntime().availableProcessors(); + int threads = procs * 2; // runs > 100 ? procs / 2 : procs; + ExecutorService es = Executors.newFixedThreadPool(procs); for (int runs : new int[]{10, 50, 250, 500, 1000, 2500}) { + // JAVA 8 produces more garbage than previous versions for internal work. +// System.gc(); final long entries = runs * 1000 * 1000L; OffHeapUpdatableChronicleMapBuilder builder = OffHeapUpdatableChronicleMapBuilder .of(CharSequence.class, LongValue.class) .entries(entries) + .entryAndValueAlignment(OF_8_BYTES) .entrySize(24); File tmpFile = File.createTempFile("testAcquirePerf", ".deleteme"); tmpFile.deleteOnExit(); final ChronicleMap map = builder.createWithFile(tmpFile); - int procs = Runtime.getRuntime().availableProcessors(); - int threads = procs * 2; // runs > 100 ? procs / 2 : procs; - int count = runs > 500 ? runs > 1200 ? 1 : 3 : 5; - final int independence = 8; // Math.min(procs, runs > 500 ? 8 : 4); + int count = runs > 500 ? runs > 1200 ? 3 : 5 : 5; + final int independence = Math.min(procs, runs > 500 ? 8 : 4); System.out.println("\nKey size: " + runs + " Million entries. " + builder); for (int j = 0; j < count; j++) { long start = System.currentTimeMillis(); - ExecutorService es = Executors.newFixedThreadPool(procs); List futures = new ArrayList(); for (int i = 0; i < threads; i++) { final int t = i; @@ -625,8 +628,6 @@ public class ChronicleMapTest { for (Future future : futures) { future.get(); } - es.shutdown(); - es.awaitTermination(runs / 10 + 1, TimeUnit.MINUTES); long time = System.currentTimeMillis() - start; System.out.printf("Throughput %.1f M ops/sec%n", threads * entries / independence / 1000.0 / time); } @@ -635,21 +636,95 @@ public class ChronicleMapTest { map.close(); file.delete(); } + es.shutdown(); + es.awaitTermination(1, TimeUnit.MINUTES); + } + @Test + @Ignore + public void testAcquireLockedPerf() + throws IOException, ClassNotFoundException, IllegalAccessException, + InstantiationException, InterruptedException, ExecutionException { +// int runs = Integer.getInteger("runs", 10); + int procs = Runtime.getRuntime().availableProcessors(); + int threads = procs * 2; // runs > 100 ? procs / 2 : procs; + ExecutorService es = Executors.newFixedThreadPool(procs); + for (int runs : new int[]{10, 50, 250, 500, 1000, 2500}) { + // JAVA 8 produces more garbage than previous versions for internal work. +// System.gc(); + final long entries = runs * 1000 * 1000L; + OffHeapUpdatableChronicleMapBuilder builder = OffHeapUpdatableChronicleMapBuilder + .of(CharSequence.class, LongValue.class) + .entries(entries) + .entryAndValueAlignment(OF_8_BYTES) + .entrySize(24); + + File tmpFile = File.createTempFile("testAcquirePerf", ".deleteme"); + tmpFile.deleteOnExit(); + final ChronicleMap map = builder.createWithFile(tmpFile); + + int count = runs > 500 ? runs > 1200 ? 3 : 5 : 5; + final int independence = Math.min(procs, runs > 500 ? 8 : 4); + System.out.println("\nKey size: " + runs + " Million entries. " + builder); + for (int j = 0; j < count; j++) { + long start = System.currentTimeMillis(); + List futures = new ArrayList(); + for (int i = 0; i < threads; i++) { + final int t = i; + futures.add(es.submit(new Runnable() { + @Override + public void run() { + LongValue value = nativeLongValue(); + StringBuilder sb = new StringBuilder(); + long next = 50 * 1000 * 1000; + // use a factor to give up to 10 digit numbers. + int factor = Math.max(1, (int) ((10 * 1000 * 1000 * 1000L - 1) / entries)); + for (long j = t % independence; j < entries + independence - 1; j += independence) { + sb.setLength(0); + sb.append("us:"); + sb.append(j * factor); + long n; + try(WriteContext wc = map.acquireUsingLocked(sb, value)) { + n = value.addValue(1); + } + assert n > 0 && n < 1000 : "Counter corrupted " + n; + if (t == 0 && j >= next) { + long size = map.longSize(); + if (size < 0) throw new AssertionError("size: " + size); + System.out.println(j + ", size: " + size); + next += 50 * 1000 * 1000; + } + } + } + })); + } + for (Future future : futures) { + future.get(); + } + long time = System.currentTimeMillis() - start; + System.out.printf("Throughput %.1f M ops/sec%n", threads * entries / independence / 1000.0 / time); + } + printStatus(); + File file = map.file(); + map.close(); + file.delete(); + } + es.shutdown(); + es.awaitTermination(1, TimeUnit.MINUTES); } @Test @Ignore public void testCHMAcquirePerf() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException { - for (int runs : new int[]{10, 50, 250, 1000, 2500}) { + for (int runs : new int[]{10, 50, 250, 500, 1000, 2500}) { System.out.println("Testing " + runs + " million entries"); final long entries = runs * 1000 * 1000L; - final ConcurrentMap map = new ConcurrentHashMap((int) (entries * 5 / 4), 1.0f, 1024); int procs = Runtime.getRuntime().availableProcessors(); int threads = procs * 2; - int count = runs > 500 ? runs > 1200 ? 1 : 2 : 3; + int count = runs > 500 ? runs > 1200 ? 1 : 2 : 5; final int independence = Math.min(procs, runs > 500 ? 8 : 4); for (int j = 0; j < count; j++) { + final ConcurrentMap map = new ConcurrentHashMap((int) (entries * 5 / 4), 1.0f, 1024); long start = System.currentTimeMillis(); ExecutorService es = Executors.newFixedThreadPool(procs); for (int i = 0; i < threads; i++) { @@ -668,7 +743,7 @@ public class ChronicleMapTest { String key = sb.toString(); AtomicInteger count = map.get(key); if (count == null) { - map.put(key, new AtomicInteger()); + map.putIfAbsent(key, new AtomicInteger()); count = map.get(key); } count.getAndIncrement();