From c1f8a577da876d6e9195e88c3e18c1b074e8ae09 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Tue, 3 Dec 2013 16:40:39 +1300 Subject: [PATCH] Add performance tests for custom immutable ring buffer --- .gitignore | 1 + runme.sh | 26 +++++ .../lmax/disruptor/immutable/Constants.java | 7 ++ .../immutable/CustomPerformanceTest.java | 58 +++++++++++ .../disruptor/immutable/CustomRingBuffer.java | 98 +++++++++++++++++++ .../disruptor/immutable/EventAccessor.java | 6 ++ .../lmax/disruptor/immutable/EventHolder.java | 18 ++++ .../immutable/EventHolderHandler.java | 20 ++++ .../lmax/disruptor/immutable/SimpleEvent.java | 22 +++++ .../immutable/SimpleEventHandler.java | 11 +++ .../immutable/SimplePerformanceTest.java | 74 ++++++++++++++ 11 files changed, 341 insertions(+) create mode 100755 runme.sh create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/Constants.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/CustomPerformanceTest.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/CustomRingBuffer.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/EventAccessor.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/EventHolder.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/EventHolderHandler.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/SimpleEvent.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/SimpleEventHandler.java create mode 100644 src/perftest/java/com/lmax/disruptor/immutable/SimplePerformanceTest.java diff --git a/.gitignore b/.gitignore index ca6c80b87..33793ed77 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ pom.xml *.iml *.ipr *.iws +*-gc.log diff --git a/runme.sh b/runme.sh new file mode 100755 index 000000000..f75595f1a --- /dev/null +++ b/runme.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +rm *-gc.log + +echo "Running Simple..." +$JAVA_HOME/bin/java -Xloggc:simple-gc.log \ + -verbose:gc \ + -XX:+PrintGCDateStamps \ + -XX:+PrintGCApplicationStoppedTime \ + -cp "build/classes/main:build/classes/perf:templib/*.jar" \ + com.lmax.disruptor.immutable.SimplePerformanceTest +echo "Done" + +grep 'stopped:' simple-gc.log | sed 's/.*stopped: \([0-9.]*\) seconds/\1/' | sort -n | awk '{ printf "%1.3f\n", $1 }' | (echo " Count Millis" ; uniq -c ) + +echo "Running Custom..." +$JAVA_HOME/bin/java -Xloggc:custom-gc.log \ + -verbose:gc \ + -XX:+PrintGCDateStamps \ + -XX:+PrintGCApplicationStoppedTime \ + -cp "build/classes/main:build/classes/perf:templib/*.jar" \ + com.lmax.disruptor.immutable.CustomPerformanceTest +echo "Done" + +grep 'stopped:' custom-gc.log | sed 's/.*stopped: \([0-9.]*\) seconds/\1/' | sort -n | awk '{ printf "%1.3f\n", $1 }' | (echo " Count Millis" ; uniq -c ) + diff --git a/src/perftest/java/com/lmax/disruptor/immutable/Constants.java b/src/perftest/java/com/lmax/disruptor/immutable/Constants.java new file mode 100644 index 000000000..7c5525803 --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/Constants.java @@ -0,0 +1,7 @@ +package com.lmax.disruptor.immutable; + +public class Constants +{ + public static final long ITERATIONS = 1000 * 1000 * 100L; + public static final int SIZE = 1 << 20; +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/CustomPerformanceTest.java b/src/perftest/java/com/lmax/disruptor/immutable/CustomPerformanceTest.java new file mode 100644 index 000000000..250f521dc --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/CustomPerformanceTest.java @@ -0,0 +1,58 @@ +package com.lmax.disruptor.immutable; + +import java.util.concurrent.locks.LockSupport; + +import com.lmax.disruptor.BatchEventProcessor; +import com.lmax.disruptor.SingleProducerSequencer; +import com.lmax.disruptor.YieldingWaitStrategy; + +public class CustomPerformanceTest +{ + private final CustomRingBuffer ringBuffer; + + public CustomPerformanceTest() + { + ringBuffer = new CustomRingBuffer(new SingleProducerSequencer(Constants.SIZE, new YieldingWaitStrategy())); + } + + public void run() + { + try + { + doRun(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + private void doRun() throws InterruptedException + { + BatchEventProcessor batchEventProcessor = ringBuffer.createHandler(new SimpleEventHandler()); + + Thread t = new Thread(batchEventProcessor); + t.start(); + + long iterations = Constants.ITERATIONS; + for (long l = 0; l < iterations; l++) + { + SimpleEvent e = new SimpleEvent(l, l, l, l); + ringBuffer.put(e); + } + + while (batchEventProcessor.getSequence().get() != iterations - 1) + { + LockSupport.parkNanos(1); + } + + batchEventProcessor.halt(); + t.join(); + } + + public static void main(String[] args) + { + new CustomPerformanceTest().run(); + } + +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/CustomRingBuffer.java b/src/perftest/java/com/lmax/disruptor/immutable/CustomRingBuffer.java new file mode 100644 index 000000000..c44225d22 --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/CustomRingBuffer.java @@ -0,0 +1,98 @@ +package com.lmax.disruptor.immutable; + +import com.lmax.disruptor.BatchEventProcessor; +import com.lmax.disruptor.DataProvider; +import com.lmax.disruptor.EventHandler; +import com.lmax.disruptor.LifecycleAware; +import com.lmax.disruptor.Sequencer; + +public class CustomRingBuffer implements DataProvider>, EventAccessor +{ + private static final class AccessorEventHandler implements EventHandler>, LifecycleAware + { + private final EventHandler handler; + private final LifecycleAware lifecycle; + + private AccessorEventHandler(EventHandler handler) + { + this.handler = handler; + lifecycle = handler instanceof LifecycleAware ? (LifecycleAware) handler : null; + } + + @Override + public void onEvent(EventAccessor accessor, long sequence, boolean endOfBatch) throws Exception + { + this.handler.onEvent(accessor.take(sequence), sequence, endOfBatch); + } + + @Override + public void onShutdown() + { + if (null != lifecycle) + { + lifecycle.onShutdown(); + } + } + + @Override + public void onStart() + { + if (null != lifecycle) + { + lifecycle.onStart(); + } + } + } + + private final Sequencer sequencer; + private final Object[] buffer; + private final int mask; + + public CustomRingBuffer(Sequencer sequencer) + { + this.sequencer = sequencer; + buffer = new Object[sequencer.getBufferSize()]; + mask = sequencer.getBufferSize() - 1; + } + + private int index(long sequence) + { + return (int) sequence & mask; + } + + public void put(T e) + { + long next = sequencer.next(); + buffer[index(next)] = e; + sequencer.publish(next); + } + + @SuppressWarnings("unchecked") + @Override + public T take(long sequence) + { + int index = index(sequence); + + T t = (T) buffer[index]; + buffer[index] = null; + + return t; + } + + @Override + public EventAccessor get(long sequence) + { + return this; + } + + public BatchEventProcessor> createHandler(final EventHandler handler) + { + BatchEventProcessor> processor = + new BatchEventProcessor>(this, + sequencer.newBarrier(), + new AccessorEventHandler(handler)); + sequencer.addGatingSequences(processor.getSequence()); + + return processor; + } +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/EventAccessor.java b/src/perftest/java/com/lmax/disruptor/immutable/EventAccessor.java new file mode 100644 index 000000000..2f0fe86bd --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/EventAccessor.java @@ -0,0 +1,6 @@ +package com.lmax.disruptor.immutable; + +public interface EventAccessor +{ + T take(long sequence); +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/EventHolder.java b/src/perftest/java/com/lmax/disruptor/immutable/EventHolder.java new file mode 100644 index 000000000..515310b9f --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/EventHolder.java @@ -0,0 +1,18 @@ +package com.lmax.disruptor.immutable; + +import com.lmax.disruptor.EventFactory; + +public class EventHolder +{ + + public static final EventFactory FACTORY = new EventFactory() + { + @Override + public EventHolder newInstance() + { + return new EventHolder(); + } + }; + + public SimpleEvent event; +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/EventHolderHandler.java b/src/perftest/java/com/lmax/disruptor/immutable/EventHolderHandler.java new file mode 100644 index 000000000..f59718784 --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/EventHolderHandler.java @@ -0,0 +1,20 @@ +package com.lmax.disruptor.immutable; + +import com.lmax.disruptor.EventHandler; + +public class EventHolderHandler implements EventHandler +{ + private final EventHandler delegate; + + public EventHolderHandler(EventHandler delegate) + { + this.delegate = delegate; + } + + @Override + public void onEvent(EventHolder holder, long sequence, boolean endOfBatch) throws Exception + { + delegate.onEvent(holder.event, sequence, endOfBatch); + holder.event = null; + } +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/SimpleEvent.java b/src/perftest/java/com/lmax/disruptor/immutable/SimpleEvent.java new file mode 100644 index 000000000..d24bda593 --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/SimpleEvent.java @@ -0,0 +1,22 @@ +package com.lmax.disruptor.immutable; + +public class SimpleEvent +{ + private final long id; + private final long v1; + private final long v2; + private final long v3; + + public SimpleEvent(long id, long v1, long v2, long v3) + { + this.id = id; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + } + + public long getCounter() + { + return v1; + } +} \ No newline at end of file diff --git a/src/perftest/java/com/lmax/disruptor/immutable/SimpleEventHandler.java b/src/perftest/java/com/lmax/disruptor/immutable/SimpleEventHandler.java new file mode 100644 index 000000000..0f72a122e --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/SimpleEventHandler.java @@ -0,0 +1,11 @@ +package com.lmax.disruptor.immutable; + +import com.lmax.disruptor.EventHandler; + +public class SimpleEventHandler implements EventHandler +{ + @Override + public void onEvent(SimpleEvent arg0, long arg1, boolean arg2) throws Exception + { + } +} diff --git a/src/perftest/java/com/lmax/disruptor/immutable/SimplePerformanceTest.java b/src/perftest/java/com/lmax/disruptor/immutable/SimplePerformanceTest.java new file mode 100644 index 000000000..f8b6b7124 --- /dev/null +++ b/src/perftest/java/com/lmax/disruptor/immutable/SimplePerformanceTest.java @@ -0,0 +1,74 @@ +package com.lmax.disruptor.immutable; + +import java.util.concurrent.locks.LockSupport; + +import com.lmax.disruptor.BatchEventProcessor; +import com.lmax.disruptor.EventTranslatorOneArg; +import com.lmax.disruptor.RingBuffer; +import com.lmax.disruptor.YieldingWaitStrategy; + +public class SimplePerformanceTest +{ + private final RingBuffer ringBuffer; + private final EventHolderHandler eventHolderHandler; + + public SimplePerformanceTest() + { + ringBuffer = RingBuffer.createSingleProducer(EventHolder.FACTORY, Constants.SIZE, new YieldingWaitStrategy()); + eventHolderHandler = new EventHolderHandler(new SimpleEventHandler()); + } + + public void run() + { + try + { + doRun(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + private void doRun() throws InterruptedException + { + BatchEventProcessor batchEventProcessor = + new BatchEventProcessor(ringBuffer, + ringBuffer.newBarrier(), + eventHolderHandler); + ringBuffer.addGatingSequences(batchEventProcessor.getSequence()); + + Thread t = new Thread(batchEventProcessor); + t.start(); + + long iterations = Constants.ITERATIONS; + for (long l = 0; l < iterations; l++) + { + SimpleEvent e = new SimpleEvent(l, l, l, l); + ringBuffer.publishEvent(TRANSLATOR, e); + } + + while (batchEventProcessor.getSequence().get() != iterations - 1) + { + LockSupport.parkNanos(1); + } + + batchEventProcessor.halt(); + t.join(); + } + + private static final EventTranslatorOneArg TRANSLATOR = + new EventTranslatorOneArg() + { + @Override + public void translateTo(EventHolder holder, long arg1, SimpleEvent event) + { + holder.event = event; + } + }; + + public static void main(String[] args) + { + new SimplePerformanceTest().run(); + } +}