package org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class JucLockStackDriver extends BenchmarkDriver { private int pushThreadCount = 1; private int popThreadCount = 1; private int capacity; private PushThread[] pushThreads; private PopThread[] popThreads; private Stack stack; @Override public void setUp() { System.out.printf("Multiverse > Pop threadcount %s\n", pushThreadCount); System.out.printf("Multiverse > Push threadcount %s\n", popThreadCount); if (capacity == Integer.MAX_VALUE) { System.out.printf("Multiverse > Capacity unbound\n"); } else { System.out.printf("Multiverse > Capacity %s\n", capacity); } stack = new Stack(); pushThreads = new PushThread[pushThreadCount]; for (int k = 0; k < pushThreadCount; k++) { pushThreads[k] = new PushThread(k); } popThreads = new PopThread[popThreadCount]; for (int k = 0; k < popThreadCount; k++) { popThreads[k] = new PopThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(pushThreads); startAll(popThreads); joinAll(pushThreads); joinAll(popThreads); } @Override public void processResults(TestCaseResult result) { long pushCount = 0; long totalDurationMs = 0; for (PushThread t : pushThreads) { pushCount += t.count; totalDurationMs += t.getDurationMs(); } long popCount = 0; for (PopThread t : popThreads) { popCount += t.count; totalDurationMs += t.getDurationMs(); } int threadCount = pushThreadCount + popThreadCount; long count = pushCount + popCount; System.out.printf("Multiverse > Total number of transactions %s\n", count); double transactionsPerSecond = (count * 1000.0d) / totalDurationMs; System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecond), threadCount); result.put("transactionsPerSecond", transactionsPerSecond); } public class PushThread extends TestThread { private long count; public PushThread(int id) { super("PushThread-" + id); } @Override public void doRun() throws Exception { while (!shutdown) { stack.push("item"); count++; } for (int k = 0; k < popThreadCount; k++) { stack.push("end"); } } } public class PopThread extends TestThread { private long count; public PopThread(int id) { super("PopThread-" + id); } @Override public void doRun() throws Exception { boolean end = false; while (!end) { end = stack.pop().equals("end"); count++; } } } class Stack { final Lock lock = new ReentrantLock(); final Condition isNotEmptyCondition = lock.newCondition(); final Condition isNotFullCondition = lock.newCondition(); Node head; int size; public String pop() { lock.lock(); try { while (head == null) { isNotEmptyCondition.awaitUninterruptibly(); } if (capacity != Integer.MAX_VALUE) { size--; } isNotFullCondition.signalAll(); Node node = head; head = node.next; return node.value; } finally { lock.unlock(); } } public void push(String value) { lock.lock(); try { if (capacity != Integer.MAX_VALUE) { while (size == capacity) { isNotFullCondition.awaitUninterruptibly(); } } size++; head = new Node(head, value); isNotEmptyCondition.signalAll(); } finally { lock.unlock(); } } } static class Node { final Node next; final String value; Node(Node next, String value) { this.next = next; this.value = value; } } }