@Override
  protected long runDisruptorPass() throws Exception {
    CountDownLatch latch = new CountDownLatch(1);
    fizzBuzzHandler.reset(latch, batchProcessorFizzBuzz.getSequence().get() + ITERATIONS);

    executor.submit(batchProcessorFizz);
    executor.submit(batchProcessorBuzz);
    executor.submit(batchProcessorFizzBuzz);

    long start = System.currentTimeMillis();

    for (long i = 0; i < ITERATIONS; i++) {
      long sequence = ringBuffer.next();
      ringBuffer.get(sequence).setValue(i);
      ringBuffer.publish(sequence);
    }

    latch.await();
    long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);

    batchProcessorFizz.halt();
    batchProcessorBuzz.halt();
    batchProcessorFizzBuzz.halt();

    Assert.assertEquals(expectedResult, fizzBuzzHandler.getFizzBuzzCounter());

    return opsPerSecond;
  }
public class TestShow {

  private static final int BUFFER_SIZE = 32;

  private final RingBuffer<ValueEvent> ringBuffer =
      RingBuffer.createSingleProducer(
          ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());
  private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();

  private final ConsumeEventHandler handler = new ConsumeEventHandler();

  private final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();

  private final BatchEventProcessor<ValueEvent> batchEventProcessor =
      new BatchEventProcessor<ValueEvent>(ringBuffer, sequenceBarrier, handler);

  public TestShow() {
    ringBuffer.addGatingSequences(batchEventProcessor.getSequence());
  }

  public void consume() {
    EXECUTOR.submit(batchEventProcessor);
  }

  public void produce() {
    new Thread(new Producer(ringBuffer)).start();
  }

  public static void main(String[] args) {
    TestShow test = new TestShow();
    test.produce();
    test.consume();
  }
}
示例#3
0
    private boolean sendMessages(
        RingBuffer<byte[]> ringBuffer, long messagesPerSecond, int runtimeSeconds)
        throws InterruptedException {
      LOGGER.info("Rate: " + messagesPerSecond + ", for " + runtimeSeconds + "s");

      long runtimeNanos = TimeUnit.SECONDS.toNanos(runtimeSeconds);

      long t0 = System.nanoTime();
      long delta = 0;
      long sent = 0;

      try {
        do {
          delta = System.nanoTime() - t0;
          long shouldHaveSent = (messagesPerSecond * delta) / 1000000000;

          for (; sent < shouldHaveSent; sent++) {
            if (!send(ringBuffer)) {
              return false;
            }
          }

          LockSupport.parkNanos(1);
        } while (delta <= runtimeNanos);

        Thread.sleep(1000);
        return ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize());

      } finally {
        while (!ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize())) {
          Thread.sleep(1000);
        }
      }
    }
示例#4
0
 private void fillRingBuffer(long expectedNumberMessages) throws InterruptedException {
   for (long i = 0; i < expectedNumberMessages; i++) {
     long sequence = ringBuffer.next();
     StubEvent event = ringBuffer.getPreallocated(sequence);
     event.setValue((int) i);
     ringBuffer.publish(sequence);
   }
 }
 public void onData(ByteBuffer bb) {
   long sequence = ringBuffer.next(); // Grab the next sequence
   try {
     LongEvent event = ringBuffer.get(sequence); // Get the entry in the Disruptor for the sequence
     event.set(bb.getLong(0)); // Fill with data
   } finally {
     ringBuffer.publish(sequence);
   }
 }
示例#6
0
 public DisruptorQueue(ClaimStrategy claim, WaitStrategy wait) {
   _buffer = new RingBuffer<MutableObject>(new ObjectEventFactory(), claim, wait);
   _consumer = new Sequence();
   _barrier = _buffer.newBarrier();
   _buffer.setGatingSequences(_consumer);
   if (claim instanceof SingleThreadedClaimStrategy) {
     consumerStartedFlag = true;
   }
 }
示例#7
0
 public void pushData(ByteBuffer bb) {
   long sequence = ringBuffer.next();
   try {
     PCData event = ringBuffer.get(sequence);
     event.setData(bb.getLong(0));
   } finally {
     ringBuffer.publish(sequence);
   }
 }
