Samples :: FIX Benchmark

Parsing Benchmark Sample

Description

This sample measures speed of message parsing.

Directory Contents

Item Description
conf/sample/MessageBenchmark.properties configuration file
conf/sample/*.txt test data files

Usage

  • Run the sample:
    • win: MessageBenchmark.bat
    • linux: MessageBenchmark.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.parser.Message;
import biz.onixs.util.PrecisionTimer;
import biz.onixs.util.settings.PropertyBasedSettings;
import biz.onixs.util.url.ResourceLoader;
import biz.onixs.util.url.ResourceLoaderUtil;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class MessageBenchmark {
    private static final Logger LOG = LoggerFactory.getLogger(MessageBenchmark.class);
    private static final ResourceLoader resourceLoader = ResourceLoaderUtil.DEFAULT_LOADER;
    private final PropertyBasedSettings settings = new PropertyBasedSettings("sample/MessageBenchmark.properties");

    private void run() {
        try {
            Engine.init(settings);
            final long messageNum = settings.getLong("MessageNum");
            final String messageFile = settings.getString("MessageFile");
            final InputStream inputStream = resourceLoader.getResource(messageFile);
            final String rawMsg = IOUtils.toString(inputStream, Charset.defaultCharset()).trim();
            final Message fixMsg = new Message(rawMsg);
            LOG.info("Raw message size: {} bytes", rawMsg.length());
            doBenchmark(new ParsingBenchmark(rawMsg.getBytes(StandardCharsets.ISO_8859_1), messageNum));
            doBenchmark(new AssembleBenchmark(fixMsg, messageNum));
        } catch (final Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (Engine.isInited()) {
                LOG.info("Engine shutdown...");
                Engine.getInstance().shutdown();
            }
        }
    }

    private static void doBenchmark(final Benchmark benchmark) {
        LOG.info("{}", benchmark.getName());
        benchmark.warmUp();
        final PrecisionTimer timer = new PrecisionTimer();
        benchmark.run();
        timer.stop();
        LOG.info("Performance: {} msgs/sec", timer.getItemsPerSecond(benchmark.getMessageNumber()));
    }

    public static void main(final String[] args) {
        LOG.info("Message Benchmark");
        LOG.info("The application is starting...");
        final MessageBenchmark messageBenchmark = new MessageBenchmark();
        messageBenchmark.run();
    }
}

The following classes are used in the sample:

import biz.onixs.fix.parser.Message;
import biz.onixs.fix.parser.MessageValidationFlags;

public class ParsingBenchmark extends Benchmark {
    private final Message message = new Message();
    private byte[] rawMsg;

    public ParsingBenchmark(final byte[] rawMsg, final long messageNum) {
        super(messageNum);
        this.rawMsg = rawMsg;
    }

    public byte[] getRawMsg() {
        return rawMsg;
    }

    public void setRawMsg(final byte[] rawMsg) {
        this.rawMsg = rawMsg;
    }

    @Override
    public void doAction() {
        message.init(rawMsg, rawMsg.length, MessageValidationFlags.None);
    }

    @Override
    public String getName() {
        return "Message parsing from byte array";
    }
}
import biz.onixs.fix.parser.Message;
import biz.onixs.util.ByteBuffer;

public class AssembleBenchmark extends Benchmark {
    private final ByteBuffer buffer = new ByteBuffer();
    private Message message;

    public AssembleBenchmark(final Message message, final long messageNum) {
        super(messageNum);
        this.message = message;
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(final Message message) {
        this.message = message;
    }

    @Override
    public void doAction() {
        buffer.clear();
        message.assemble(buffer);
    }

    @Override
    public String getName() {
        return "Message assembling to byte array";
    }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class Benchmark {
    private static final Logger LOG = LoggerFactory.getLogger(Benchmark.class);
    private long messageNumber;

    protected Benchmark(final long messageNumber) {
        this.messageNumber = messageNumber;
    }

    public long getMessageNumber() {
        return messageNumber;
    }

    public void setMessageNumber(final long messageNumber) {
        this.messageNumber = messageNumber;
    }

    public void warmUp() {
        LOG.info("Running warm-up...");
        cycle(messageNumber / 10L);
    }

    public void run() {
        LOG.info("Running benchmark...");
        cycle(messageNumber);
    }

    private void cycle(final long messageNum) {
        LOG.info("Message number: {}", messageNum);
        for (long l = 0L; l < messageNum; l++) {
            doAction();
        }
    }

    protected abstract void doAction();

    protected abstract String getName();
}

Throughput Acceptor and Initiator Benchmark Sample

Description

This sample is intended for measuring overall message transfer speed.

Directory Contents

Item Description
conf/sample/Throughput*.properties configuration files
conf/sample/*.txt test message data files

Usage

  • Run the throughput benchmark as 2 applications (acceptor and initiator) with no session storage:
    • win: t1-ThroughputAcceptorBenchmark.bat, t2-ThroughputInitiatorBenchmark.bat
    • linux: t1-ThroughputAcceptorBenchmark.sh, t2-ThroughputInitiatorBenchmark.sh
  • Run the throughput benchmark as a single application (acceptor and initiator) with no session storage:
    • win: ThroughputLoopbackBenchmark.bat
    • linux: ThroughputLoopbackBenchmark.sh
  • Run the throughput benchmark as 2 applications (acceptor and initiator) with file session storage:
    • win: t1-ThroughputAcceptorFileBenchmark.bat, t2-ThroughputInitiatorFileBenchmark.bat
    • linux: t1-ThroughputAcceptorFileBenchmark.sh, t2-ThroughputInitiatorFileBenchmark.sh
  • Run the throughput benchmark as a single application (acceptor and initiator) with no session storage:
    • win: ThroughputLoopbackFileBenchmark.bat
    • linux: ThroughputLoopbackFileBenchmark.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

The sources of the benchmark are available in the distributed package.

Latency Acceptor and Initiator Benchmark Sample

Description

This sample is intended for measuring message transfer latency.

Directory Contents

Item Description
conf/sample/Latency*.properties configuration files
conf/sample/*.txt test message data files

Usage

  • Run the latency benchmark as 2 applications (acceptor and initiator) with no session storage:
    • win: LatencyAcceptorBenchmark.bat, LatencyInitiatorBenchmark.bat
    • linux: LatencyAcceptorBenchmark.sh, LatencyInitiatorBenchmark.sh
  • Run the latency benchmark as a single application (acceptor and initiator) with no session storage:
    • win: LatencyLoopbackBenchmark.bat
    • linux: LatencyLoopbackBenchmark.sh
  • Run the latency benchmark as 2 applications (acceptor and initiator) with file session storage:
    • win: LatencyAcceptorBenchmark.bat, LatencyInitiatorBenchmark.bat
    • linux: LatencyAcceptorBenchmark.sh, LatencyInitiatorBenchmark.sh
  • Run the latency benchmark as a single application (acceptor and initiator) with file session storage:
    • win: LatencyLoopbackFileBenchmark.bat
    • linux: LatencyLoopbackFileBenchmark.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

The sources of the benchmark are available in the distributed package.

WarmUp Benchmark Sample

Description

This sample is intended for measuring latency before and after warm-up.

Usage

  • Run the warm-up benchmark:
    • win: WarmUpBenchmark.bat
    • linux: WarmUpBenchmark.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

import biz.onixs.fix.dictionary.Version;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.engine.EngineSettings;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.engine.storage.SessionStorageType;
import biz.onixs.fix.parser.Message;
import biz.onixs.util.PrecisionTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WarmUpBenchmark {
    private static final Logger LOG = LoggerFactory.getLogger(WarmUpBenchmark.class);
    private static final int MSG_NUM = 10;
    private static final int WARM_UP_MSG_NUM = 100000;
    private static final String PORT = "21001";
    private static final String RAW_MSG = "8=FIX.4.0\u00019=82\u000135=D\u000149=0\u000156=0\u000134=1\u0001" +
                                            "52=99990909-17:17:17\u000111=ClOrdID\u000121=1\u000155=IBM\u0001" +
                                            "54=1\u000138=1000\u000140=1\u000110=014\u0001";

    private void run() {
        final EngineSettings engineSettings = new EngineSettings()
                .setStorageFolder("storage-WarmUpBenchmark")
                .setListenPorts(PORT);
        final Engine engine = Engine.init(engineSettings);
        //
        final Message message = new Message(RAW_MSG);
        //
        LOG.info("");
        LOG.info("Warm Up Network");
        LOG.info("");
        {
            final SessionPair loopback = createLoopbackSessions("Warm-Up-Network");
            for (int i = 0; WARM_UP_MSG_NUM > i; ++i) {
                loopback.getInitiator().send(message);
            }
            //
            loopback.getInitiator().logout();
        }
        //
        LOG.info("");
        LOG.info("Warm Up Engine");
        LOG.info("");
        //
        {
            final SessionPair loopback = createLoopbackSessions("Warm-Up-Engine");
            //
            {
                final PrecisionTimer timer = new PrecisionTimer();
                for (int i = 0; MSG_NUM > i; i++) {
                    loopback.getInitiator().send(message);
                }
                timer.stop();
                LOG.info("");
                LOG.info("Latency before warmUp {} microseconds", timer.getMicroSecondsPerItem((long) MSG_NUM));
                LOG.info("");
            }
            {
                for (int i = 0; WARM_UP_MSG_NUM > i; ++i) {
                    loopback.getInitiator().warmUp(message);
                }
                final PrecisionTimer timer = new PrecisionTimer();
                for (int i = 0; MSG_NUM > i; i++) {
                    loopback.getInitiator().send(message);
                }
                timer.stop();
                LOG.info("");
                LOG.info("Latency with warmUp {} microseconds", timer.getMicroSecondsPerItem((long) MSG_NUM));
                LOG.info("");
            }

            LOG.info("Acceptor out. seq. number is {} and in. seq. number is {} ",
                    loopback.getAcceptor().getOutSeqNum(), loopback.getAcceptor().getInSeqNum());
            LOG.info("Initiator out. seq. number is {} and in. seq. number is {} ",
                    loopback.getInitiator().getOutSeqNum(), loopback.getInitiator().getInSeqNum());
            //
            loopback.getInitiator().logout();
        }
        //
        engine.shutdown();
    }

    private SessionPair createLoopbackSessions(final String prefix) {
        final String SenderCompID = prefix + 'A';
        final String TargetCompID = prefix + 'I';

        final SessionStorageType storageType = SessionStorageType.AsyncFileBased;

        final Session acceptor = new Session(SenderCompID, TargetCompID,Version.FIX42,
                false, storageType);
        acceptor.setInboundMessageReuse(true);
        acceptor.logonAsAcceptor();

        final Session initiator = new Session(TargetCompID, SenderCompID, Version.FIX42,
                false, storageType);
        initiator.setInboundMessageReuse(true);
        initiator.logonAsInitiator("localhost", Engine.getInstance().getSettings().getListenPorts()[0]);

        return new SessionPair(acceptor, initiator);
    }

    private static class SessionPair {
        private final Session acceptor;
        private final Session initiator;

        SessionPair(final Session acceptor, final Session initiator){
            this.acceptor = acceptor;
            this.initiator = initiator;
        }

        public Session getAcceptor(){
            return acceptor;
        }

        public Session getInitiator(){
            return initiator;
        }
    }

    public static void main(final String[] args) {
        try {
            LOG.info("WarmUpBenchmark is starting...");
            //
            final WarmUpBenchmark benchmark = new WarmUpBenchmark();
            benchmark.run();
        } catch (final Throwable throwable) {
            LOG.error(throwable.getMessage(), throwable);
        } finally {
            LOG.info("WarmUpBenchmark is stopped.");
        }
    }
}