Improve SocketReadWrite microbenchmark niosocketimpl-branch
authoralanb
Fri, 15 Feb 2019 10:39:45 +0000
branchniosocketimpl-branch
changeset 57185 e0e1493fa166
parent 57179 1774a7b73c72
child 57186 997178749c87
Improve SocketReadWrite microbenchmark Contributed-by: sergey.kuksenko@oracle.com
test/micro/org/openjdk/bench/java/net/SocketReadWrite.java
--- a/test/micro/org/openjdk/bench/java/net/SocketReadWrite.java	Wed Feb 13 14:43:25 2019 +0000
+++ b/test/micro/org/openjdk/bench/java/net/SocketReadWrite.java	Fri Feb 15 10:39:45 2019 +0000
@@ -22,65 +22,206 @@
  */
 package org.openjdk.bench.java.net;
 
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import org.openjdk.jmh.annotations.*;
-
 /**
  * Tests socket read/write.
  */
+
 @BenchmarkMode(Mode.Throughput)
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@OutputTimeUnit(TimeUnit.SECONDS)
 @State(Scope.Thread)
 public class SocketReadWrite {
 
-    private Socket s1, s2;
-    private InputStream in;
-    private OutputStream out;
+    static final InetAddress address = InetAddress.getLoopbackAddress();
+    public static final int TIMEOUT = 10000;
+
+    static class EchoServer implements Runnable {
+        final ServerSocket ss;
+        final int port;
+        final CountDownLatch startedLatch;
+        final int size;
+        final boolean timeout;
+        List<ServerThread> threads = new ArrayList<>();
+        volatile boolean isDone = false;
+
+        public EchoServer(CountDownLatch await, int size, boolean timeout) throws IOException {
+            this.size = size;
+            this.timeout = timeout;
+            ss = new ServerSocket(0);
+            port = ss.getLocalPort();
+            this.startedLatch = await;
+        }
+
+        @Override
+        public void run() {
+            startedLatch.countDown();
+            while (!isDone) {
+                try {
+                    Socket s = ss.accept();
+                    s.setTcpNoDelay(true);
+                    if (timeout) {
+                        s.setSoTimeout(TIMEOUT);
+                    }
+                    ServerThread st = new ServerThread(s, size);
+                    threads.add(st);
+                    new Thread(st).start();
+                } catch (IOException e) {
+                    if (!isDone) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        synchronized void close() throws IOException {
+            if (!isDone) {
+                isDone = true;
+                ss.close();
+                for (ServerThread st : threads) {
+                    st.close();
+                }
+            }
+        }
+
+        static EchoServer instance = null;
 
-    @Setup
-    public void beforeRun() throws IOException {
-        InetAddress lb = InetAddress.getLoopbackAddress();
-        try (ServerSocket ss = new ServerSocket(0)) {
-            s1 = new Socket(lb, ss.getLocalPort());
-            s2 = ss.accept();
+        static synchronized EchoServer startServer(int size, boolean timeout) throws IOException {
+            if (instance == null) {
+                CountDownLatch started = new CountDownLatch(1);
+                EchoServer s = new EchoServer(started, size, timeout);
+                new Thread(s).start();
+                try {
+                    started.await(); // wait until server thread started
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                instance = s;
+            }
+            return instance;
         }
-        s1.setTcpNoDelay(true);
-        s2.setTcpNoDelay(true);
-        in = s1.getInputStream();
-        out = s2.getOutputStream();
+
+        static class ServerThread implements Runnable {
+
+            final Socket s;
+            final InputStream in;
+            final OutputStream out;
+            final int size;
+            volatile boolean isDone = false;
+
+            ServerThread(Socket s, int size) throws IOException {
+                this.s = s;
+                this.size = size;
+                in = s.getInputStream();
+                out = s.getOutputStream();
+            }
+
+            @Override
+            public void run() {
+                if (size == 1) {
+                    while (!isDone) {
+                        try {
+                            int b = this.in.read();
+                            out.write(b);
+                        } catch (IOException e) {
+                            if (!isDone) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                } else {
+                    byte[] a = new byte[size];
+                    while (!isDone) {
+                        try {
+                            readN(a, size, this.in);
+                            out.write(a);
+                        } catch (IOException e) {
+                            if (!isDone) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+            }
+
+            public void close() throws IOException {
+                isDone = true;
+                s.close();
+            }
+
+        }
     }
 
-    @TearDown
-    public void afterRun() throws IOException {
-        s1.close();
-        s2.close();
+    static void readN(byte[] array, int size, InputStream in) throws IOException {
+        int nread = 0;
+        while (size > 0) {
+            int n = in.read(array, nread, size);
+            if (n < 0) throw new RuntimeException();
+            nread += n;
+            size -= n;
+        }
     }
 
+    EchoServer server;
+
     @Param({"1", "1024", "8192", "64000", "128000"})
     public int size;
 
-    private final byte[] array = new byte[512*1024];
+    @Param({"false", "true"})
+    public boolean timeout;
+
+    Socket s;
+    InputStream in;
+    OutputStream out;
+    byte[] array;
+
+    @Setup
+    public void setup() throws IOException {
+        server = EchoServer.startServer(size, timeout);
+        int port = server.port;
+        s = new Socket(address, port);
+        s.setTcpNoDelay(true);
+        if (timeout) {
+            s.setSoTimeout(TIMEOUT);
+        }
+        in = s.getInputStream();
+        out = s.getOutputStream();
+        array = new byte[size];
+    }
+
+    @TearDown
+    public void tearDown() throws IOException {
+        server.close();
+        s.close();
+    }
 
     @Benchmark
-    public void test() throws IOException {
+    public void echo() throws IOException {
         if (size == 1) {
             out.write((byte) 47);
             int c = in.read();
         } else {
-            out.write(array, 0, size);
-            int nread = 0;
-            while (nread < size) {
-                int n = in.read(array, 0, size);
-                if (n < 0) throw new RuntimeException();
-                nread += n;
-            }
+            out.write(array);
+            readN(array, size, in);
         }
+
     }
 }