示例#8
0
 public void run() {
   // Publishers claim events in sequence
   long sequence = ringBuffer.next();
   ValueEvent event = ringBuffer.get(sequence);
   for (int i = 0; i < 3000; i++) {
     event.setValue(i); // this could be more complex with multiple fields
     // make the event available to EventProcessors
     ringBuffer.publish(sequence);
   }
 }
 public void put(Object member, List<Record> records) throws AnalyticsException {
   RingBuffer<RecordsHolder> buffer = this.getRingBuffer(member);
   long sequence = buffer.next();
   try {
     RecordsHolder event = buffer.get(sequence);
     event.setRecords(records);
   } finally {
     buffer.publish(sequence);
   }
 }
 private void prefillArgumentHolderObjects(
     final RingBuffer<ProxyMethodInvocation> ringBuffer,
     final ArgumentHolderGenerator argumentHolderGenerator) {
   final int bufferSize = ringBuffer.getBufferSize();
   for (int i = 0; i < bufferSize; i++) {
     ringBuffer
         .get(i)
         .setArgumentHolder(
             (Resetable) instantiate(argumentHolderGenerator.getGeneratedClass(), new Class[] {}));
   }
 }
示例#11
0
 private void publishDirect(Object obj, boolean block) throws InsufficientCapacityException {
   final long id;
   if (block) {
     id = _buffer.next();
   } else {
     id = _buffer.tryNext(1);
   }
   final MutableObject m = _buffer.get(id);
   m.setObject(obj);
   _buffer.publish(id);
 }
示例#12
0
    private boolean send(RingBuffer<byte[]> ringBuffer) {

      if (ringBuffer.hasAvailableCapacity(1)) {
        long next = ringBuffer.next();
        byte[] event = ringBuffer.get(next);
        System.arraycopy(input, 0, event, 0, event.length);
        ringBuffer.publish(next);
        return true;
      } else {
        errorCount++;
        return false;
      }
    }
  @Override
  public void run() {
    try {
      cyclicBarrier.await();

      for (long i = 0; i < iterations; i++) {
        long sequence = ringBuffer.next();
        ValueEvent event = ringBuffer.get(sequence);
        event.setValue(i);
        ringBuffer.publish(sequence);
      }
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }
示例#14
0
  @Test
  public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsAhead() throws Exception {
    final long expectedNumberMessages = 10;
    final long expectedWorkSequence = 9;
    fillRingBuffer(expectedNumberMessages);

    final Sequence sequence1 = new Sequence(expectedNumberMessages);
    final Sequence sequence2 = new Sequence(expectedWorkSequence);
    final Sequence sequence3 = new Sequence(expectedNumberMessages);

    context.checking(
        new Expectations() {
          {
            one(eventProcessor1).getSequence();
            will(returnValue(sequence1));

            one(eventProcessor2).getSequence();
            will(returnValue(sequence2));

            one(eventProcessor3).getSequence();
            will(returnValue(sequence3));
          }
        });

    SequenceBarrier sequenceBarrier =
        ringBuffer.newBarrier(
            eventProcessor1.getSequence(),
            eventProcessor2.getSequence(),
            eventProcessor3.getSequence());

    long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence);
    assertTrue(completedWorkSequence >= expectedWorkSequence);
  }
示例#15
0
  @Test
  public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsBehind() throws Exception {
    long expectedNumberMessages = 10;
    fillRingBuffer(expectedNumberMessages);

    final StubEventProcessor[] eventProcessors = new StubEventProcessor[3];
    for (int i = 0, size = eventProcessors.length; i < size; i++) {
      eventProcessors[i] = new StubEventProcessor();
      eventProcessors[i].setSequence(expectedNumberMessages - 2);
    }

    final SequenceBarrier sequenceBarrier =
        ringBuffer.newBarrier(Util.getSequencesFor(eventProcessors));

    Runnable runnable =
        new Runnable() {
          public void run() {
            for (StubEventProcessor stubWorker : eventProcessors) {
              stubWorker.setSequence(stubWorker.getSequence().get() + 1L);
            }
          }
        };

    Thread thread = new Thread(runnable);
    thread.start();
    thread.join();

    long expectedWorkSequence = expectedNumberMessages - 1;
    long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence);
    assertTrue(completedWorkSequence >= expectedWorkSequence);
  }
