Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8267502

JDK-8246677 caused 16x performance regression in SynchronousQueue

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: P3
    • Resolution: Unresolved
    • Affects Version/s: 17
    • Fix Version/s: tbd
    • Component/s: core-libs
    • Labels:
      None

      Description

      I was benchmarking SynchronousQueue from the OpenJDK Tip. I found its performance is 16 times lower than the performance of SynchronousQueue from OpenJDK 11. Comparing SynchronousQueue implementations I found the OpenJDK Tip SynchronousQueue is changed by JDK-8246677. Reverting SynchronousQueue to the version before JDK-8246677 fixed the regression.

      I have the regression on Amazon Linux 2 AArch64 and on Amazon Linux 2 x86_64.
      To reproduce:

      $ build/linux-x86_64-server-release/images/jdk/bin/javac SQBench.java
      $ build/linux-x86_64-server-release/images/jdk/bin/java SQBench
      500000
      500000
      500000
      500000
      500000
      # Warmup done. Restarting threads.
      # duration = 1013243934
      # duration (ns) per round trip op = 506.621967
      # round trip ops/sec = 1973858

      $ cd src/java.base/share/classes/java/util/concurrent
      $ wget https://raw.githubusercontent.com/openjdk/jdk/5cfa8c94d6765b93f910fc01cd1ac2a56b16d78a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java
      $ cd -
      $ make images
      $ build/linux-x86_64-server-release/images/jdk/bin/java SQBench
      500000
      500000
      500000
      500000
      500000
      # Warmup done. Restarting threads.
      # duration = 15841810490
      # duration (ns) per round trip op = 7920.905245
      # round trip ops/sec = 126248
      $ uname -o -r
      5.4.109-57.183.amzn2int.x86_64 GNU/Linux

      ----------- SQBench.java
      import java.util.Random;
      import java.util.concurrent.*;

      public class SQBench {
        public static final long WARMUP_PASS_COUNT = 5;
        public static final long WARMUP_ITERATIONS = 500L * 1000L;
        public static final long ITERATIONS = 2 * 1000L * 1000L;

        static class Producer extends java.lang.Thread {
          final long iterations;
          Random rand;
          BlockingQueue<Integer> queue;

          Producer(final long terminatingIterationCount, BlockingQueue<Integer> queue) {
            this.iterations = terminatingIterationCount;
            this.queue = queue;
            rand = new Random(100);
          }

          public void run() {
            try {
              for (long i = 0; i < iterations; i++) {
                queue.put(rand.nextInt(10000));
              }
              queue.put(-1);
            } catch (InterruptedException ie) {
            }
          }
        }

        static class Consumer extends java.lang.Thread {
          public int bits = 0;
          public int count = 0;
          BlockingQueue<Integer> queue;

          Consumer(BlockingQueue<Integer> queue) {
            this.queue = queue;
          }

          public void run() {
            while (true) {
              try {
                Integer number = queue.take();
                if (number == -1) return;
                ++count;
                bits += Integer.bitCount(number.intValue());
              } catch (InterruptedException ie) {
              }
            }
          }
        }

        public static void main(final String[] args) {
          BlockingQueue<Integer> queue = new SynchronousQueue<>();
          try {
            Producer producer;
            Consumer consumer;

            for (int i = 0; i < WARMUP_PASS_COUNT; i++) {
              consumer = new Consumer(queue);
              producer = new Producer(WARMUP_ITERATIONS, queue);
              producer.start();
              consumer.start();
              producer.join();
              consumer.join();
              System.out.println(consumer.count);
            }

            java.lang.Thread.sleep(1000); // Let things (like JIT compilations) settle down.
            System.out.println("# Warmup done. Restarting threads.");

            consumer = new Consumer(queue);
            producer = new Producer(ITERATIONS, queue);

            long start = System.nanoTime();
            producer.start();
            consumer.start();
            producer.join();
            consumer.join();
            long duration = System.nanoTime() - start;

            System.out.println("# duration = " + duration);
            System.out.println("# duration (ns) per round trip op = " + duration / (ITERATIONS * 1.0));
            System.out.println(
                "# round trip ops/sec = " + (ITERATIONS * 1000L * 1000L * 1000L) / duration);
          } catch (InterruptedException ex) {
            System.err.println("SpinWaitTest interrupted.");
          }
        }
      }

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              dl Doug Lea
              Reporter:
              eastigeevich Evgeny Astigeevich
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Dates

                Created:
                Updated: