test/micro/org/openjdk/bench/java/net/SocketReadWrite.java
changeset 54850 f8d45530b75e
parent 52595 16609197022c
child 57358 f0a1d9760c5e
equal deleted inserted replaced
54849:1e4ab8f5bc77 54850:f8d45530b75e
     1 /*
     1 /*
     2  * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2014, 2019 Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 package org.openjdk.bench.java.net;
    23 package org.openjdk.bench.java.net;
       
    24 
       
    25 import org.openjdk.jmh.annotations.Benchmark;
       
    26 import org.openjdk.jmh.annotations.BenchmarkMode;
       
    27 import org.openjdk.jmh.annotations.Mode;
       
    28 import org.openjdk.jmh.annotations.OutputTimeUnit;
       
    29 import org.openjdk.jmh.annotations.Param;
       
    30 import org.openjdk.jmh.annotations.Scope;
       
    31 import org.openjdk.jmh.annotations.Setup;
       
    32 import org.openjdk.jmh.annotations.State;
       
    33 import org.openjdk.jmh.annotations.TearDown;
    24 
    34 
    25 import java.io.IOException;
    35 import java.io.IOException;
    26 import java.io.InputStream;
    36 import java.io.InputStream;
    27 import java.io.OutputStream;
    37 import java.io.OutputStream;
    28 import java.net.InetAddress;
    38 import java.net.InetAddress;
    29 import java.net.ServerSocket;
    39 import java.net.ServerSocket;
    30 import java.net.Socket;
    40 import java.net.Socket;
    31 import java.net.SocketException;
    41 import java.util.ArrayList;
       
    42 import java.util.List;
       
    43 import java.util.concurrent.CountDownLatch;
       
    44 import java.util.concurrent.ThreadLocalRandom;
    32 import java.util.concurrent.TimeUnit;
    45 import java.util.concurrent.TimeUnit;
    33 
    46 
    34 import org.openjdk.jmh.annotations.BenchmarkMode;
       
    35 import org.openjdk.jmh.annotations.Benchmark;
       
    36 import org.openjdk.jmh.annotations.Mode;
       
    37 import org.openjdk.jmh.annotations.OutputTimeUnit;
       
    38 import org.openjdk.jmh.annotations.Scope;
       
    39 import org.openjdk.jmh.annotations.Setup;
       
    40 import org.openjdk.jmh.annotations.State;
       
    41 import org.openjdk.jmh.annotations.TearDown;
       
    42 
       
    43 /**
    47 /**
    44  * Tests the overheads of I/O API.
    48  * Benchmark socket read/write.
    45  * This test is known to depend heavily on network conditions and paltform.
    49  *
    46  */
    50  */
    47 @BenchmarkMode(Mode.Throughput)
    51 @BenchmarkMode(Mode.Throughput)
    48 @OutputTimeUnit(TimeUnit.MILLISECONDS)
    52 @OutputTimeUnit(TimeUnit.SECONDS)
    49 @State(Scope.Thread)
    53 @State(Scope.Thread)
    50 public class SocketReadWrite {
    54 public class SocketReadWrite {
    51 
    55 
    52     private OutputStream os;
    56     static final InetAddress address = InetAddress.getLoopbackAddress();
    53     private InputStream is;
    57     public static final int TIMEOUT = 10000;
    54     private ServerSocket ss;
    58 
    55     private Socket s1, s2;
    59     static class EchoServer implements Runnable {
    56     private ReadThread rt;
    60         // EchoServer is implemented to execute the same amount echo threads as benchmarking threads are running
       
    61 
       
    62         final ServerSocket ss;
       
    63         final int port;
       
    64         final CountDownLatch startedLatch;
       
    65         final int size;
       
    66         final boolean timeout;
       
    67         List<ServerThread> threads = new ArrayList<>();
       
    68         volatile boolean isDone = false;
       
    69 
       
    70         public EchoServer(CountDownLatch await, int size, boolean timeout) throws IOException {
       
    71             this.size = size;
       
    72             this.timeout = timeout;
       
    73             ss = new ServerSocket(0);
       
    74             port = ss.getLocalPort();
       
    75             this.startedLatch = await;
       
    76         }
       
    77 
       
    78         @Override
       
    79         public void run() {
       
    80             startedLatch.countDown();
       
    81             while (!isDone) {
       
    82                 try {
       
    83                     Socket s = ss.accept();
       
    84                     s.setTcpNoDelay(true);
       
    85                     if (timeout) {
       
    86                         s.setSoTimeout(TIMEOUT);
       
    87                     }
       
    88                     ServerThread st = new ServerThread(s, size);
       
    89                     threads.add(st);
       
    90                     new Thread(st).start();
       
    91                 } catch (IOException e) {
       
    92                     if (!isDone) {
       
    93                         e.printStackTrace();
       
    94                     }
       
    95                 }
       
    96             }
       
    97         }
       
    98 
       
    99         synchronized void close() throws IOException {
       
   100             if (!isDone) {
       
   101                 isDone = true;
       
   102                 ss.close();
       
   103                 for (ServerThread st : threads) {
       
   104                     st.close();
       
   105                 }
       
   106             }
       
   107         }
       
   108 
       
   109         static EchoServer instance = null;
       
   110 
       
   111         static synchronized EchoServer startServer(int size, boolean timeout) throws IOException {
       
   112             if (instance == null) {
       
   113                 CountDownLatch started = new CountDownLatch(1);
       
   114                 EchoServer s = new EchoServer(started, size, timeout);
       
   115                 new Thread(s).start();
       
   116                 try {
       
   117                     started.await(); // wait until server thread started
       
   118                 } catch (InterruptedException e) {
       
   119                     e.printStackTrace();
       
   120                 }
       
   121                 instance = s;
       
   122             }
       
   123             return instance;
       
   124         }
       
   125 
       
   126         static class ServerThread implements Runnable {
       
   127 
       
   128             final Socket s;
       
   129             final InputStream in;
       
   130             final OutputStream out;
       
   131             final int size;
       
   132             volatile boolean isDone = false;
       
   133 
       
   134             ServerThread(Socket s, int size) throws IOException {
       
   135                 this.s = s;
       
   136                 this.size = size;
       
   137                 in = s.getInputStream();
       
   138                 out = s.getOutputStream();
       
   139             }
       
   140 
       
   141             @Override
       
   142             public void run() {
       
   143                 byte[] a = new byte[size];
       
   144                 while (!isDone) {
       
   145                     try {
       
   146                         readN(a, size, this.in);
       
   147                         out.write(a);
       
   148                     } catch (IOException e) {
       
   149                         if (!isDone) {
       
   150                             e.printStackTrace();
       
   151                         }
       
   152                     }
       
   153                 }
       
   154             }
       
   155 
       
   156             public void close() throws IOException {
       
   157                 isDone = true;
       
   158                 s.close();
       
   159             }
       
   160 
       
   161         }
       
   162     }
       
   163 
       
   164     static void readN(byte[] array, int size, InputStream in) throws IOException {
       
   165         int nread = 0;
       
   166         while (size > 0) {
       
   167             int n = in.read(array, nread, size);
       
   168             if (n < 0) throw new RuntimeException();
       
   169             nread += n;
       
   170             size -= n;
       
   171         }
       
   172     }
       
   173 
       
   174     EchoServer server;
       
   175 
       
   176     @Param({"1", "1024", "8192", "64000", "128000"})
       
   177     public int size;
       
   178 
       
   179     @Param({"false", "true"})
       
   180     public boolean timeout;
       
   181 
       
   182     Socket s;
       
   183     InputStream in;
       
   184     OutputStream out;
       
   185     byte[] array;
    57 
   186 
    58     @Setup
   187     @Setup
    59     public void beforeRun() throws IOException {
   188     public void setup() throws IOException {
    60         InetAddress iaddr = InetAddress.getLocalHost();
   189         server = EchoServer.startServer(size, timeout);
    61 
   190         int port = server.port;
    62         ss = new ServerSocket(0);
   191         s = new Socket(address, port);
    63         s1 = new Socket(iaddr, ss.getLocalPort());
   192         s.setTcpNoDelay(true);
    64         s2 = ss.accept();
   193         if (timeout) {
    65 
   194             s.setSoTimeout(TIMEOUT);
    66         os = s1.getOutputStream();
   195             // 10 seconds times is quite large and never will happen (for microbenchmarking),
    67         is = s2.getInputStream();
   196             // but it's required since other paths inside SocketImpl are involved
    68 
   197         }
    69         rt = new ReadThread(is);
   198         in = s.getInputStream();
    70         rt.start();
   199         out = s.getOutputStream();
       
   200         array = new byte[size];
       
   201         ThreadLocalRandom.current().nextBytes(array);
    71     }
   202     }
    72 
   203 
    73     @TearDown
   204     @TearDown
    74     public void afterRun() throws IOException, InterruptedException {
   205     public void tearDown() throws IOException {
    75         os.write(0);
   206         server.close();
    76         os.close();
   207         s.close();
    77         is.close();
       
    78         s1.close();
       
    79         s2.close();
       
    80         ss.close();
       
    81         rt.join();
       
    82     }
   208     }
    83 
   209 
    84     @Benchmark
   210     @Benchmark
    85     public void test() throws IOException {
   211     public void echo() throws IOException {
    86         os.write((byte) 4711);
   212         out.write(array);
    87     }
   213         readN(array, size, in);
    88 
   214     }
    89     static class ReadThread extends Thread {
       
    90         private InputStream is;
       
    91 
       
    92         public ReadThread(InputStream is) {
       
    93             this.is = is;
       
    94         }
       
    95 
       
    96         public void run() {
       
    97             try {
       
    98                 while (is.read() > 0);
       
    99             } catch (SocketException ex) {
       
   100                 // ignore - most likely "socket closed", which means shutdown
       
   101             } catch (IOException e) {
       
   102                 e.printStackTrace();
       
   103             }
       
   104         }
       
   105     }
       
   106 
       
   107 }
   215 }