示例#16
0
  public void engage() {
    // starts WorkerPool workers in separate thread(s)
    RingBuffer<DemoEvent> ringBuf = workerPool.start(execService);

    // publish lots of events
    for (int i = 0; i < 5 * NUM_WORKERS; i++) {
      long seq = ringBuf.next();
      ringBuf.get(seq).setProcessId(i);
      ringBuf.publish(seq);
      // try it with and without the sleep
      // try { Thread.sleep(33); } catch (Exception e) { }
    }

    // wait until all published events are processed, then stop the workers
    workerPool.drainAndHalt();
  }
示例#17
0
 private void consumeBatchToCursor(long cursor, EventHandler<Object> handler) {
   for (long curr = _consumer.get() + 1; curr <= cursor; curr++) {
     try {
       MutableObject mo = _buffer.get(curr);
       Object o = mo.o;
       mo.setObject(null);
       if (o == FLUSH_CACHE) {
         Object c = null;
         while (true) {
           c = _cache.poll();
           if (c == null) break;
           else handler.onEvent(c, curr, true);
         }
       } else if (o == INTERRUPT) {
         throw new InterruptedException("Disruptor processing interrupted");
       } else {
         handler.onEvent(o, curr, curr == cursor);
       }
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
   }
   // TODO: only set this if the consumer cursor has changed?
   _consumer.set(cursor);
 }
示例#18
0
 public void publish(Object obj, boolean block) throws InsufficientCapacityException {
   if (consumerStartedFlag) {
     final long id;
     if (block) {
       id = _buffer.next();
     } else {
       id = _buffer.tryNext(1);
     }
     final MutableObject m = _buffer.get(id);
     m.setObject(obj);
     _buffer.publish(id);
   } else {
     _cache.add(obj);
     if (consumerStartedFlag) flushCache();
   }
 }
示例#19
0
  @Test
  public void shouldWaitForWorkCompleteWhereAllWorkersAreBlockedOnRingBuffer() throws Exception {
    long expectedNumberMessages = 10;
    fillRingBuffer(expectedNumberMessages);

    final StubEventProcessor[] workers = new StubEventProcessor[3];
    for (int i = 0, size = workers.length; i < size; i++) {
      workers[i] = new StubEventProcessor();
      workers[i].setSequence(expectedNumberMessages - 1);
    }

    final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(Util.getSequencesFor(workers));

    Runnable runnable =
        new Runnable() {
          public void run() {
            long sequence = ringBuffer.next();
            StubEvent event = ringBuffer.getPreallocated(sequence);
            event.setValue((int) sequence);
            ringBuffer.publish(sequence);

            for (StubEventProcessor stubWorker : workers) {
              stubWorker.setSequence(sequence);
            }
          }
        };

    new Thread(runnable).start();

    long expectedWorkSequence = expectedNumberMessages;
    long completedWorkSequence = sequenceBarrier.waitFor(expectedNumberMessages);
    assertTrue(completedWorkSequence >= expectedWorkSequence);
  }
示例#20
0
  @Test
  public void shouldSupportCustomProcessorsAsDependencies() throws Exception {
    RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer();

    final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();

    CountDownLatch countDownLatch = new CountDownLatch(2);
    EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub(countDownLatch);

    final BatchEventProcessor<TestEvent> processor =
        new BatchEventProcessor<TestEvent>(
            ringBuffer, ringBuffer.newBarrier(), delayedEventHandler);
    disruptor.handleEventsWith(processor);
    disruptor.after(processor).handleEventsWith(handlerWithBarrier);

    ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler);
  }
  @Override
  protected long runDisruptorPass() throws InterruptedException {

    resetCounters();
    RingBuffer<ValueEvent> ringBuffer = workerPool.start(EXECUTOR);
    long start = System.currentTimeMillis();

    for (long i = 0; i < ITERATIONS; i++) {
      long sequence = ringBuffer.next();
      ringBuffer.getPreallocated(sequence).setValue(i);
      ringBuffer.publish(sequence);
    }

    workerPool.drainAndHalt();
    long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);

    assertEquals(ITERATIONS, sumCounters());

    return opsPerSecond;
  }
