Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41e890b8 authored by Miguel Aranda's avatar Miguel Aranda
Browse files

Add retry logic and improve exception handling in ServerSocketPerfTest.

Bug: 429097283
Test: atest ServerSocketPerfTest
Change-Id: I1c252b87e63a8225c6ba7d3c9c87d51ae607b9ec
parent 3922d5a4
Loading
Loading
Loading
Loading
+102 −52
Original line number Original line Diff line number Diff line
@@ -16,14 +16,15 @@


package android.conscrypt;
package android.conscrypt;


import org.conscrypt.ChannelType;
import static org.conscrypt.TestUtils.getCommonProtocolSuites;
import static org.conscrypt.TestUtils.newTextMessage;
import static org.conscrypt.TestUtils.newTextMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;

import static org.junit.Assert.fail;
import android.conscrypt.ServerEndpoint.MessageProcessor;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import java.io.IOException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collection;
import java.util.List;
import java.util.List;
@@ -33,20 +34,17 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLong;

import javax.net.ssl.SSLException;
import android.conscrypt.ServerEndpoint.MessageProcessor;

import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;

import junitparams.JUnitParamsRunner;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import junitparams.Parameters;

import org.conscrypt.ChannelType;
import org.junit.Rule;
import org.junit.After;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;


/**
/**
 * Benchmark for comparing performance of server socket implementations.
 * Benchmark for comparing performance of server socket implementations.
@@ -55,7 +53,40 @@ import org.junit.runner.RunWith;
@LargeTest
@LargeTest
public final class ServerSocketPerfTest {
public final class ServerSocketPerfTest {


    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
    private static class RetryRule implements TestRule {
        private final int retryCount;

        RetryRule(int retryCount) {
            this.retryCount = retryCount;
        }

        @Override
        public Statement apply(Statement base, Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    Throwable caughtThrowable = null;
                    for (int i = 0; i < retryCount; i++) {
                        try {
                            base.evaluate();
                            return;
                        } catch (Throwable t) {
                            caughtThrowable = t;
                        }
                    }
                    if (caughtThrowable != null) {
                        throw caughtThrowable;
                    }
                }
            };
        }
    }

    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    @Rule
    public final TestRule retryRule = new RetryRule(3);


    /**
    /**
     * Provider for the benchmark configuration
     * Provider for the benchmark configuration
@@ -98,14 +129,14 @@ public final class ServerSocketPerfTest {
        }
        }
    }
    }


    public Collection getParams() {
    public Collection<Object[]> getParams() {
        final List<Object[]> params = new ArrayList<>();
        final List<Object[]> params = new ArrayList<>();
        for (EndpointFactory endpointFactory : EndpointFactory.values()) {
        for (EndpointFactory endpointFactory : EndpointFactory.values()) {
            for (ChannelType channelType : ChannelType.values()) {
            for (ChannelType channelType : ChannelType.values()) {
                for (int messageSize : ConscryptParams.messageSizes) {
                for (int messageSize : ConscryptParams.messageSizes) {
                    for (String cipher : ConscryptParams.ciphers) {
                    for (String cipher : ConscryptParams.ciphers) {
                        params.add(new Object[] {new Config(endpointFactory,
                        params.add(new Object[] {new Config(endpointFactory, endpointFactory,
                            endpointFactory, messageSize, cipher, channelType)});
                                messageSize, cipher, channelType)});
                    }
                    }
                }
                }
            }
            }
@@ -142,38 +173,42 @@ public final class ServerSocketPerfTest {


    private void setup(final Config config) throws Exception {
    private void setup(final Config config) throws Exception {
        recording.set(false);
        recording.set(false);
        stopping = false;


        byte[] message = newTextMessage(config.messageSize());
        byte[] message = newTextMessage(config.messageSize());


        final ChannelType channelType = config.channelType();
        socketPair.server = config.serverFactory().newServer(

                config.messageSize(), new String[] {"TLSv1.3", "TLSv1.2"}, ciphers(config));
        socketPair.server = config.serverFactory().newServer(config.messageSize(),
            new String[] {"TLSv1.3", "TLSv1.2"}, ciphers(config));
        socketPair.server.init();
        socketPair.server.init();
        socketPair.server.setMessageProcessor(new MessageProcessor() {
        socketPair.server.setMessageProcessor(new MessageProcessor() {
            @Override
            @Override
            public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
            public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
                try {
                try {
                try {
                    while (!stopping) {
                    while (!stopping) {
                        os.write(inMessage, 0, numBytes);
                        os.write(inMessage, 0, numBytes);
                    }
                    }
                    } finally {
                } catch (SSLException e) {
                        os.flush();
                    String msg = e.getMessage();
                    if (msg == null || !msg.contains("Connection reset by peer")) {
                        throw new RuntimeException(e);
                    }
                    }
                } catch (SocketException e) {
                    // Just ignore.
                } catch (IOException e) {
                } catch (IOException e) {
                    if (!stopping) {
                        throw new RuntimeException(e);
                        throw new RuntimeException(e);
                    }
                    }
                } finally {
                    try {
                        os.flush();
                    } catch (IOException e) {
                    }
                }
            }
            }
        });
        });


        Future<?> connectedFuture = socketPair.server.start();
        Future<?> connectedFuture = socketPair.server.start();


        // Always use the same client for consistency across the benchmarks.
        socketPair.client =
        socketPair.client = config.clientFactory().newClient(
                config.clientFactory().newClient(ChannelType.CHANNEL, socketPair.server.port(),
                ChannelType.CHANNEL, socketPair.server.port(),
                        new String[] {"TLSv1.3", "TLSv1.2"}, ciphers(config));
                        new String[] {"TLSv1.3", "TLSv1.2"}, ciphers(config));
        socketPair.client.start();
        socketPair.client.start();


@@ -191,16 +226,22 @@ public final class ServerSocketPerfTest {
                Thread thread = Thread.currentThread();
                Thread thread = Thread.currentThread();
                byte[] buffer = new byte[config.messageSize()];
                byte[] buffer = new byte[config.messageSize()];
                while (!stopping && !thread.isInterrupted()) {
                while (!stopping && !thread.isInterrupted()) {
                    try {
                        int numBytes = socketPair.client.readMessage(buffer);
                        int numBytes = socketPair.client.readMessage(buffer);
                        if (numBytes < 0) {
                        if (numBytes < 0) {
                            return;
                            return;
                        }
                        }
                        assertEquals(config.messageSize(), numBytes);
                        assertEquals(config.messageSize(), numBytes);


                    // Increment the message counter if we're recording.
                        if (recording.get()) {
                        if (recording.get()) {
                            bytesCounter.addAndGet(numBytes);
                            bytesCounter.addAndGet(numBytes);
                        }
                        }
                    } catch (Exception e) {
                        if (!stopping) {
                            fail("Client read failed: " + e.getMessage());
                        }
                        return;
                    }
                }
                }
            }
            }
        });
        });
@@ -208,16 +249,24 @@ public final class ServerSocketPerfTest {


    void close() throws Exception {
    void close() throws Exception {
        stopping = true;
        stopping = true;
        // Stop and wait for sending to complete.

        if (socketPair != null) {
            socketPair.close();
        }
        if (executor != null) {
        if (executor != null) {
            executor.shutdown();
            executor.shutdown();
            executor.awaitTermination(5, TimeUnit.SECONDS);
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        }
        }

        if (receivingFuture != null) {
        if (receivingFuture != null) {
            try {
                receivingFuture.get(5, TimeUnit.SECONDS);
                receivingFuture.get(5, TimeUnit.SECONDS);
            } catch (Exception e) {
                // Ignore exceptions here, as the task may have been interrupted.
            }
        }

        if (socketPair != null) {
            socketPair.close();
        }
        }
    }
    }


@@ -230,6 +279,7 @@ public final class ServerSocketPerfTest {
            while (state.keepRunning()) {
            while (state.keepRunning()) {
                recording.set(true);
                recording.set(true);
                while (bytesCounter.get() < config.messageSize()) {
                while (bytesCounter.get() < config.messageSize()) {
                    Thread.yield();
                }
                }
                bytesCounter.set(0);
                bytesCounter.set(0);
                recording.set(false);
                recording.set(false);