# HG changeset patch # User alanb # Date 1550227185 0 # Node ID e0e1493fa16609f709cb397a13c337431c1c2623 # Parent 1774a7b73c72061035bd9f01d4372eef909c1e54 Improve SocketReadWrite microbenchmark Contributed-by: sergey.kuksenko@oracle.com diff -r 1774a7b73c72 -r e0e1493fa166 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 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); } + } }