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

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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.UTF_8), 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:

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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";
    }
}
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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";
    }
}
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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.");
        }
    }
}