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 } |