public int onNext() {
    while (pub.tryClaim(buffer.capacity(), bufferClaim) < 0L) {}

    final MutableDirectBuffer buffer = bufferClaim.buffer();
    final int offset = bufferClaim.offset();
    buffer.putByte(offset, (byte) 'p');
    buffer.putInt(offset + 1, msgCount++);
    buffer.putLong(offset + 5, System.nanoTime());
    bufferClaim.commit();
    return msgLen;
  }
  public AeronLatencyUnderLoadPublisher(final String[] args) {
    try {
      parseArgs(args);
    } catch (final ParseException e) {
      throw new RuntimeException(e);
    }
    final Aeron.Context ctx = new Aeron.Context().newImageHandler(this::imageHandler);
    fragmentHandler = new FragmentAssembler(this::msgHandler);
    final Aeron aeron = Aeron.connect(ctx);
    System.out.println("Reflect: " + reflectChannel + " Pub: " + pubChannel);
    pub = aeron.addPublication(pubChannel, pubStreamId);
    sub = aeron.addSubscription(reflectChannel, subStreamId);
    imageLatch = new CountDownLatch(1);
    final IdleStrategy idle = new BusySpinIdleStrategy();
    bufferClaim = new BufferClaim();

    final List<RateControllerInterval> intervals = new ArrayList<>();
    intervals.add(new MessagesAtMessagesPerSecondInterval(100, 10));
    intervals.add(new MessagesAtMessagesPerSecondInterval(1000, 100));
    intervals.add(new MessagesAtMessagesPerSecondInterval(10000, 1000));
    intervals.add(new MessagesAtMessagesPerSecondInterval(100000, 10000));
    intervals.add(new MessagesAtMessagesPerSecondInterval(1000000, 100000));
    intervals.add(new MessagesAtMessagesPerSecondInterval(10000000, 1000000));
    intervals.add(new MessagesAtMessagesPerSecondInterval(30000000, 3000000));
    buffer = new UnsafeBuffer(ByteBuffer.allocateDirect(msgLen));
    msgCount = 0;

    RateController rateController = null;
    try {
      rateController = new RateController(this, intervals);
    } catch (final Exception ex) {
      throw new RuntimeException(ex);
    }

    final Runnable task =
        () -> {
          while (running) {
            while (sub.poll(fragmentHandler, 1) <= 0 && running) {}
          }
          System.out.println("Done");
        };
    final Thread subThread = new Thread(task);
    subThread.start();

    try {
      imageLatch.await();
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }

    final int warmUpMsgs = 100000;
    for (int i = 0; i < warmUpMsgs; i++) {
      while (pub.tryClaim(buffer.capacity(), bufferClaim) < 0L) {
        idle.idle(1);
      }
      final MutableDirectBuffer buffer = bufferClaim.buffer();
      final int offset = bufferClaim.offset();
      buffer.putByte(offset, (byte) 'w');
      bufferClaim.commit();
    }
    try {
      Thread.sleep(1000);
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("warmup msgs received: " + warmups);
    final int start = (int) System.currentTimeMillis();
    while (rateController.next()) {}

    final int total = (int) (System.currentTimeMillis() - start) / 1000;
    buffer.putByte(0, (byte) 'q');

    while (pub.offer(buffer, 0, buffer.capacity()) < 0L) {
      idle.idle(0);
    }

    System.out.println("Duration: " + total + " seconds");
    try {
      Thread.sleep(1000);
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }

    running = false;

    try {
      subThread.join();
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }

    aeron.close();

    try {
      computeStats();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }