10c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler/* 20c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * Copyright 2017 The Android Open Source Project 30c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * 40c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * Licensed under the Apache License, Version 2.0 (the "License"); 50c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * you may not use this file except in compliance with the License. 60c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * You may obtain a copy of the License at 70c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * 80c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * http://www.apache.org/licenses/LICENSE-2.0 90c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * 100c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * Unless required by applicable law or agreed to in writing, software 110c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * distributed under the License is distributed on an "AS IS" BASIS, 120c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * See the License for the specific language governing permissions and 140c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * limitations under the License. 150c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler */ 160c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 170c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerpackage org.conscrypt.benchmarks; 180c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 1938ff07c8d63362d70a32938edb1bae9dea218f5bNathan Mittlerimport static org.conscrypt.testing.TestUtil.LOCALHOST; 20171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport static org.conscrypt.testing.TestUtil.getConscryptServerSocketFactory; 2138ff07c8d63362d70a32938edb1bae9dea218f5bNathan Mittlerimport static org.conscrypt.testing.TestUtil.getConscryptSocketFactory; 22171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport static org.conscrypt.testing.TestUtil.getJdkServerSocketFactory; 2338ff07c8d63362d70a32938edb1bae9dea218f5bNathan Mittlerimport static org.conscrypt.testing.TestUtil.getJdkSocketFactory; 2438ff07c8d63362d70a32938edb1bae9dea218f5bNathan Mittlerimport static org.conscrypt.testing.TestUtil.getProtocols; 2538ff07c8d63362d70a32938edb1bae9dea218f5bNathan Mittlerimport static org.conscrypt.testing.TestUtil.newTextMessage; 2638ff07c8d63362d70a32938edb1bae9dea218f5bNathan Mittlerimport static org.conscrypt.testing.TestUtil.pickUnusedPort; 270c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 280c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport java.io.IOException; 29171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport java.io.OutputStream; 3035b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport java.util.concurrent.ExecutorService; 3135b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport java.util.concurrent.Executors; 32171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport java.util.concurrent.Future; 3335b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport java.util.concurrent.TimeUnit; 3435b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport java.util.concurrent.atomic.AtomicBoolean; 3535b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport java.util.concurrent.atomic.AtomicLong; 360c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport javax.net.SocketFactory; 37171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport javax.net.ssl.SSLServerSocket; 38171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport javax.net.ssl.SSLServerSocketFactory; 390c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport javax.net.ssl.SSLSocket; 400c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport javax.net.ssl.SSLSocketFactory; 41c58d52620b66bfee6298d0ca58540fcdaa469c8cNathan Mittlerimport org.conscrypt.testing.TestClient; 42171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Rootimport org.conscrypt.testing.TestServer; 4335b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport org.openjdk.jmh.annotations.AuxCounters; 440c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport org.openjdk.jmh.annotations.Benchmark; 4535b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport org.openjdk.jmh.annotations.Fork; 4635b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerimport org.openjdk.jmh.annotations.Level; 470c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport org.openjdk.jmh.annotations.Param; 480c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport org.openjdk.jmh.annotations.Scope; 490c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport org.openjdk.jmh.annotations.Setup; 500c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport org.openjdk.jmh.annotations.State; 510c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittlerimport org.openjdk.jmh.annotations.TearDown; 520c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 530c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler/** 540c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * Benchmark for comparing performance of client socket implementations. All benchmarks use Netty 550c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * with tcnative as the server. 560c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler */ 570c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler@State(Scope.Benchmark) 5835b401854558f39cf694facb87ea28e250548dd2Nathan Mittler@Fork(1) 5935b401854558f39cf694facb87ea28e250548dd2Nathan Mittlerpublic class ClientSocketThroughputBenchmark { 6035b401854558f39cf694facb87ea28e250548dd2Nathan Mittler /** 6178a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root * Use an AuxCounter so we can measure that bytes per second as they accumulate without 6278a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root * consuming CPU in the benchmark method. 6335b401854558f39cf694facb87ea28e250548dd2Nathan Mittler */ 6435b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @AuxCounters 6535b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @State(Scope.Thread) 6678a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root public static class BytesPerSecondCounter { 6735b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @Setup(Level.Iteration) 6835b401854558f39cf694facb87ea28e250548dd2Nathan Mittler public void clean() { 6978a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root bytesCounter.set(0); 7035b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 7135b401854558f39cf694facb87ea28e250548dd2Nathan Mittler 7278a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root public long bytesPerSecond() { 7378a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root return bytesCounter.get(); 7435b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 7535b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 7635b401854558f39cf694facb87ea28e250548dd2Nathan Mittler 770c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler /** 780c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler * Various factories for SSL sockets. 790c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler */ 80c58d52620b66bfee6298d0ca58540fcdaa469c8cNathan Mittler public enum SslProvider { 81171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root JDK(getJdkSocketFactory(), getJdkServerSocketFactory()), 82171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root CONSCRYPT(getConscryptSocketFactory(false), getConscryptServerSocketFactory(false)), 83171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root CONSCRYPT_ENGINE(getConscryptSocketFactory(true), getConscryptServerSocketFactory(true)) { 840c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler @Override 85171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root SSLSocket newClientSocket(String host, int port, SSLSocketFactory socketFactory) throws IOException { 86171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root return (SSLSocket) socketFactory.createSocket( 87171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root SocketFactory.getDefault().createSocket(host, port), host, port, true); 880c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 890c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler }; 900c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 91171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root private final SSLSocketFactory clientSocketFactory; 92171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root private final SSLServerSocketFactory serverSocketFactory; 93171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root 94171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root SslProvider(SSLSocketFactory clientSocketFactory, SSLServerSocketFactory serverSocketFactory) { 95171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root this.clientSocketFactory = clientSocketFactory; 96171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root this.serverSocketFactory = serverSocketFactory; 97171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root } 98171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root 99171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root final SSLSocket newClientSocket(String host, int port, String cipher) { 1000c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler try { 101171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root SSLSocket sslSocket = newClientSocket(host, port, clientSocketFactory); 1020c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler sslSocket.setEnabledProtocols(getProtocols()); 1030c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler sslSocket.setEnabledCipherSuites(new String[] {cipher}); 1040c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler return sslSocket; 1050c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } catch (Exception e) { 1060c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler throw new RuntimeException(e); 1070c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 1080c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 1090c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 110171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root SSLSocket newClientSocket(String host, int port, SSLSocketFactory socketFactory) throws IOException { 111171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root return (SSLSocket) socketFactory.createSocket(host, port); 112171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root } 113171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root 114171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root final SSLServerSocket newServerSocket(String cipher) { 115171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root try { 116171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root int port = pickUnusedPort(); 117171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root SSLServerSocket sslSocket = 118171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root (SSLServerSocket) serverSocketFactory.createServerSocket(port); 119171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root sslSocket.setEnabledProtocols(getProtocols()); 120171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root sslSocket.setEnabledCipherSuites(new String[] {cipher}); 121171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root return sslSocket; 122171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root } catch (IOException e) { 123171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root throw new RuntimeException(e); 124171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root } 125171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root } 1260c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 1270c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 128c58d52620b66bfee6298d0ca58540fcdaa469c8cNathan Mittler @Param public SslProvider sslProvider; 1290c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 13035b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @Param({"64", "1024"}) public int messageSize; 1310c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 1329390a99b27d7c4234d060f284184a3ee87be1618Kenny Root @Param({"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"}) public String cipher; 1330c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 1340c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler private TestClient client; 135171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root private TestServer server; 1360c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler private byte[] message; 13735b401854558f39cf694facb87ea28e250548dd2Nathan Mittler private ExecutorService executor; 13835b401854558f39cf694facb87ea28e250548dd2Nathan Mittler private volatile boolean stopping; 13935b401854558f39cf694facb87ea28e250548dd2Nathan Mittler 14078a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root private static final AtomicLong bytesCounter = new AtomicLong(); 14135b401854558f39cf694facb87ea28e250548dd2Nathan Mittler private AtomicBoolean recording = new AtomicBoolean(); 1420c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 14335b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @Setup(Level.Trial) 1440c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler public void setup() throws Exception { 14535b401854558f39cf694facb87ea28e250548dd2Nathan Mittler recording.set(false); 14635b401854558f39cf694facb87ea28e250548dd2Nathan Mittler 1470c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler message = newTextMessage(messageSize); 1480c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 149171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root server = new TestServer(sslProvider.newServerSocket(cipher), messageSize); 150171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root server.setMessageProcessor(new TestServer.MessageProcessor() { 15135b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @Override 152171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root public void processMessage(byte[] inMessage, int numBytes, OutputStream os) { 15335b401854558f39cf694facb87ea28e250548dd2Nathan Mittler if (recording.get()) { 15435b401854558f39cf694facb87ea28e250548dd2Nathan Mittler // Server received a message, increment the count. 15578a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root bytesCounter.addAndGet(numBytes); 15635b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 15735b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 15835b401854558f39cf694facb87ea28e250548dd2Nathan Mittler }); 159171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root Future<?> connectedFuture = server.start(); 1600c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 161171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root client = new TestClient(sslProvider.newClientSocket(LOCALHOST, server.port(), cipher)); 1620c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler client.start(); 16335b401854558f39cf694facb87ea28e250548dd2Nathan Mittler 164171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root // Wait for the initial connection to complete. 165171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root connectedFuture.get(5, TimeUnit.SECONDS); 166171e29e7efffd0ec2b64d4410c1c709d63beee0aKenny Root 16735b401854558f39cf694facb87ea28e250548dd2Nathan Mittler executor = Executors.newSingleThreadExecutor(); 16835b401854558f39cf694facb87ea28e250548dd2Nathan Mittler executor.submit(new Runnable() { 16935b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @Override 17035b401854558f39cf694facb87ea28e250548dd2Nathan Mittler public void run() { 17135b401854558f39cf694facb87ea28e250548dd2Nathan Mittler Thread thread = Thread.currentThread(); 17235b401854558f39cf694facb87ea28e250548dd2Nathan Mittler while (!stopping && !thread.isInterrupted()) { 17335b401854558f39cf694facb87ea28e250548dd2Nathan Mittler client.sendMessage(message); 17435b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 17535b401854558f39cf694facb87ea28e250548dd2Nathan Mittler } 17635b401854558f39cf694facb87ea28e250548dd2Nathan Mittler }); 1770c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 1780c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 17935b401854558f39cf694facb87ea28e250548dd2Nathan Mittler @TearDown(Level.Trial) 1800c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler public void teardown() throws Exception { 18135b401854558f39cf694facb87ea28e250548dd2Nathan Mittler stopping = true; 1820c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler client.stop(); 1830c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler server.stop(); 18435b401854558f39cf694facb87ea28e250548dd2Nathan Mittler executor.shutdown(); 18535b401854558f39cf694facb87ea28e250548dd2Nathan Mittler executor.awaitTermination(5, TimeUnit.SECONDS); 1860c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 1870c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler 1880c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler @Benchmark 18978a2c40bd741f3e4572941756baae8cd3acbbafaKenny Root public final void throughput(BytesPerSecondCounter counter) throws Exception { 19035b401854558f39cf694facb87ea28e250548dd2Nathan Mittler recording.set(true); 19135b401854558f39cf694facb87ea28e250548dd2Nathan Mittler // No need to do anything, just sleep here. 19235b401854558f39cf694facb87ea28e250548dd2Nathan Mittler Thread.sleep(1001); 19335b401854558f39cf694facb87ea28e250548dd2Nathan Mittler recording.set(false); 1940c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler } 1950c6f7671f35af188bcfd7cf84f9c46f72a25ccffNathan Mittler} 196