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