FIX Antenna Java 2.17.0 Results


Benchmarks were run against two different versions of FIX Antenna Java (2.15.27 and 2.17.0), against FIX Antenna Java 2.17.0 with different configurations and against FIX Antenna Java 2.27.0 and QuickFIX Java 1.6.3, and the results were compared in order to detect possible regressions. 


FIX Antenna Machine

  • Intel(R) Xeon(R) CPU E5-2687W v3 @ 3.10GHz  (2 CPU  Hyper-Trading Enabled, 20 Cores)
  • RAM 128 GB, 2133 MHz
  • NIC Solarflare Communications SFC9120 (Firmware-version: rx1 tx1)
  • Linux (CentOS 7.0.1406 kernel  3.10.0-123.el7.x86_64)
  • SolarFlare driver version:

Client Machine

  • Intel(R) Xeon(R) CPU E5-2643 v3 @ 3.40GHz (2 CPU Hyper-Trading Enabled, 24 Cores)
  • RAM 128 GB, 2133 MHz
  • NIC Solarflare Communications SFC9120 (Firmware-version: rx1 tx1)
  • Linux (CentOS 7.0.1406 kernel  3.10.0-123.el7.x86_64)
  • SolarFlare driver version:


FIX Antenna Java 2.17.0 

Nagle`s algorithm
Affinity NoYesYes
Message validation parametersvalidateCheckSum 

validateGarbledMessage ✔

Storage type
PersistentIn memoryIn memory
Queue type
PersistentIn memoryIn memory
Solarflare OpenOnload

Nagle's algorithm is the algorithm aimed to reduce the number of packets that need to be sent over the network. Nagle's algorithm works by combining a number of small outgoing messages and sending them all at once.

Affinity means that session threads are pinned to the specific CPU core.

Solarflare OpenOnload is the kernel bypass technique by Solarflare that is activated within the test.

The following description helps to choose the most relevant FIX Antenna Java configuration:

  • Balanced. It is a good starting point with balanced performance and security. Basic validation options are enabled to prevent corrupted message processing.
  • Optimized. It is the configuration aimed at maximum performance. All validation options as well as message persistence are disabled, so it has to be used only in a fully controlled environment. Also, affinity masks are used in this configuration.
  • Optimized.onload. The Solarflare OpenOnload technique is activated within the configuration and optimizes the TCP stack. However, the configuration may be applied only if a Solarflare Network interface controller is installed on the machine.






FIX Antenna Java 2.17.0 VS FIX Antenna Java 2.15.27

  • One acceptor session is configured on the FIX Antenna Java side.
  • One initiator session is configured on the client application side.

 The process:

  1. The client application connects to the FIX Antenna Java and sends 200000 FIX 4.2 messages at a rate of 50000 messages per second.
  2. FIX Antenna Java receives the messages and responds to the client application with the same message via the same TCP/IP connection (the same session).
  3. The client application collects the response time histogram.
  4. The process is repeated for each FIX Antenna Java version.

The response time measured by the client application is the difference between timestamps:

  • t1 - timestamp is taken right before sending a message to the socket
  • t2 - timestamp is taken right after receiving the same message from the socket (from the FIX Antenna Java)

So the round-trip time formula is: RTT = t2 - t1 and the measurement unit is microseconds.

The test scenario diagram:

The performance of the FIX Antenna Java 2.17.0 release is almost the same as the performance of the FIX Antenna Java 2.15.27 release. There is no performance degradation or improvement.

Performance value slightly differs to the nature of the system used to measure the performance.

The table below contains a single run one-to-one comparison and may have some differences compared to the graphic above.

FIXAJ 2.17.0, usecFIXAJ 2.15.27, usec

FIX Antenna Java 2.17.0 VS QuickFIX Java 1.6.3

The benchmark code was ported to QuickFIXJ:

Sender Host
public final class RoundTripTester extends ApplicationAdapter {
    private void sendMessage() throws IOException {
        workMessage.getHeader().setInt(MsgSeqNum.FIELD, workMessageSequence++);
        start = System.nanoTime();
    public void fromApp(Message message, SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
            long end = System.nanoTime();
            String type = message.getHeader().getString(MsgType.FIELD);
            if (workMessageType.equals(type)) {
                final long currentLatency = end - start;
                latencies[counter++] = currentLatency;
                if (limitEnabled) {
                    long nextSendTime = testStart + (counter * sendIntervalMsec);
                    while (true) {
                        long currentTime = System.currentTimeMillis();
                        long toSleep = nextSendTime - currentTime;
                        if (toSleep <= 0) {
                if (counter == NO_OF_MESSAGES) {
                    //print results
                } else {
            } else if (warmUpMessageType.equals(type)) {
                if(warmUpCounter == WARM_UP_CYCLE_COUNT){
          "Warm up cycle has been done");
                    testStart = System.currentTimeMillis();

Receiver Host
public final class RoundTripServer extends ApplicationAdapter {
    public void fromApp(Message message, SessionID sessionId) {
         try {
            String type = message.getHeader().getString(MsgType.FIELD);
            if("D".equals(type)) {
                executionReport.setString(ClientID.FIELD, message.getString(ClientID.FIELD));
                executionReport.setString(Price.FIELD, message.getString(Price.FIELD));
                executionReport.setString(OrderQty.FIELD, message.getString(OrderQty.FIELD));
                executionReport.setString(TransactTime.FIELD, message.getString(TransactTime.FIELD));
                executionReport.setInt(ExecID.FIELD, ++execID);
                executionReport.setInt(OrderID.FIELD, ++orderID);
                Session.sendToTarget(executionReport, sessionId);
            } else {
                Session.sendToTarget(message, sessionId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);

FIXAntenna Java Balanced

FIXAntenna Java Optimized

QuickFIXJ Default

QuickFIXJ Optimized


The only difference between default and optimized QuickFIXJ configurations is in storage type usage. The corresponding application argument is specified during performance test execution.

QuickFIXJ Default means that a Persistent storage type is used for this configuration.

QuickFIXJ Optimized means that no messages are persisted. This will force QFJ to always send GapFills instead of resending messages.