OnixS C++ CME Market Data Handler  4.8.0.10
API documentation
Pages/LowLatencyBestPractices.md
Go to the documentation of this file.
1 \addtogroup low-latency-best-practices
2 
3 \brief Uncovers how to configure the Handler to achieve maximal
4 performance characteristics and lowest processing latency.
5 
6 The given topic uncovers how to configure the Handler in order to
7 achieve maximal performance characteristics and lowest processing
8 latency.
9 
10 \section configure-logging-for-low-latency Configuring Logging Subsystem
11 
12 Under normal conditions, the Handler logs important events and market data
13 transmitted by MDP into a log file. As far as logging entries represent
14 textual information, binary data like incoming market data packets are
15 encoded using base64-encoding before stored in a log. That adds extra time
16 to a processing cycle. Finally, if the Logger implementation stores its
17 data into a file, that may be a relatively slow operation.
18 
19 If the users want to eliminate slowdowns caused by flushing data to filesystem
20 and/or extra encoding operations, they can disable logging by binding instance
21 of the OnixS::CME::MDH::NullLogger class to the Handler. In such case
22 log events are not constructed by the Handler, and nothing is logged at
23 all.
24 
25 \section configure-threads-for-low-latency Turning Up Working Threads
26 
27 Market data processing is done asynchronously by using working threads.
28 Under normal conditions, threads are executed on any processor available
29 in the system. That may have negative influence on overall performance
30 due to unnecessary thread context switching.
31 
32 To avoid switching threads between processors, the Feed Engine as a
33 manager of working threads, allows to establish processor affinity for
34 each working thread:
35 
36 ~~~{.cpp}
37 
38 FeedEngineSettings feSettings1;
39 FeedEngineSettings feSettings2;
40 
41 // Scheduling Feed Engines to use different processors.
42 
43 feSettings1.threadAffinity().insert(1);
44 feSettings2.threadAffinity().insert(2);
45 
46 ~~~
47 
48 In addition to the ability to manipulate thread affinity for working
49 threads of the Feed Engine, it also provides a set of events triggered
50 by working threads at the beginning of processing and before ending
51 a processing loop. See \ref feed-engine-events for more information.
52 
53 With the help of working threads events, it is possible to perform
54 more advanced thread turning like updating thread priority:
55 
56 ~~~{.cpp}
57 
58 using namespace OnixS::CME::MDH;
59 
60 struct ThreadPriorityManager : FeedEngineListener
61 {
62  void onFeedEngineThreadBegin(const FeedEngine&)
63  {
64  SetThreadPriority(
65  GetCurrentThread(),
66  THREAD_PRIORITY_TIME_CRITICAL);
67  }
68 };
69 
70 FeedEngineSettings feSettings;
71 ThreadPriorityManager priorityManager;
72 
73 FeedEngine feedEngine(feSettings, &priorityManager);
74 
75 ~~~
76 
77 \section decreasing-data-waiting-time Decreasing Time Handler Spends on Waiting for Incoming Data
78 
79 When the Handler accomplishes processing of the previously
80 received market data, it initiates reception of new incoming
81 data if it is available in the feed. In reality, data packets
82 do not come each after another, but there's a certain time
83 interval between two neighbor packets. Pauses between incoming
84 packets cause the Feed Engine bound to the Handler to suspend
85 activities and sleep in a kernel while waiting for incoming data.
86 As a result, data and an execution code can be ejected from a
87 processor's cache. That brings to the fact that the next iteration
88 of processing loop is performed slower compare to the previous
89 one. The Feed Engine provides the
90 OnixS::CME::MDH::FeedEngineSettings::dataWaitTime parameter, which
91 value defines the time the Feed Engine spends in I/O operation while
92 waiting for incoming data. Reducing a value of the noted parameter
93 increases the number of wake-ups, and thus reduces the probability for
94 the Feed Engine to be thrown out of a processor's cache. If the parameter
95 is set to zero, the Feed Engine just checks for data availability, but
96 does not enter into a kernel for sleep. The drawback of reducing waiting
97 time is an increase of processor consumption (up to 100% in case of zero
98 parameter value).
99 
100 \section suppress-coping-for-low-latency Suppressing Market Data Copying
101 
102 Under normal conditions, the Handler effectively utilizes internal structures
103 used to keep incoming market data. Packets and messages are re-used once the
104 Handler processes the contained data. Therefore, no data is allocated during
105 a real-time market data processing.
106 
107 However, data may be copied within callbacks, which the Handler invokes
108 as listeners for various market data events. Thus, when a book is copied,
109 that assumes memory allocation and thus has a negative effect on performance
110 and latency. Copying should be minimized or strategies with preallocation
111 should be used to improve the results.
112 
113 For example, book snapshots can be constructed of a certain capacity capable
114 of storing a particular number of price levels. Constructing book snapshots with
115 initial capacity, sufficient to hold books of maximal possible depth, eliminates
116 reallocations.