/* * Copyright 2016 higherfrequencytrading.com * * 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. */ package net.openhft.lang.io; import net.openhft.lang.model.constraints.NotNull; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; /** * @author peter.lawrey */ public class DirectBytesTest { private static void manyToggles(@NotNull DirectStore store1, int lockCount, int from, int to) { long id = Thread.currentThread().getId(); assertEquals(0, id >>> 24); System.out.println("Thread " + id); DirectBytes slice1 = store1.bytes(); int records = 64; for (int i = 0; i < lockCount; i += records) { for (long j = 0; j < records * 64; j += 64) { slice1.positionAndSize(j, 64); boolean condition = false; for (int k = 0; k < 20; k++) { condition = slice1.tryLockInt(0L) || slice1.tryLockNanosInt(0L, 5 * 1000 * 1000); if (condition) break; if (k > 0) System.out.println("k: " + (5 + k * 5)); } if (!condition) assertTrue("i= " + i, condition); int toggle1 = slice1.readInt(4); if (toggle1 == from) { slice1.writeInt(4L, to); } else { // noinspection AssignmentToForLoopParameter,AssignmentToForLoopParameter i--; } slice1.unlockInt(0L); System.currentTimeMillis(); // small delay } } } private static void manyLongToggles(@NotNull DirectStore store1, int lockCount, int from, int to) { long id = Thread.currentThread().getId(); assertEquals(0, id >>> 32); System.out.println("Thread " + id); DirectBytes slice1 = store1.bytes(); int records = 64; for (int i = 0; i < lockCount; i += records) { for (long j = 0; j < records * 64; j += 64) { slice1.positionAndSize(j, 64); boolean condition = false; for (int k = 0; k < 20; k++) { condition = slice1.tryLockLong(0L) || slice1.tryLockNanosLong(0L, 5 * 1000 * 1000); if (condition) break; if (k > 0) System.out.println("k: " + (5 + k * 5)); } if (!condition) assertTrue("i= " + i, condition); long toggle1 = slice1.readLong(8); if (toggle1 == from) { slice1.writeLong(8L, to); } else { // noinspection AssignmentToForLoopParameter,AssignmentToForLoopParameter i--; } slice1.unlockLong(0L); System.currentTimeMillis(); // small delay } } } @Test public void testSimpleLock() { DirectBytes bytes = new DirectStore(64).bytes(); bytes.writeLong(0, -1L); assertFalse(bytes.tryLockLong(0)); bytes.writeLong(0, 0L); assertTrue(bytes.tryLockLong(0)); long val1 = bytes.readLong(0); assertTrue(bytes.tryLockLong(0)); bytes.unlockLong(0); assertEquals(val1, bytes.readLong(0)); bytes.unlockLong(0); assertEquals(0L, bytes.readLong(0)); try { bytes.unlockLong(0); fail(); } catch (IllegalMonitorStateException e) { // expected. } } @Test public void testAllocate() { long size = 1L << 24; // 31; don't overload cloud-bees DirectStore store = DirectStore.allocate(size); assertEquals(size, store.size()); DirectBytes slice = store.bytes(); slice.positionAndSize(0, size); slice.writeLong(0, size); slice.writeLong(size - 8, size); store.free(); } @Test public void testLocking() { if (Runtime.getRuntime().availableProcessors() < 2) { System.err.println("Test requires 2 CPUs, skipping"); return; } long start = System.nanoTime(); // a page final DirectStore store1 = DirectStore.allocate(1 << 12); final int lockCount = 10 * 1000 * 1000; new Thread(new Runnable() { @Override public void run() { manyToggles(store1, lockCount, 1, 0); } }).start(); manyToggles(store1, lockCount, 0, 1); store1.free(); long time = System.nanoTime() - start; System.out.printf("Contended lock rate was %,d per second%n", (int) (lockCount * 2 * 1e9 / time)); } @Test public void testLockingLong() { if (Runtime.getRuntime().availableProcessors() < 2) { System.err.println("Test requires 2 CPUs, skipping"); return; } long start = System.nanoTime(); // a page final DirectStore store1 = DirectStore.allocate(1 << 12); final int lockCount = 10 * 1000 * 1000; new Thread(new Runnable() { @Override public void run() { manyLongToggles(store1, lockCount, 1, 0); } }).start(); manyLongToggles(store1, lockCount, 0, 1); store1.free(); long time = System.nanoTime() - start; System.out.printf("Contended lock rate was %,d per second%n", (int) (lockCount * 2 * 1e9 / time)); } @Test public void testLocking2() throws InterruptedException { if (Runtime.getRuntime().availableProcessors() < 2) { System.err.println("Test requires 2 CPUs, skipping"); return; } // a page final DirectStore store1 = DirectStore.allocate(1 << 12); final DirectStore store2 = DirectStore.allocate(1 << 12); final int lockCount = 1000000; Thread t = new Thread(new Runnable() { @Override public void run() { long id = Thread.currentThread().getId(); System.out.println("Thread " + id); assertEquals(0, id >>> 24); int expected = (1 << 24) | (int) id; try { DirectBytes slice1 = store1.bytes(); DirectBytes slice2 = store2.bytes(); for (int i = 0; i < lockCount; i += 2) { slice1.busyLockInt(0); slice2.busyLockInt(0); int lockValue1 = slice1.readInt(0); if (lockValue1 != expected) assertEquals(expected, lockValue1); int lockValue2 = slice2.readInt(0); if (lockValue2 != expected) assertEquals(expected, lockValue2); int toggle1 = slice1.readInt(4); if (toggle1 == 1) { slice1.writeInt(4, 0); // if (i % 10000== 0) // System.out.println("t: " + i); } else { // noinspection AssignmentToForLoopParameter i--; } int toggle2 = slice2.readInt(4); if (toggle2 == 1) { slice2.writeInt(4, 0); // if (i % 10000== 0) // System.out.println("t: " + i); } else { // noinspection AssignmentToForLoopParameter i--; } int lockValue1A = slice1.readInt(0); int lockValue2A = slice1.readInt(0); try { slice2.unlockInt(0); slice1.unlockInt(0); } catch (IllegalStateException e) { int lockValue1B = slice1.readInt(0); int lockValue2B = slice2.readInt(0); System.err.println("i= " + i + " lock: " + Integer.toHexString(lockValue1A) + " / " + Integer.toHexString(lockValue2A) + " lock: " + Integer.toHexString(lockValue1B) + " / " + Integer.toHexString(lockValue2B)); throw e; } } } catch (InterruptedException e) { e.printStackTrace(); } } }); t.start(); long id = Thread.currentThread().getId(); assertEquals(0, id >>> 24); int expected = (1 << 24) | (int) id; System.out.println("Thread " + id); DirectBytes slice1 = store1.bytes(); DirectBytes slice2 = store2.bytes(); for (int i = 0; i < lockCount; i += 2) { slice1.busyLockInt(0); slice2.busyLockInt(0); int lockValue1 = slice1.readInt(0); if (lockValue1 != expected) assertEquals(expected, lockValue1); int lockValue2 = slice2.readInt(0); if (lockValue2 != expected) assertEquals(expected, lockValue2); int toggle1 = slice1.readInt(4); if (toggle1 == 0) { slice1.writeInt(4, 1); // if (i % 10000== 0) // System.out.println("t: " + i); } else { // noinspection AssignmentToForLoopParameter i--; } int toggle2 = slice2.readInt(4); if (toggle2 == 0) { slice2.writeInt(4, 1); // if (i % 10000== 0) // System.out.println("t: " + i); } else { // noinspection AssignmentToForLoopParameter i--; } int lockValue1A = slice1.readInt(0); int lockValue2A = slice1.readInt(0); try { slice2.unlockInt(0); slice1.unlockInt(0); } catch (IllegalStateException e) { int lockValue1B = slice1.readInt(0); int lockValue2B = slice2.readInt(0); System.err.println("i= " + i + " lock: " + Integer.toHexString(lockValue1A) + " / " + Integer.toHexString(lockValue2A) + " lock: " + Integer.toHexString(lockValue1B) + " / " + Integer.toHexString(lockValue2B)); throw e; } } store1.free(); store2.free(); } @Test @Ignore public void benchmarkByteLargeArray() { long length = 1L << 32; long start = System.nanoTime(); DirectBytes array = DirectStore.allocateLazy(length).bytes(); System.out.println("Constructor time: " + (System.nanoTime() - start) / 1e9 + " sec"); int iters = 2; byte one = 1; start = System.nanoTime(); for (int it = 0; it < iters; it++) { for (long i = 0; i < length; i++) { array.writeByte(i, one); array.writeByte(i, (byte) (array.readByte(i) + one)); } } System.out.println("Computation time: " + (System.nanoTime() - start) / 1e9 / iters + " sec"); } }