/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.openhft.performance.tests.network; import net.openhft.chronicle.core.threads.EventLoop; import net.openhft.chronicle.core.threads.ThreadDump; import net.openhft.chronicle.network.AcceptorEventHandler; import net.openhft.chronicle.network.TCPRegistry; import net.openhft.chronicle.network.VanillaNetworkContext; import net.openhft.chronicle.network.connection.TcpChannelHub; import net.openhft.chronicle.threads.EventGroup; import org.jetbrains.annotations.NotNull; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SocketChannel; import java.util.Arrays; import static org.junit.Assert.assertEquals; /* On an i7-3970X Throughput was 2944.9 MB/s Loop back echo latency was 5.0/6.5 8/10 36/2248 us for 50/90 99/99.9 99.99/worst %tile compared with raw performance of Throughput was 3728.4 MB/s Loop back echo latency was 4.8/5.2 5.6/7.4 9.6us for 50/90 99/99.9 99.99%tile */ public class TcpServerEventGroupTest { private ThreadDump threadDump; public static void main(String[] args) throws IOException, InterruptedException { new TcpServerEventGroupTest().testStart(); } private static void testThroughput(@NotNull SocketChannel... sockets) throws IOException { System.out.println("Starting throughput test"); int bufferSize = 32 * 1024; ByteBuffer bb = ByteBuffer.allocateDirect(bufferSize); int count = 1, window = 0; long start = System.nanoTime(); while (System.nanoTime() - start < 10e9) { for (@NotNull SocketChannel socket : sockets) { bb.clear(); bb.putLong(0, count); if (socket.write(bb) < 0) throw new AssertionError("Socket " + socket + " unable to write in one go."); } if (count > window) for (@NotNull SocketChannel socket : sockets) { bb.clear(); while (socket.read(bb) >= 0 && bb.remaining() > 0) ; long ts2 = bb.getLong(0); if (count - window != ts2) assertEquals(count - window, ts2); } count++; } for (@NotNull SocketChannel socket : sockets) { try { do { bb.clear(); } while (socket.read(bb) > 0); } catch (ClosedChannelException expected) { } } long time = System.nanoTime() - start; System.out.printf("Throughput was %.1f MB/s%n", 1e3 * count * bufferSize * sockets.length / time); } private static void testLatency(@NotNull SocketChannel... sockets) throws IOException { System.out.println("Starting latency test"); int tests = 500000; @NotNull long[] times = new long[tests * sockets.length]; int count = 0; ByteBuffer bb = ByteBuffer.allocateDirect(64); for (int i = -50000; i < tests; i++) { long now = System.nanoTime(); for (@NotNull SocketChannel socket : sockets) { bb.clear(); socket.write(bb); if (bb.remaining() > 0) throw new AssertionError("Unable to write in one go."); } for (@NotNull SocketChannel socket : sockets) { bb.clear(); while (bb.remaining() > 0) if (socket.read(bb) < 0) throw new AssertionError("Unable to read in one go."); if (i >= 0) times[count++] = System.nanoTime() - now; } } Arrays.sort(times); System.out.printf("Loop back echo latency was %.1f/%.1f %,d/%,d %,d/%d us for 50/90 99/99.9 99.99/worst %%tile%n", times[times.length / 2] / 1e3, times[times.length * 9 / 10] / 1e3, times[times.length - times.length / 100] / 1000, times[times.length - times.length / 1000] / 1000, times[times.length - times.length / 10000] / 1000, times[times.length - 1] / 1000 ); } @Before public void threadDump() { threadDump = new ThreadDump(); } @After public void checkThreadDump() { threadDump.assertNoNewThreads(); } @Ignore("fix JIRA https://higherfrequencytrading.atlassian.net/browse/NET-13") @Test public void testStart() throws IOException, InterruptedException { @NotNull EventLoop eg = new EventGroup(true); eg.start(); TCPRegistry.createServerSocketChannelFor("TcpServerEventGroupTest"); @NotNull AcceptorEventHandler eah = new AcceptorEventHandler("TcpServerEventGroupTest", LegacyHanderFactory.legacyTcpEventHandlerFactory(nc -> new EchoHandler()), VanillaNetworkContext::new); eg.addHandler(eah); SocketChannel sc = TCPRegistry.createSocketChannel("TcpServerEventGroupTest"); sc.configureBlocking(false); testThroughput(sc); testLatency(sc); eg.stop(); TcpChannelHub.closeAllHubs(); TCPRegistry.reset(); } }