21 #include "core/jthread.hpp"
22 #include "core/latency_timestamps.hpp"
24 #include <boost/asio.hpp>
25 #include <boost/exception/diagnostic_information.hpp>
26 #include <boost/program_options.hpp>
30 using namespace libisimud;
31 using namespace libjmmcg;
33 int main(
int argc,
char const *
const *argv) {
35 using thread_t=libjmmcg::
ppd::jthread;
38 boost::program_options::options_description general(
39 "A simple client that repeatedly sends a fixed FIX-message to a link listening at a IPADDR:PORT combination. The executable name indicates the message version implemented. For details regarding the properties of the client see the documentation that came with the distribution. Note that Wireshark has a built-in FIX protocol: see the \"Analyze/Enabled Protocols...\" dialog in Wireshark or https://www.wireshark.org/docs/dfref/f/fix.html. Copyright © J.M.McGuiness, isimud@hussar.me.uk. http://libjmmcg.sf.net/ Distributed under the terms of the GPL v2.1.\n"+
exit_codes::to_string()+
"Arguments"
42 (
"help",
"Print this help message.")
43 (
"version",
"Print the build number of this program.")
45 boost::program_options::options_description client(
"FIX-translator options.");
47 (
"address",
boost::program_options::value<
boost::
asio::
ip::address>()->default_value(
boost::
asio::
ip::address_v4::loopback()),
"IP address (in v4 format; thus the network interface to which it is boundmo) to which the messages should be sent.")
48 (
"port",
boost::program_options::value<
unsigned short>()->required(),
"The port to which the messages should be sent.")
49 (
"processor",
boost::program_options::value<
unsigned short>()->required()->default_value(exchanges
::common
::thread_traits
::client_to_exchange_thread.core),
"The core to which the client should be bound.")
51 boost::program_options::options_description performance(
"Performance-monitoring options.");
52 performance.add_options()
53 (
"num_loops",
boost::program_options::value<
unsigned long>()->required()->default_value(20000),
"The number of times the fix message should be sent (and therefore received) in each batch.")
54 (
"loops_for_conv",
boost::program_options::value<
unsigned short>()->required()->default_value(500),
"The maximum number of times the batch should be run.")
55 (
"perc_conv_estimate",
boost::program_options::value<
double>()->required()->default_value(2.0),
"The maximum value of mean average-deviation to which the repeated runs of the batches should converge.")
57 performance.add_options()
60 boost::program_options::value<
unsigned long>()->required()->default_value(0UL),
61 "The number (positive-integer) of latency timings to reserve. This value must be greater than the total number of messages to be processed, otherwise the behaviour is undefined. Upon exit, these values will be written in CSV-format to a file named 'argv[0]+\"-%%%%%.PID.csv\"' (where each '%' is a random hexadecimal digit and PID is the current process id). This file shall be created in the current directory. If the value is zero, then the file shall not be created, no values will be stored, unlimited messages may be processed."
63 boost::program_options::options_description all(
"All options.");
64 all.add(general).add(client).add(performance);
65 boost::program_options::variables_map vm;
66 boost::program_options::store(
boost::program_options::parse_command_line(argc, argv, all), vm);
67 if (vm.count(
"help")) {
71 if (vm.count(
"version")) {
75 boost::program_options::notify(vm);
76 ppd::api_threading_traits<ppd::platform_api, ppd::sequential_mode>::set_backtrace_on_signal();
77 const std::size_t num_timestamps=vm[
"num_timings"].as<std::size_t>();
78 latency_timestamps timestamps
(num_timestamps
);
81 vm[
"address"].as<boost::asio::ip::address>(),
82 vm[
"port"].as<
unsigned short>(),
83 socket::socket_priority::high,
84 vm[
"processor"].as<
unsigned short>(),
87 std::clog<<sender<<
std::endl;
88 std::pair<fix_client_t::timed_results_t,
bool> results;
89 thread_t collect_stats(
90 [&sender, &vm, &results]() {
91 results=sender.in_order_tx_rx_stats(
92 vm[
"num_loops"].as<
unsigned long>(),
93 vm[
"loops_for_conv"].as<
unsigned short>(),
94 vm[
"perc_conv_estimate"].as<
double>()
98 thread_t::thread_traits::set_kernel_affinity(
99 thread_t::thread_traits::get_current_thread(),
100 thread_t::thread_traits::api_params_type::processor_mask_type(0)
102 thread_t::thread_traits::set_kernel_priority(
103 thread_t::thread_traits::get_current_thread(),
104 thread_t::thread_traits::api_params_type::priority_type::idle
107 thread_t::thread_traits::sleep(0);
109 std::cout<<
"Exchange round-trip in-order time (microseconds)="<<results.first<<(results.second ?
" converged." :
" NOT converged.")<<std::endl;
110 std::clog<<sender<<
std::endl;
111 thread_t::thread_traits::raise(SIGQUIT);
115 }
catch (
std::exception
const &ex) {
116 std::cerr<<
"STL-derived exception. Details: "<<
boost::diagnostic_information(ex)<<
std::endl;
119 std::cerr<<
"Unknown exception."<<
std::endl;