示例#22
0
  @Test
  public void shouldSetAndClearAlertStatus() {
    SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();

    assertFalse(sequenceBarrier.isAlerted());

    sequenceBarrier.alert();
    assertTrue(sequenceBarrier.isAlerted());

    sequenceBarrier.clearAlert();
    assertFalse(sequenceBarrier.isAlerted());
  }
示例#23
0
  public DisruptorQueue(String queueName, ClaimStrategy claim, WaitStrategy wait, long timeout) {
    this._queueName = PREFIX + queueName;
    _buffer = new RingBuffer<MutableObject>(new ObjectEventFactory(), claim, wait);
    _consumer = new Sequence();
    _barrier = _buffer.newBarrier();
    _buffer.setGatingSequences(_consumer);
    _metrics = new QueueMetrics();

    if (claim instanceof SingleThreadedClaimStrategy) {
      consumerStartedFlag = true;
    } else {
      // make sure we flush the pending messages in cache first
      try {
        publishDirect(FLUSH_CACHE, true);
      } catch (InsufficientCapacityException e) {
        throw new RuntimeException("This code should be unreachable!", e);
      }
    }

    _waitTimeout = timeout;
  }
示例#24
0
  @Test
  public void shouldInterruptDuringBusySpin() throws Exception {
    final long expectedNumberMessages = 10;
    fillRingBuffer(expectedNumberMessages);

    final CountDownLatch latch = new CountDownLatch(3);
    final Sequence sequence1 = new CountDownLatchSequence(8L, latch);
    final Sequence sequence2 = new CountDownLatchSequence(8L, latch);
    final Sequence sequence3 = new CountDownLatchSequence(8L, latch);

    context.checking(
        new Expectations() {
          {
            one(eventProcessor1).getSequence();
            will(returnValue(sequence1));

            one(eventProcessor2).getSequence();
            will(returnValue(sequence2));

            one(eventProcessor3).getSequence();
            will(returnValue(sequence3));
          }
        });

    final SequenceBarrier sequenceBarrier =
        ringBuffer.newBarrier(
            Util.getSequencesFor(eventProcessor1, eventProcessor2, eventProcessor3));

    final boolean[] alerted = {false};
    Thread t =
        new Thread(
            new Runnable() {
              public void run() {
                try {
                  sequenceBarrier.waitFor(expectedNumberMessages - 1);
                } catch (AlertException e) {
                  alerted[0] = true;
                } catch (InterruptedException e) {
                  // don't care
                }
              }
            });

    t.start();
    latch.await(3, TimeUnit.SECONDS);
    sequenceBarrier.alert();
    t.join();

    assertTrue("Thread was not interrupted", alerted[0]);
  }
    @SuppressWarnings("unchecked")
    public void run() {
      try {
        if (cyclicBarrier != null) cyclicBarrier.await();

        for (int i = 0; i < howmany; i++) {
          long seq = ringBuf.next();
          DemoEvent ev = ringBuf.get(seq);
          // each event will have the pubcount in processId
          // and the name of the publisher it came from in the Name field
          ev.setProcessId(i);
          ev.setName("Published by DemoPublisher #" + id);
          System.out.printf("Published by DemoPublisher #%d; procId: %d; slot: %d\n", id, i, seq);
          ringBuf.publish(seq);
          if (should_pause_b)
            try {
              Thread.sleep(8);
            } catch (Exception e) {
            }
        }
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
示例#26
0
 public long writePos() {
   return _buffer.getCursor();
 }
示例#27
0
 public long capacity() {
   return _buffer.getBufferSize();
 }
示例#28
0
 public SequenceBarrierTest() {
   ringBuffer.setGatingSequences(new NoOpEventProcessor(ringBuffer).getSequence());
 }
 {
   ringBuffer.addGatingSequences(batchProcessorFizzBuzz.getSequence());
 }
/**
 *
 *
 * <pre>
 * Produce an event replicated to two event processors and fold back to a single third event processor.
 *
 *           +-----+
 *    +----->| EP1 |------+
 *    |      +-----+      |
 *    |                   v
 * +----+              +-----+
 * | P1 |              | EP3 |
 * +----+              +-----+
 *    |                   ^
 *    |      +-----+      |
 *    +----->| EP2 |------+
 *           +-----+
 *
 *
 * Queue Based:
 * ============
 *                 take       put
 *     put   +====+    +-----+    +====+  take
 *    +----->| Q1 |<---| EP1 |--->| Q3 |<------+
 *    |      +====+    +-----+    +====+       |
 *    |                                        |
 * +----+    +====+    +-----+    +====+    +-----+
 * | P1 |--->| Q2 |<---| EP2 |--->| Q4 |<---| EP3 |
 * +----+    +====+    +-----+    +====+    +-----+
 *
 * P1  - Publisher 1
 * Q1  - Queue 1
 * Q2  - Queue 2
 * Q3  - Queue 3
 * Q4  - Queue 4
 * EP1 - EventProcessor 1
 * EP2 - EventProcessor 2
 * EP3 - EventProcessor 3
 *
 *
 * Disruptor:
 * ==========
 *                    track to prevent wrap
 *              +-------------------------------+
 *              |                               |
 *              |                               v
 * +----+    +====+               +=====+    +-----+
 * | P1 |--->| RB |<--------------| SB2 |<---| EP3 |
 * +----+    +====+               +=====+    +-----+
 *      claim   ^  get               |   waitFor
 *              |                    |
 *           +=====+    +-----+      |
 *           | SB1 |<---| EP1 |<-----+
 *           +=====+    +-----+      |
 *              ^                    |
 *              |       +-----+      |
 *              +-------| EP2 |<-----+
 *             waitFor  +-----+
 *
 * P1  - Publisher 1
 * RB  - RingBuffer
 * SB1 - SequenceBarrier 1
 * EP1 - EventProcessor 1
 * EP2 - EventProcessor 2
 * SB2 - SequenceBarrier 2
 * EP3 - EventProcessor 3
 *
 * </pre>
 */
public final class OnePublisherToThreeProcessorDiamondThroughputTest
    extends AbstractPerfTestQueueVsDisruptor {
  private static final int NUM_EVENT_PROCESSORS = 3;
  private static final int BUFFER_SIZE = 1024 * 8;
  private static final long ITERATIONS = 1000L * 1000L * 100L;
  private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS);

  private final long expectedResult;

  {
    long temp = 0L;

    for (long i = 0; i < ITERATIONS; i++) {
      boolean fizz = 0 == (i % 3L);
      boolean buzz = 0 == (i % 5L);

      if (fizz && buzz) {
        ++temp;
      }
    }

    expectedResult = temp;
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////

  private final BlockingQueue<Long> fizzInputQueue = new LinkedBlockingQueue<Long>(BUFFER_SIZE);
  private final BlockingQueue<Long> buzzInputQueue = new LinkedBlockingQueue<Long>(BUFFER_SIZE);
  private final BlockingQueue<Boolean> fizzOutputQueue =
      new LinkedBlockingQueue<Boolean>(BUFFER_SIZE);
  private final BlockingQueue<Boolean> buzzOutputQueue =
      new LinkedBlockingQueue<Boolean>(BUFFER_SIZE);

  private final FizzBuzzQueueProcessor fizzQueueProcessor =
      new FizzBuzzQueueProcessor(
          FizzBuzzStep.FIZZ,
          fizzInputQueue,
          buzzInputQueue,
          fizzOutputQueue,
          buzzOutputQueue,
          ITERATIONS - 1);

  private final FizzBuzzQueueProcessor buzzQueueProcessor =
      new FizzBuzzQueueProcessor(
          FizzBuzzStep.BUZZ,
          fizzInputQueue,
          buzzInputQueue,
          fizzOutputQueue,
          buzzOutputQueue,
          ITERATIONS - 1);

  private final FizzBuzzQueueProcessor fizzBuzzQueueProcessor =
      new FizzBuzzQueueProcessor(
          FizzBuzzStep.FIZZ_BUZZ,
          fizzInputQueue,
          buzzInputQueue,
          fizzOutputQueue,
          buzzOutputQueue,
          ITERATIONS - 1);

  ///////////////////////////////////////////////////////////////////////////////////////////////

  private final RingBuffer<FizzBuzzEvent> ringBuffer =
      createSingleProducer(FizzBuzzEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());

  private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();

  private final FizzBuzzEventHandler fizzHandler = new FizzBuzzEventHandler(FizzBuzzStep.FIZZ);
  private final BatchEventProcessor<FizzBuzzEvent> batchProcessorFizz =
      new BatchEventProcessor<FizzBuzzEvent>(ringBuffer, sequenceBarrier, fizzHandler);

  private final FizzBuzzEventHandler buzzHandler = new FizzBuzzEventHandler(FizzBuzzStep.BUZZ);
  private final BatchEventProcessor<FizzBuzzEvent> batchProcessorBuzz =
      new BatchEventProcessor<FizzBuzzEvent>(ringBuffer, sequenceBarrier, buzzHandler);

  private final SequenceBarrier sequenceBarrierFizzBuzz =
      ringBuffer.newBarrier(batchProcessorFizz.getSequence(), batchProcessorBuzz.getSequence());

  private final FizzBuzzEventHandler fizzBuzzHandler =
      new FizzBuzzEventHandler(FizzBuzzStep.FIZZ_BUZZ);
  private final BatchEventProcessor<FizzBuzzEvent> batchProcessorFizzBuzz =
      new BatchEventProcessor<FizzBuzzEvent>(ringBuffer, sequenceBarrierFizzBuzz, fizzBuzzHandler);

  {
    ringBuffer.addGatingSequences(batchProcessorFizzBuzz.getSequence());
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////

  @Override
  protected int getRequiredProcessorCount() {
    return 4;
  }

  @Test
  @Override
  public void shouldCompareDisruptorVsQueues() throws Exception {
    testImplementations();
  }

  @Override
  protected long runQueuePass() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    fizzBuzzQueueProcessor.reset(latch);

    Future<?>[] futures = new Future[NUM_EVENT_PROCESSORS];
    futures[0] = executor.submit(fizzQueueProcessor);
    futures[1] = executor.submit(buzzQueueProcessor);
    futures[2] = executor.submit(fizzBuzzQueueProcessor);

    long start = System.currentTimeMillis();

    for (long i = 0; i < ITERATIONS; i++) {
      Long value = Long.valueOf(i);
      fizzInputQueue.put(value);
      buzzInputQueue.put(value);
    }

    latch.await();
    long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);

    fizzQueueProcessor.halt();
    buzzQueueProcessor.halt();
    fizzBuzzQueueProcessor.halt();

    for (Future<?> future : futures) {
      future.cancel(true);
    }

    Assert.assertEquals(expectedResult, fizzBuzzQueueProcessor.getFizzBuzzCounter());

    return opsPerSecond;
  }

  @Override
  protected long runDisruptorPass() throws Exception {
    CountDownLatch latch = new CountDownLatch(1);
    fizzBuzzHandler.reset(latch, batchProcessorFizzBuzz.getSequence().get() + ITERATIONS);

    executor.submit(batchProcessorFizz);
    executor.submit(batchProcessorBuzz);
    executor.submit(batchProcessorFizzBuzz);

    long start = System.currentTimeMillis();

    for (long i = 0; i < ITERATIONS; i++) {
      long sequence = ringBuffer.next();
      ringBuffer.get(sequence).setValue(i);
      ringBuffer.publish(sequence);
    }

    latch.await();
    long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);

    batchProcessorFizz.halt();
    batchProcessorBuzz.halt();
    batchProcessorFizzBuzz.halt();

    Assert.assertEquals(expectedResult, fizzBuzzHandler.getFizzBuzzCounter());

    return opsPerSecond;
  }
}