# HG changeset patch # User skuksenko # Date 1557871771 25200 # Node ID f8d45530b75e463ad8721d572e89df770eebe166 # Parent 1e4ab8f5bc77fc77cef36b418f840b994ba378d2 8223921: Update SocketReadWrite benchmark Reviewed-by: redestad diff -r 1e4ab8f5bc77 -r f8d45530b75e test/micro/org/openjdk/bench/java/net/SocketReadWrite.java --- a/test/micro/org/openjdk/bench/java/net/SocketReadWrite.java Tue May 14 22:31:52 2019 +0200 +++ b/test/micro/org/openjdk/bench/java/net/SocketReadWrite.java Tue May 14 15:09:31 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,86 +22,194 @@ */ 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.net.SocketException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; - /** - * Tests the overheads of I/O API. - * This test is known to depend heavily on network conditions and paltform. + * Benchmark socket read/write. + * */ @BenchmarkMode(Mode.Throughput) -@OutputTimeUnit(TimeUnit.MILLISECONDS) +@OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class SocketReadWrite { - private OutputStream os; - private InputStream is; - private ServerSocket ss; - private Socket s1, s2; - private ReadThread rt; + static final InetAddress address = InetAddress.getLoopbackAddress(); + public static final int TIMEOUT = 10000; + + static class EchoServer implements Runnable { + // EchoServer is implemented to execute the same amount echo threads as benchmarking threads are running + + 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; + + 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; + } + + 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() { + 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(); + } + + } + } + + 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; + + @Param({"false", "true"}) + public boolean timeout; + + Socket s; + InputStream in; + OutputStream out; + byte[] array; @Setup - public void beforeRun() throws IOException { - InetAddress iaddr = InetAddress.getLocalHost(); - - ss = new ServerSocket(0); - s1 = new Socket(iaddr, ss.getLocalPort()); - s2 = ss.accept(); - - os = s1.getOutputStream(); - is = s2.getInputStream(); - - rt = new ReadThread(is); - rt.start(); + 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); + // 10 seconds times is quite large and never will happen (for microbenchmarking), + // but it's required since other paths inside SocketImpl are involved + } + in = s.getInputStream(); + out = s.getOutputStream(); + array = new byte[size]; + ThreadLocalRandom.current().nextBytes(array); } @TearDown - public void afterRun() throws IOException, InterruptedException { - os.write(0); - os.close(); - is.close(); - s1.close(); - s2.close(); - ss.close(); - rt.join(); + public void tearDown() throws IOException { + server.close(); + s.close(); } @Benchmark - public void test() throws IOException { - os.write((byte) 4711); + public void echo() throws IOException { + out.write(array); + readN(array, size, in); } - - static class ReadThread extends Thread { - private InputStream is; - - public ReadThread(InputStream is) { - this.is = is; - } - - public void run() { - try { - while (is.read() > 0); - } catch (SocketException ex) { - // ignore - most likely "socket closed", which means shutdown - } catch (IOException e) { - e.printStackTrace(); - } - } - } - }