1187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler/* 2187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * Copyright 2017 The Android Open Source Project 3187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * 4187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * Licensed under the Apache License, Version 2.0 (the "License"); 5187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * you may not use this file except in compliance with the License. 6187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * You may obtain a copy of the License at 7187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * 8187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * http://www.apache.org/licenses/LICENSE-2.0 9187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * 10187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * Unless required by applicable law or agreed to in writing, software 11187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * distributed under the License is distributed on an "AS IS" BASIS, 12187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * See the License for the specific language governing permissions and 14187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * limitations under the License. 15187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler */ 16187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 17187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerpackage org.conscrypt; 18187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 19187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport static org.conscrypt.TestUtils.getProtocols; 20187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport static org.conscrypt.TestUtils.newTextMessage; 21187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 22187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.io.OutputStream; 23187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.util.concurrent.ExecutorService; 24187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.util.concurrent.Executors; 25187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.util.concurrent.Future; 26187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.util.concurrent.TimeUnit; 27187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.util.concurrent.atomic.AtomicBoolean; 28187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerimport java.util.concurrent.atomic.AtomicLong; 29187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 30187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler/** 31187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * Benchmark for comparing performance of client socket implementations. 32187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler */ 33187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittlerpublic final class ClientSocketBenchmark { 34187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler /** 35187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * Provider for the benchmark configuration 36187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler */ 37187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler interface Config { 38187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler SocketType socketType(); 39187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler int messageSize(); 40187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler String cipher(); 41486db2f3e9558c712c4ae394973631caedbe5256Nathan Mittler ChannelType channelType(); 42187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 43187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 44187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private ClientEndpoint client; 45187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private ServerEndpoint server; 46187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private byte[] message; 47187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private ExecutorService executor; 48187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private Future<?> sendingFuture; 49187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private volatile boolean stopping; 50187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 51187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private static final AtomicLong bytesCounter = new AtomicLong(); 52187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private AtomicBoolean recording = new AtomicBoolean(); 53187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 54187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler ClientSocketBenchmark(Config config) throws Exception { 55187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler recording.set(false); 56187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 57187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler message = newTextMessage(config.messageSize()); 58187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 59187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler // Always use the same server for consistency across the benchmarks. 60187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler server = SocketType.CONSCRYPT_ENGINE.newServer( 61486db2f3e9558c712c4ae394973631caedbe5256Nathan Mittler ChannelType.CHANNEL, config.messageSize(), getProtocols(), ciphers(config)); 62187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 63187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler server.setMessageProcessor(new ServerEndpoint.MessageProcessor() { 64187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler @Override 65187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler public void processMessage(byte[] inMessage, int numBytes, OutputStream os) { 66187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler if (recording.get()) { 67187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler // Server received a message, increment the count. 68187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler bytesCounter.addAndGet(numBytes); 69187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 70187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 71187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler }); 72187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler Future<?> connectedFuture = server.start(); 73187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 74187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler client = config.socketType().newClient( 75486db2f3e9558c712c4ae394973631caedbe5256Nathan Mittler config.channelType(), server.port(), getProtocols(), ciphers(config)); 76187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler client.start(); 77187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 78187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler // Wait for the initial connection to complete. 79187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler connectedFuture.get(5, TimeUnit.SECONDS); 80187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 81187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler executor = Executors.newSingleThreadExecutor(); 82187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler sendingFuture = executor.submit(new Runnable() { 83187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler @Override 84187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler public void run() { 85187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler Thread thread = Thread.currentThread(); 86187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler while (!stopping && !thread.isInterrupted()) { 87187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler client.sendMessage(message); 88187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 89187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 90187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler }); 91187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 92187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 93187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler void close() throws Exception { 94187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler stopping = true; 95187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler client.stop(); 96187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler server.stop(); 97187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler executor.shutdown(); 98187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler executor.awaitTermination(5, TimeUnit.SECONDS); 99187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler sendingFuture.get(5, TimeUnit.SECONDS); 100187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 101187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 102187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler /** 103187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * Simple benchmark for throughput. 104187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler */ 105187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler void throughput() throws Exception { 106187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler recording.set(true); 107187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler // Send as many messages as we can in a second. 108187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler Thread.sleep(1001); 109187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler recording.set(false); 110187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 111187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 112187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler static void reset() { 113187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler bytesCounter.set(0); 114187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 115187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 116187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler static long bytesPerSecond() { 117187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler return bytesCounter.get(); 118187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 119187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 120187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler private String[] ciphers(Config config) { 121187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler return new String[] {config.cipher()}; 122187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 123187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 124187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler /** 125187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler * A simple main for profiling. 126187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler */ 127187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler public static void main(String[] args) throws Exception { 128187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler ClientSocketBenchmark bm = new ClientSocketBenchmark(new Config() { 129187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler @Override 130187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler public SocketType socketType() { 131187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler return SocketType.CONSCRYPT_ENGINE; 132187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 133187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 134187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler @Override 135187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler public int messageSize() { 136187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler return 512; 137187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 138187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 139187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler @Override 140187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler public String cipher() { 141187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler return TestUtils.TEST_CIPHER; 142187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 143187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 144187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler @Override 145486db2f3e9558c712c4ae394973631caedbe5256Nathan Mittler public ChannelType channelType() { 146486db2f3e9558c712c4ae394973631caedbe5256Nathan Mittler return ChannelType.CHANNEL; 147187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 148187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler }); 149187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler 150187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler // Just run forever for profiling. 151187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler while (true) { 152187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler bm.throughput(); 153187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 154187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler } 155187f2399527021b4d6d76b755d93d1b5a8a15231Nathan Mittler} 156