From fb12d429cb613e070cb6e171897e743594c9cd64 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Fri, 19 Oct 2018 20:52:53 +0000 Subject: [PATCH 01/29] Added hedge traces to perf stats. --- .../orderman/orderman_utils/PerfTraceLog.cpp | 190 ++++++++++++++---- .../orderman/orderman_utils/PerfTraceLog.h | 4 +- .../perf_analysis/logs/quick_stats.sh | 2 +- 3 files changed, 150 insertions(+), 46 deletions(-) diff --git a/src/lib/orderman/orderman_utils/PerfTraceLog.cpp b/src/lib/orderman/orderman_utils/PerfTraceLog.cpp index 7b0131d01..2ee4e5163 100644 --- a/src/lib/orderman/orderman_utils/PerfTraceLog.cpp +++ b/src/lib/orderman/orderman_utils/PerfTraceLog.cpp @@ -13,11 +13,11 @@ #include #include #include +#include #include #include #include #include -#include namespace bts { @@ -78,24 +78,37 @@ auto create = "create table trace (" "order_key INTEGER," "md_sn INTEGER );"; -auto view = "create view requote_trace as select " - "version, " - "host, " - "build_type, " - "session_start," - "trace_time," - "order_key," - "(fix_socket_w-md) / 1000.0 total," - "(spreader_on_book - md) / 1000.0 md," - "(send_fix_buffer-spreader_on_book)/1000.0 spreader," - "(fix_socket_w-send_fix_buffer)/1000.0 fix " - "from " - "trace " - "where md<>0 and (md_src-md)<1000000"; +auto requote_trace_view = "drop view if exists requote_trace; " + "create view requote_trace as select " + "version, " + "host, " + "build_type, " + "session_start," + "trace_time," + "order_key," + "(fix_socket_w-md) / 1000.0 total," + "(spreader_on_book - md) / 1000.0 md," + "(send_fix_buffer-spreader_on_book)/1000.0 spreader," + "(fix_socket_w-send_fix_buffer)/1000.0 fix " + "from " + "trace " + "where md<>0 and (md_src-md)<1000000"; + +auto hedge_trace_view = + "drop view if exists hedge_trace; " + "CREATE VIEW hedge_trace as " + "select version, host, build_type, session_start,trace_time,order_key, " + "(fix_socket_w-fix_socket_r) / 1000.0 total, " + "(spreader_on_child_order_update - fix_socket_r) / 1000.0 fix_in, " + "(send_fix_buffer-spreader_on_child_order_update)/1000.0 spreader, " + "(fix_socket_w-send_fix_buffer)/1000.0 fix_out " + "from trace where fix_socket_r<>0 "; auto requote_query = "select * from requote_trace order by trace_time desc limit ?"; +auto hedge_query = "select * from hedge_trace order by trace_time desc limit ?"; + struct PerfTraceLog::PImpl { PImpl(std::string const &loc) : db(loc, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE), @@ -103,6 +116,7 @@ struct PerfTraceLog::PImpl { SQLite::Database db; std::unique_ptr insert_statement; std::unique_ptr requote_query_statement; + std::unique_ptr hedge_query_statement; tbb::concurrent_queue pending_traces; std::string session_start; std::mutex lock; @@ -116,12 +130,15 @@ PerfTraceLog::PerfTraceLog() : me() { LOG(persist, Warn, "{} database does not exist yet. Creating it ", std::string(me->db.getFilename())); me->db.exec(create); - me->db.exec(view); } + me->db.exec(requote_trace_view); + me->db.exec(hedge_trace_view); me->insert_statement = std::make_unique(me->db, insert); me->requote_query_statement = std::make_unique(me->db, requote_query); + me->hedge_query_statement = + std::make_unique(me->db, hedge_query); me->session_start = datetime::FIX_timestamp(datetime::local_now()); } catch (SQLite::Exception const &e) { auto msg = fmt::format("Unable to create {}. Error: {}", loc, @@ -219,7 +236,7 @@ std::string encode_number(SQLite::Column const &c) { } std::vector> -PerfTraceLog::get_latest_traces(size_t n) { +PerfTraceLog::get_latest_requote_traces(size_t n) { std::vector> result; std::lock_guard l(me->lock); @@ -252,7 +269,7 @@ PerfTraceLog::get_latest_traces(size_t n) { } me->requote_query_statement->reset(); } catch (SQLite::Exception const &e) { - auto msg = fmt::format("Unable to query {}. Error: {}", + auto msg = fmt::format("Unable to quote_traces {}. Error: {}", std::string(me->db.getFilename()), std::string(e.getErrorStr())); bts_assert_msg(false, msg); @@ -260,6 +277,46 @@ PerfTraceLog::get_latest_traces(size_t n) { return result; } +std::vector> +PerfTraceLog::get_latest_hedge_traces(size_t n) { + std::vector> result; + + std::lock_guard l(me->lock); + try { + me->hedge_query_statement->bind(1, (long long)n); + + while (me->hedge_query_statement->executeStep()) { + auto &row = result.emplace_back(); + row["version"] = + encode_string(me->hedge_query_statement->getColumn("version")); + row["host"] = + encode_string(me->hedge_query_statement->getColumn("host")); + row["build_type"] = + encode_string(me->hedge_query_statement->getColumn("build_type")); + row["session_start"] = encode_string( + me->hedge_query_statement->getColumn("session_start")); + row["trace_time"] = + encode_string(me->hedge_query_statement->getColumn("trace_time")); + + row["order_key"] = + encode_number(me->hedge_query_statement->getColumn("order_key")); + row["total"] = + encode_number(me->hedge_query_statement->getColumn("total")); + row["fix_in"] = encode_number(me->hedge_query_statement->getColumn("fix_in")); + row["spreader"] = + encode_number(me->hedge_query_statement->getColumn("spreader")); + row["fix_out"] = + encode_number(me->hedge_query_statement->getColumn("fix_out")); + } + me->hedge_query_statement->reset(); + } catch (SQLite::Exception const &e) { + auto msg = fmt::format("Unable to query hedge_traces. Error: {}", + std::string(e.getErrorStr())); + bts_assert_msg(false, msg); + } + return result; +} + namespace perf_stat { using Row = std::map; @@ -286,8 +343,8 @@ struct Session { } // namespace perf_stat -std::map -structure_traces(std::vector> "es) { +std::map structure_quote_traces( + std::vector> "es) { std::map result; @@ -322,32 +379,63 @@ structure_traces(std::vector> "es) { return result; } -void print_summary(std::ostream &ss, perf_stat::Summary const &s,bool last) { +std::map structure_hedge_traces( + std::vector> "es) { + + std::map result; + + for (auto &q : quotes) { + auto &session = result[q["session_start"]]; + if (session.start.empty()) { + session.start = q["session_start"]; + session.host = q["host"]; + session.version = q["version"]; + session.build_type = q["build_type"]; + } + for (auto st : {"total", "fix_in", "spreader", "fix_out"}) { + auto &summary = session.summaries[st]; + if (summary.name.empty()) + summary.name = st; + summary.values.push_back(std::stod(q[st])); + } + session.rows.push_back(q); + session.n_rows++; + } + + for (auto &session_kvp : result) + for (auto &stat_kvp : session_kvp.second.summaries) { + auto &summary = stat_kvp.second; + summary.min = stats::min(summary.values); + summary.max = stats::max(summary.values); + summary.median = stats::percentile(summary.values, 0.5); + summary.ninenty_nine = stats::percentile(summary.values, 0.99); + summary.stddev = stats::stdev(summary.values); + } + + return result; +} + +void print_summary(std::ostream &ss, perf_stat::Summary const &s, bool last) { ss << " { " << "\"value\":" << " \"" << s.name << "\"" - << ", \"min\":" << s.min - << ", \"max\":" << s.max - << ", \"median\":" << s.median - << ", \"ninenty_nine\":" << s.ninenty_nine + << ", \"min\":" << s.min << ", \"max\":" << s.max + << ", \"median\":" << s.median << ", \"ninenty_nine\":" << s.ninenty_nine << ", \"stdev\":" << s.stddev; if (!last) ss << " },\n"; else ss << " }\n"; - } -void print_row(std::ostream &ss, perf_stat::Row const &r,bool last) { +void print_row(std::ostream &ss, perf_stat::Row const &r, bool last) { ss << " { "; size_t i = 0; for (auto const &kvp : r) - if (kvp.first != "version" && - kvp.first != "host" && - kvp.first != "build_type" && - kvp.first != "session_start") { + if (kvp.first != "version" && kvp.first != "host" && + kvp.first != "build_type" && kvp.first != "session_start") { ss << "\"" << kvp.first << "\":" << kvp.second; - if (++i != r.size()-4) + if (++i != r.size() - 4) ss << ","; } if (!last) @@ -356,7 +444,7 @@ void print_row(std::ostream &ss, perf_stat::Row const &r,bool last) { ss << " }\n"; } -void print_session(std::ostream &ss, perf_stat::Session const &s,bool last) { +void print_session(std::ostream &ss, perf_stat::Session const &s, bool last) { ss << "{\n" << " \"session_name\": " << s.start << ",\n" << " \"host\": " << s.host << ",\n" @@ -365,15 +453,15 @@ void print_session(std::ostream &ss, perf_stat::Session const &s,bool last) { << " \"n_rows\": " << s.n_rows << ",\n"; ss << " \"summaries\":\n [\n"; - size_t i = 0; + size_t i = 0; for (auto &summaries_kvp : s.summaries) - print_summary(ss, summaries_kvp.second,++i == s.summaries.size()); + print_summary(ss, summaries_kvp.second, ++i == s.summaries.size()); ss << " ],\n"; ss << " \"rows\":\n [\n"; i = 0; for (auto &r : s.rows) - print_row(ss, r,++i == s.rows.size()); + print_row(ss, r, ++i == s.rows.size()); ss << " ]\n"; if (!last) ss << "},\n"; @@ -382,14 +470,28 @@ void print_session(std::ostream &ss, perf_stat::Session const &s,bool last) { } void PerfTraceLog::print_latest_traces(std::ostream &ss, size_t n) { - auto rows = get_latest_traces(n); - auto structured = structure_traces(rows); - - ss << "[\n"; - size_t i = 0; - for (auto &session_kvp : boost::adaptors::reverse(structured)) - print_session(ss, session_kvp.second, ++i == structured.size()); - ss << "]\n"; + { + auto rows = get_latest_requote_traces(n); + auto structured = structure_quote_traces(rows); + + ss << "{\n\"requotes\": [\n"; + size_t i = 0; + for (auto &session_kvp : boost::adaptors::reverse(structured)) + print_session(ss, session_kvp.second, ++i == structured.size()); + ss << "],\n"; + } + + { + auto rows = get_latest_hedge_traces(n); + auto structured = structure_hedge_traces(rows); + + ss << "\"hedges\": [\n"; + + size_t i = 0; + for (auto &session_kvp : boost::adaptors::reverse(structured)) + print_session(ss, session_kvp.second, ++i == structured.size()); + ss << "]\n}\n"; + } } } // namespace bts diff --git a/src/lib/orderman/orderman_utils/PerfTraceLog.h b/src/lib/orderman/orderman_utils/PerfTraceLog.h index 49cdd8e07..cac7aacb0 100644 --- a/src/lib/orderman/orderman_utils/PerfTraceLog.h +++ b/src/lib/orderman/orderman_utils/PerfTraceLog.h @@ -17,7 +17,9 @@ class PerfTraceLog { int persist_traces(); // return the N last traces - std::vector> get_latest_traces(size_t n=0); + std::vector> get_latest_requote_traces(size_t n=0); + std::vector> get_latest_hedge_traces(size_t n=0); + void print_latest_traces(std::ostream &,size_t n = 0); private: diff --git a/src/lib/orderman/perf_analysis/logs/quick_stats.sh b/src/lib/orderman/perf_analysis/logs/quick_stats.sh index cc0bc52f1..ccc12b7d9 100755 --- a/src/lib/orderman/perf_analysis/logs/quick_stats.sh +++ b/src/lib/orderman/perf_analysis/logs/quick_stats.sh @@ -3,7 +3,7 @@ if [ $# -ne 2 ]; then echo - echo " Syntax: quick_stats.sh tick_to_order|fill_to_order" + echo " Syntax: quick_stats.sh log_file tick_to_order|fill_to_order" echo exit 1 fi From df56c85e7b5397f725dffaa29c26e4dae600750a Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Sat, 20 Oct 2018 16:34:03 +0000 Subject: [PATCH 02/29] Added C string logging for fast logging of string literals. --- src/lib/logging/logging.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/logging/logging.h b/src/lib/logging/logging.h index e47e0587b..d7f4448c0 100644 --- a/src/lib/logging/logging.h +++ b/src/lib/logging/logging.h @@ -53,6 +53,15 @@ struct LoggerHandle { Logger *logger; }; +struct CharPtrWrapper +{const char* ptr;}; + +inline std::ostream& operator<<(std::ostream&s,CharPtrWrapper const&ptr) +{ + s << ptr.ptr; + return s; +} + extern thread_local LoggerHandle _thread_logger; void configure_logging(LoggingConfig const&cfg); void configure_logging(bts::config::Logging const&cfg,bts::config::ThreadGroupCfg const&); From 2db8d717d437a22166d1ca85c7374baf92fe4adf Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Sat, 20 Oct 2018 16:36:21 +0000 Subject: [PATCH 03/29] Added logging of mercury events to uncover performance problems. --- src/lib/mercury/broker/Broker.cpp | 35 ++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/lib/mercury/broker/Broker.cpp b/src/lib/mercury/broker/Broker.cpp index dd6bf4d9d..313ebffe7 100644 --- a/src/lib/mercury/broker/Broker.cpp +++ b/src/lib/mercury/broker/Broker.cpp @@ -4,6 +4,7 @@ #include "lib/mercury/topics/ITopic.h" #include "lib/utils/Puid.h" #include "lib/utils/bts_assert.h" +#include "lib/utils/bts_chrono.h" #include #include @@ -30,13 +31,15 @@ struct Broker::LocalSubFilter { struct Broker::StreamRec { StreamRec(Broker &owner, IRemoteBroker &src, StreamID sid, TopicPtr const &topic) - : owner(owner), local(false), src(&src), sid(sid), topic(topic), - local_subs(), external_subs(), sub_id(), + : owner(owner), local(false), src(&src), sid(sid), + topic_str(intern_topic_str(topic)), topic(topic), local_subs(), + external_subs(), sub_id(), synopsis_builder(topic->make_synopsis_builder()), topic_tag(topic->to_str()) {} StreamRec(Broker &owner, StreamID sid, TopicPtr const &topic) - : owner(owner), local(true), src(), sid(sid), topic(topic), local_subs(), + : owner(owner), local(true), src(), sid(sid), + topic_str(intern_topic_str(topic)), topic(topic), local_subs(), external_subs(), sub_id(), synopsis_builder(topic->make_synopsis_builder()), topic_tag(topic->to_str()) {} @@ -56,10 +59,21 @@ struct Broker::StreamRec { IRemoteBroker *neighbour; }; + char *intern_topic_str(TopicPtr const &topic) { + // this C string is used to make it possible to log topic names + // assynchronously, without copying strings around. we leak + // topic names, which isn't great, but performance oblige. + auto ts = topic->to_str(); + auto result = new char[ts.size() + 1]; + memcpy(result, ts.c_str(), ts.size() + 1); + return result; + } + Broker &owner; const bool local; IRemoteBroker *const src; const StreamID sid; + const char *topic_str; const TopicPtr topic; std::vector local_subs; @@ -337,15 +351,26 @@ void Broker::notify(BrokerID sender, StreamID sid, SubID ex_subid, Notification const &payload) { NoReenter nr(me->inside); #else -void Broker::notify(BrokerID , StreamID sid, SubID ex_subid, +void Broker::notify(BrokerID, StreamID sid, SubID ex_subid, Notification const &payload) { #endif auto &srec = me->streams[sid]; bts_assert_d(srec); bts_assert_d((srec->is_local() && sender == id()) || (!srec->is_local() && srec->src->id() == sender)); - if (srec->is_local() || srec->sub_id == ex_subid) + + if (srec->is_local() || srec->sub_id == ex_subid) { + + LOG(Mercury, Diag, "Started handling event {} on broker {}", + log::CharPtrWrapper{srec->topic_str}, me->my_id.value()); + auto start = Timer::now(); srec->notify(payload); + auto stop = Timer::now(); + + LOG(Mercury, Diag, "Finished handling event {} on broker {}. Time: {}ns", + log::CharPtrWrapper{srec->topic_str}, me->my_id.value(), + ns_diff(stop, start)); + } } void Broker::subscribe(BrokerID sender, SubID ex_subid, StreamID sid) { From 9cd2518853e3b83122da405228b6d92e59205c06 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Sat, 20 Oct 2018 16:40:14 +0000 Subject: [PATCH 04/29] Added do_work loop data to perf trace. --- .../jetfix/connection/SocketConnection.cpp | 19 +- src/lib/orderman/actors/MDSource.h | 10 +- src/lib/orderman/orderman_utils/PerfTrace.h | 1 + .../orderman/orderman_utils/PerfTraceLog.cpp | 166 +++++++++++------- .../orderman/orderman_utils/PerfTraceLog.h | 1 + 5 files changed, 123 insertions(+), 74 deletions(-) diff --git a/src/lib/jetfix/connection/SocketConnection.cpp b/src/lib/jetfix/connection/SocketConnection.cpp index bdbc462bb..ae1e8e52a 100644 --- a/src/lib/jetfix/connection/SocketConnection.cpp +++ b/src/lib/jetfix/connection/SocketConnection.cpp @@ -6,7 +6,6 @@ #include "lib/utils/TimeStamp.h" #include "lib/utils/bts_assert.h" #include "lib/utils/helper_macros.h" -#include "lib/orderman/orderman_utils/PerfTraceLog.h" #include #include @@ -127,14 +126,15 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size, if (trace.md.to_uint64()) { LOG(Latency, Info, - "perf_event:tick_to_order s2s_us:{} fix_socket_r:{} md:{} " + "perf_event:tick_to_order s2s_us:{} do_work_begin:{} fix_socket_r:{} " + "md:{} " "md_src:{} spreader_on_book:{} spreader_modify_order:{} " "spreader_on_child_order_update:{} " "order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{} " "send_fix_buffer:{}", - s2s.microseconds(), trace_cpy.fix_socket_r.to_uint64(), - trace_cpy.md.to_uint64(), trace_cpy.md_src.to_uint64(), - trace_cpy.spreader_on_book.to_uint64(), + s2s.microseconds(), trace_cpy.do_work_begin.to_uint64(), + trace_cpy.fix_socket_r.to_uint64(), trace_cpy.md.to_uint64(), + trace_cpy.md_src.to_uint64(), trace_cpy.spreader_on_book.to_uint64(), trace_cpy.spreader_modify_order.to_uint64(), trace_cpy.spreader_on_child_order_update.to_uint64(), trace_cpy.order_update.to_uint64(), trace_cpy.exe_gw.to_uint64(), @@ -145,14 +145,15 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size, if (trace.fix_socket_r.to_uint64()) { LOG(Latency, Info, - "perf_event:fill_to_order s2s_us:{} fix_socket_r:{} md:{} md_src:{} " + "perf_event:fill_to_order s2s_us:{} do_work_begin:{} fix_socket_r:{} " + "md:{} md_src:{} " "spreader_on_book:{} spreader_modify_order:{} " "spreader_on_child_order_update:{} " "order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{} " "send_fix_buffer:{} ", - s2s.microseconds(), trace_cpy.fix_socket_r.to_uint64(), - trace_cpy.md.to_uint64(), trace_cpy.md_src.to_uint64(), - trace_cpy.spreader_on_book.to_uint64(), + s2s.microseconds(), trace_cpy.do_work_begin.to_uint64(), + trace_cpy.fix_socket_r.to_uint64(), trace_cpy.md.to_uint64(), + trace_cpy.md_src.to_uint64(), trace_cpy.spreader_on_book.to_uint64(), trace_cpy.spreader_modify_order.to_uint64(), trace_cpy.spreader_on_child_order_update.to_uint64(), trace_cpy.order_update.to_uint64(), trace_cpy.exe_gw.to_uint64(), diff --git a/src/lib/orderman/actors/MDSource.h b/src/lib/orderman/actors/MDSource.h index 8bf0110a2..3b0336001 100644 --- a/src/lib/orderman/actors/MDSource.h +++ b/src/lib/orderman/actors/MDSource.h @@ -75,9 +75,11 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor { private: void on_poll() override { Book book; - PerfTrace trace; - auto start = Timer::now(); + PerfTrace trace; + auto start = utils::TimeStamp::now(); + trace.do_work_begin = start; + for (auto &h : _handles) { auto &handle = h.handle; if (handle.get_depth(h.last, std::tuple_size(), @@ -92,8 +94,8 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor { publish(_book_update, book, trace); } } - auto stop = Timer::now(); - _loop_timer->observe(ns_diff(stop, start)); + auto stop = utils::TimeStamp::now(); + _loop_timer->observe((start-stop).nanoseconds()); } struct HandleRecord { diff --git a/src/lib/orderman/orderman_utils/PerfTrace.h b/src/lib/orderman/orderman_utils/PerfTrace.h index 41f6d416d..de00a8200 100644 --- a/src/lib/orderman/orderman_utils/PerfTrace.h +++ b/src/lib/orderman/orderman_utils/PerfTrace.h @@ -7,6 +7,7 @@ namespace bts { class PerfTrace { public: + utils::TimeStamp do_work_begin; utils::TimeStamp fix_socket_r; utils::TimeStamp md ; utils::TimeStamp md_src ; diff --git a/src/lib/orderman/orderman_utils/PerfTraceLog.cpp b/src/lib/orderman/orderman_utils/PerfTraceLog.cpp index 2ee4e5163..e6ac1e32c 100644 --- a/src/lib/orderman/orderman_utils/PerfTraceLog.cpp +++ b/src/lib/orderman/orderman_utils/PerfTraceLog.cpp @@ -21,62 +21,75 @@ namespace bts { -auto insert = "insert into trace (" - "version," - "host," - "build_type," - "session_start," - "trace_time," - "fix_socket_r," - "md," - "md_src," - "spreader_on_book," - "spreader_on_child_order_update," - "order_update," - "exe_gw," - "fix_socket_w," - "spreader_modify_order," - "send_fix_buffer," - "order_key," - "md_sn" - ") values (" - ":version," - ":host," - ":build_type," - ":session_start," - ":trace_time," - ":fix_socket_r," - ":md," - ":md_src," - ":spreader_on_book," - ":spreader_on_child_order_update," - ":order_update," - ":exe_gw," - ":fix_socket_w," - ":spreader_modify_order," - ":send_fix_buffer," - ":order_key," - ":md_sn" - ")"; +auto current_schema_version = 2; -auto create = "create table trace (" - "version TEXT, " - "host TEXT, " - "build_type TEXT, " - "session_start TEXT," - "trace_time TEXT," - "fix_socket_r INTEGER," - "md INTEGER," - "md_src INTEGER," - "spreader_on_book INTEGER," - "spreader_on_child_order_update INTEGER," - "order_update INTEGER," - "exe_gw INTEGER," - "fix_socket_w INTEGER," - "spreader_modify_order INTEGER," - "send_fix_buffer INTEGER," - "order_key INTEGER," - "md_sn INTEGER );"; +auto insert_trace = "insert into trace (" + "version," + "host," + "build_type," + "session_start," + "trace_time," + "do_work_begin," + "fix_socket_r," + "md," + "md_src," + "spreader_on_book," + "spreader_on_child_order_update," + "order_update," + "exe_gw," + "fix_socket_w," + "spreader_modify_order," + "send_fix_buffer," + "order_key," + "md_sn" + ") values (" + ":version," + ":host," + ":build_type," + ":session_start," + ":trace_time," + ":do_work_begin," + ":fix_socket_r," + ":md," + ":md_src," + ":spreader_on_book," + ":spreader_on_child_order_update," + ":order_update," + ":exe_gw," + ":fix_socket_w," + ":spreader_modify_order," + ":send_fix_buffer," + ":order_key," + ":md_sn" + ")"; + +auto create_trace_table = "drop table if exists trace;create table trace (" + "version TEXT, " + "host TEXT, " + "build_type TEXT, " + "session_start TEXT," + "trace_time TEXT," + "do_work_begin INTEGER," + "fix_socket_r INTEGER," + "md INTEGER," + "md_src INTEGER," + "spreader_on_book INTEGER," + "spreader_on_child_order_update INTEGER," + "order_update INTEGER," + "exe_gw INTEGER," + "fix_socket_w INTEGER," + "spreader_modify_order INTEGER," + "send_fix_buffer INTEGER," + "order_key INTEGER," + "md_sn INTEGER );"; + +auto create_schema_version_table = + "create table schema_version(version INTEGER); insert into " + "schema_version(version) values(0);"; + +auto query_schema_version = "select version from schema_version limit 1"; +auto delete_version_record = "delete from schema_version;"; +auto update_version = "insert into schema_version(version) values(:version);"; auto requote_trace_view = "drop view if exists requote_trace; " "create view requote_trace as select " @@ -126,15 +139,25 @@ PerfTraceLog::PerfTraceLog() : me() { auto loc = init_storage_location(); try { me = std::make_unique(loc); - if (!me->db.tableExists("trace")) { + if (!me->db.tableExists("schema_version")) { LOG(persist, Warn, "{} database does not exist yet. Creating it ", std::string(me->db.getFilename())); - me->db.exec(create); + me->db.exec(create_schema_version_table); } - me->db.exec(requote_trace_view); - me->db.exec(hedge_trace_view); + + if (schema_out_of_date()) { + me->db.exec(create_trace_table); + me->db.exec(requote_trace_view); + me->db.exec(hedge_trace_view); + + SQLite::Statement(me->db, delete_version_record).exec(); + SQLite::Statement update_version_statement(me->db, update_version); + update_version_statement.bind(":version", current_schema_version); + update_version_statement.exec(); + } + me->insert_statement = - std::make_unique(me->db, insert); + std::make_unique(me->db, insert_trace); me->requote_query_statement = std::make_unique(me->db, requote_query); me->hedge_query_statement = @@ -195,6 +218,8 @@ void PerfTraceLog::store(std::vector const &traces) { datetime::FIX_timestamp( datetime::timestamp_to_ptime(t.fix_socket_r))); + me->insert_statement->bind(":do_work_begin", + (long long)t.do_work_begin.to_uint64()); me->insert_statement->bind(":fix_socket_r", (long long)t.fix_socket_r.to_uint64()); me->insert_statement->bind(":md", (long long)t.md.to_uint64()); @@ -227,6 +252,24 @@ void PerfTraceLog::store(std::vector const &traces) { } } +bool PerfTraceLog::schema_out_of_date() { + try { + SQLite::Statement query_schema_version_statement(me->db, + query_schema_version); + + while (query_schema_version_statement.executeStep()) { + int version = query_schema_version_statement.getColumn("version"); + return version != current_schema_version; + } + } catch (SQLite::Exception const &e) { + auto msg = fmt::format("Unable to query schema version in {}. Error: {}", + std::string(me->db.getFilename()), + std::string(e.getErrorStr())); + bts_assert_msg(false, msg); + } + return true; +} + std::string encode_string(SQLite::Column const &c) { return fmt::format("\"{}\"", std::string(c)); } @@ -302,7 +345,8 @@ PerfTraceLog::get_latest_hedge_traces(size_t n) { encode_number(me->hedge_query_statement->getColumn("order_key")); row["total"] = encode_number(me->hedge_query_statement->getColumn("total")); - row["fix_in"] = encode_number(me->hedge_query_statement->getColumn("fix_in")); + row["fix_in"] = + encode_number(me->hedge_query_statement->getColumn("fix_in")); row["spreader"] = encode_number(me->hedge_query_statement->getColumn("spreader")); row["fix_out"] = diff --git a/src/lib/orderman/orderman_utils/PerfTraceLog.h b/src/lib/orderman/orderman_utils/PerfTraceLog.h index cac7aacb0..8cb952fc7 100644 --- a/src/lib/orderman/orderman_utils/PerfTraceLog.h +++ b/src/lib/orderman/orderman_utils/PerfTraceLog.h @@ -27,6 +27,7 @@ class PerfTraceLog { std::unique_ptr me; std::string init_storage_location(); + bool schema_out_of_date(); void store(std::vector const &); }; From cbb638ff7aa03b8f410f8128f548672459144a09 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Sat, 20 Oct 2018 18:26:54 +0000 Subject: [PATCH 05/29] More perf logging. --- src/lib/mercury/broker/Broker.cpp | 4 +-- src/lib/orderman/actors/ExecutionGateway.cpp | 37 ++++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/lib/mercury/broker/Broker.cpp b/src/lib/mercury/broker/Broker.cpp index 313ebffe7..bec0c9033 100644 --- a/src/lib/mercury/broker/Broker.cpp +++ b/src/lib/mercury/broker/Broker.cpp @@ -361,13 +361,13 @@ void Broker::notify(BrokerID, StreamID sid, SubID ex_subid, if (srec->is_local() || srec->sub_id == ex_subid) { - LOG(Mercury, Diag, "Started handling event {} on broker {}", + LOG(Latency, Diag, "Started handling event {} on broker {}", log::CharPtrWrapper{srec->topic_str}, me->my_id.value()); auto start = Timer::now(); srec->notify(payload); auto stop = Timer::now(); - LOG(Mercury, Diag, "Finished handling event {} on broker {}. Time: {}ns", + LOG(Latency, Diag, "Finished handling event {} on broker {}. Time: {}ns", log::CharPtrWrapper{srec->topic_str}, me->my_id.value(), ns_diff(stop, start)); } diff --git a/src/lib/orderman/actors/ExecutionGateway.cpp b/src/lib/orderman/actors/ExecutionGateway.cpp index 3dffaefd4..a82315897 100644 --- a/src/lib/orderman/actors/ExecutionGateway.cpp +++ b/src/lib/orderman/actors/ExecutionGateway.cpp @@ -1,15 +1,16 @@ #include "ExecutionGateway.h" -#include "lib/logging/logging.h" -#include "lib/utils/TimeStamp.h" #include "lib/jetfix/codec/MessageDefinitions.h" +#include "lib/jetfix/common/OutFIX.h" #include "lib/jetfix/gateway/JetFIXGateway.h" +#include "lib/logging/logging.h" #include "lib/orderman/events/CancelRejectEvent.h" #include "lib/orderman/events/GatewayStatusChangeEvent.h" #include "lib/orderman/events/NewExecutionReportEvent.h" #include "lib/orderman/events/NewSecuritiesEvent.h" #include "lib/orderman/orderman_utils/fix_order_codec.h" #include "lib/tracing/bts_trace.h" -#include "lib/jetfix/common/OutFIX.h" +#include "lib/utils/TimeStamp.h" +#include "lib/utils/bts_chrono.h" #include @@ -18,17 +19,16 @@ namespace orderman { using namespace jetfix; - using JFGw = JetFIXGateway; struct ExecutionGateway::PImpl { - PImpl(config::JetFIX::Connection const &cfg,PerfTraceLog &log) - : gw(cfg,log), exe_report_pool(), state(State::WAITING_FOR_SECURITIES), + PImpl(config::JetFIX::Connection const &cfg, PerfTraceLog &log) + : gw(cfg, log), exe_report_pool(), state(State::WAITING_FOR_SECURITIES), securities(), securities_by_descriptor(), exe_report_stream(), gw_status_change_stream(), cancel_reject_stream(), gw_name(cfg.name()), - cfg(cfg) {} + cfg(cfg) {} JFGw gw; boost::object_pool exe_report_pool; @@ -43,8 +43,9 @@ struct ExecutionGateway::PImpl { config::JetFIX::Connection cfg; }; -ExecutionGateway::ExecutionGateway(config::JetFIX::Connection const &cfg,PerfTraceLog &log) - : me(new PImpl(cfg,log)) {} +ExecutionGateway::ExecutionGateway(config::JetFIX::Connection const &cfg, + PerfTraceLog &log) + : me(new PImpl(cfg, log)) {} ExecutionGateway::~ExecutionGateway() {} void ExecutionGateway::init() { @@ -114,10 +115,13 @@ void ExecutionGateway::on_securities( void ExecutionGateway::on_exe_report( const jetfix::fix::ExecutionReportMsg &msg) { + auto start = Timer::now(); OrderKey ok; SecurityKey sk; decode_clorid(msg.get(), &ok, &sk); + LOG(Latency, Info, "Started handling of execution report for order {}", + ok.value()); auto sec = me->securities[sk.value()]; if (!sec) @@ -190,7 +194,7 @@ void ExecutionGateway::on_exe_report( data->exec_type = api::orderman::ExecType(msg.get()); data->msg_seq_num = msg.get(); tracepoint(bts_trace, trace_order, - (char *)"ExecutionGateway.on_exe_report", 0, 0,0); + (char *)"ExecutionGateway.on_exe_report", 0, 0, 0); // copy data from fix msg to our structure if (msg.has()) @@ -239,14 +243,14 @@ void ExecutionGateway::on_exe_report( data->last_shares = msg.has() ? Quantity(msg.get()) : Quantity(0); - auto last_px_sec = data->leg_security? data->leg_security:sec; + auto last_px_sec = data->leg_security ? data->leg_security : sec; data->last_price = msg.has() ? securities::decode_exchange_price( *last_px_sec, Price(msg.get())) : Price(0); data->avg_price = msg.has() ? securities::decode_exchange_price( - *last_px_sec, Price(msg.get())) + *last_px_sec, Price(msg.get())) : Price(0); if (msg.has()) str_to(msg.get(), &data->exchange_fill_id); @@ -255,7 +259,10 @@ void ExecutionGateway::on_exe_report( data->msg = text_msg; auto trace = msg.trace(); trace.exe_gw = utils::TimeStamp::now(); - publish(me->exe_report_stream, data,trace); + publish(me->exe_report_stream, data, trace); + LOG(Latency, Info, + "Finished handling of execution report for order {}. {}ns", + ok.value(), ns_diff(Timer::now(), start)); } } @@ -306,11 +313,13 @@ void ExecutionGateway::on_outgoing_fix( mercury::Update const &msg) { if (msg.events) for (auto const &ev : *(msg.events)) { + LOG(Latency, Info, "on_outgoing_fix sn: {} ok: {}", ev.trace.md_sn, + ev.trace.order_key); tracepoint(bts_trace, trace_order, (char *)"on_outgoing_fix", 0, ev.trace.md_sn, 0); auto trace = ev.trace; trace.exe_gw = utils::TimeStamp::now(); - me->gw.send(trace,ev.msg); + me->gw.send(trace, ev.msg); me->gw.dispatch_events(); } } From 2c384af157b2a96404ebce894bb4c0bd8a9f4266 Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Fri, 26 Oct 2018 10:15:43 -0400 Subject: [PATCH 06/29] SPARK-1800: Add Hedge Traces --- src/data_files/files/perf_trace/index.html | 16 +- src/data_files/files/perf_trace/main.js | 219 ++++++++++++++------- 2 files changed, 164 insertions(+), 71 deletions(-) diff --git a/src/data_files/files/perf_trace/index.html b/src/data_files/files/perf_trace/index.html index 1367cca36..3e0e930c8 100644 --- a/src/data_files/files/perf_trace/index.html +++ b/src/data_files/files/perf_trace/index.html @@ -1,14 +1,14 @@ - BTS Spark Socket To Socket Requote Times + BTS Spark Socket To Socket Requote and Hedge Times @@ -47,7 +57,7 @@
-

Socket To Socket Requote Times

+

Socket To Socket Latencies

diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index e22374aa7..87b292c29 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -2,7 +2,9 @@ $( document ).ready(function (){ let urlParams = new URLSearchParams(window.location.search); num_rows = urlParams.get('r'); let show_rows = urlParams.get('showrows'); + let rows_of = urlParams.get('rowsof'); + //let trace_data_url = "./perf_trace_data"; let trace_data_url = "/perf_trace_data"; if(num_rows != null) { trace_data_url += "/" + num_rows; @@ -15,14 +17,29 @@ $( document ).ready(function (){ error: ajax_err, crossDomain: true }).done(function(result) { + if(show_rows != null) { - list_rows(show_rows, result); + if(rows_of === "quot") { + list_rows(show_rows, rows_of, result.requotes); + } + else { + list_rows(show_rows, rows_of, result.hedges); + } + } else { - if(result.length > 0){ - let summary_info = "

Host: " + result[0].host + "

"; + if(result.requotes.length > 0){ + let summary_info = "

Host: " + result.requotes[0].host + "


"; $("#output").html(summary_info); - $(result).each(display_session); + $(result.requotes).each(function (index, quot_val){ + $(result.hedges).each( function(index, hed_val){ + if(quot_val.session_name === hed_val.session_name) + { + display_session(quot_val, hed_val); + return false; + } + }); + }); } } @@ -30,29 +47,30 @@ $( document ).ready(function (){ }); -function list_rows(show_rows, data) { +function list_rows(show_rows, rows_of, data) { $.each(data, function(index, value){ if(value.session_name === show_rows){ let summary_info = ""; - summary_info += "" + - "" + - "" + - "" + - "" + - ""; + + summary_info += "" + $.each(value.rows[0], function(key, unval){ + if(key !== "trace_time" && key !== "total") + { + summary_info +=""; + } + }); + summary_info += ""; $.each(value.rows, function(key, val) { summary_info += ""; - console.log(val); - - summary_info += "" + - "" + - "" + - "" + - "" + - ""; - - + summary_info += ""; + $.each(value.rows[0], function(key, uval){ + if(key !== "trace_time" && key !== "total") + { + summary_info += ""; + } + }); + summary_info += ""; summary_info += ""; }); summary_info += "
Trace TimeOrder KeyMDSpreaderFixTotal
Trace Time" + format_title(key) + "Total
" + val.trace_time + "" + val.order_key + "" + val.md + "" + val.spreader + "" + val.fix + "" + val.total + "" + val.trace_time + "" + uval + "" + val.total + "
"; @@ -77,7 +95,26 @@ function ajax_err (jqXHR, textStatus,errorThrown) { function first_upper (str) { let ret_str = str[0].toUpperCase() + str.substring(1, str.length); - return ret_str + return ret_str; +} + +function format_title (str) +{ + let ret_str = ""; + + for(let i=0; i < str.length; i++) { + if(i === 0 || str[i-1] === "_") { + ret_str += str[i].toUpperCase(); + } + else if(str[i] === "_") { + ret_str += " "; + } + else { + ret_str += str[i]; + } + } + + return ret_str; } function generate_histogram(id, data) @@ -95,70 +132,116 @@ function generate_histogram(id, data) Plotly.newPlot(id, plot_data); } -function display_session (index, value) { - //console.log(value); - let session_info = "
    "; - session_info += "
  • Session: " + value.session_name + "
  • "; - session_info += "
  • Build Type: " + value.build_type + "
  • "; - session_info += "
  • Version: " + value.version + "
  • "; +function write_summary (histo_id, v) +{ + session_info = "
      "; + session_info += "
    • " + format_title(v.value) + "
    • "; + session_info += "
    • Min: " + v.min + "
    • "; + session_info += "
    • Median: " + v.median + "
    • "; + session_info += "
    • Max: " + v.max + "
    • "; + session_info += "
    • 99%: " + v.ninenty_nine + "
    • "; + session_info += "
    • Standard Deviation: " + v.stdev + "
    • "; + session_info += "
    "; + session_info += "
    " + + + return session_info; +} + +function display_session (quot_val, hed_val) { + + let session_info = ""; + session_info += ""; + + //column headers + session_info += "" + if(num_rows != null) { - session_info += "
  • Rows: " + value.n_rows + "
  • "; - } - else { - session_info += "
  • Rows: " + value.n_rows + "
  • "; - } + session_info += ""; + session_info += ""; + } + else { + session_info += ""; + session_info += ""; + } - $(value.summaries).each(function(i,v){ + $(quot_val.summaries).each(function(i,v){ if(v.value === "total") { - session_info += "
    • "; - session_info += "
    • " + first_upper(v.value) + "
    • "; - session_info += "
    • Min: " + v.min + "
    • "; - session_info += "
    • Median: " + v.median + "
    • "; - session_info += "
    • Max: " + v.max + "
    • "; - session_info += "
    • 99%: " + v.ninenty_nine + "
    • "; - session_info += "
    • Standard Deviation: " + v.stdev + "
    • "; - session_info += "
    "; - session_info += "
    " - session_info += "
  • "; - return false + session_info += ""; + return false } }); - $(value.summaries).each(function(i,v){ - if(v.value !== "total") { - session_info += "
    • "; - session_info += "
    • " + first_upper(v.value) + "
    • "; - session_info += "
    • Min: " + v.min + "
    • "; - session_info += "
    • Median: " + v.median + "
    • "; - session_info += "
    • Max: " + v.max + "
    • "; - session_info += "
    • 99%: " + v.ninenty_nine + "
    • "; - session_info += "
    • Standard Deviation: " + v.stdev + "
    • "; - session_info += "
    "; - session_info += "
    " - session_info += "
  • "; - } - }); + $(hed_val.summaries).each(function(i,v){ + if(v.value === "total") { + session_info += ""; + return false + } + }); - session_info += "
    "; + let loop_val = 0; + + if(quot_val.summaries.length >= hed_val.summaries.length ) { + loop_val = quot_val.summaries.length; + } + else { + loop_val = hed_val.summaries.length; + } + + for(let i = 0; i < loop_val; i++) { + if(quot_val.summaries[i].value !== "total") { + session_info += ""; + } + } + + session_info += "
    Session: " + quot_val.session_name + "
    "; + session_info += "Build Type: " + quot_val.build_type + "
    "; + session_info += "Version: " + quot_val.version + "

    RequotesHedges
    Rows: " + quot_val.n_rows + "Rows: " + head_val.n_rows + "
    Rows: " + quot_val.n_rows + "Rows: " + hed_val.n_rows + "
    "; + session_info += write_summary(quot_val.session_name + "-quot-" + v.value, v); + session_info += ""; + session_info += write_summary(hed_val.session_name + "-hed-" + v.value, v); + session_info += "
    "; + if (hed_val.summaries[i] !== undefined) { + session_info += write_summary(quot_val.session_name + "-quot-" + quot_val.summaries[i].value, quot_val.summaries[i]); + } + session_info += ""; + if (hed_val.summaries[i] !== undefined) { + session_info += write_summary(hed_val.session_name + "-hed-" + hed_val.summaries[i].value, hed_val.summaries[i]); + } + session_info += "

    "; $("#output").append(session_info); - let all_data = {}; + let quot_val_data = {}; - $(value.rows).each(function(i, row) { + $(quot_val.rows).each(function(i, row) { $.each(row, function(name, v) { - if(all_data[name] === undefined){ - all_data[name] = [v]; + if(quot_val_data[name] === undefined){ + quot_val_data[name] = [v]; } else { - all_data[name].push(v); + quot_val_data[name].push(v); } }); }); - //console.log(all_data); + let hed_val_data = {}; - $(value.summaries).each(function(i,v){ - generate_histogram(value.session_name + "-" + v.value, all_data[v.value]); + $(hed_val.rows).each(function(i, row) { + $.each(row, function(name, v) { + if(hed_val_data[name] === undefined){ + hed_val_data[name] = [v]; + } + else { + hed_val_data[name].push(v); + } + }); }); + $(quot_val.summaries).each(function(i,v){ + generate_histogram(quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); + }); + + $(hed_val.summaries).each(function(i,v){ + generate_histogram(hed_val.session_name + "-hed-" + v.value, hed_val_data[v.value]); + }); } \ No newline at end of file From 74f79a2f52e5745bbc76efa801443123dd37ff02 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Mon, 29 Oct 2018 17:56:44 +0000 Subject: [PATCH 07/29] Added a few utilities for perf testing. --- src/lib/orderman/orders/NativeOrder.cpp | 5 ++ src/lib/orderman/perf_analysis/lttng/trace.sh | 2 +- src/lib/utils/PBUtils.h | 3 + src/server/sparkd/cmds/PrintHedgeOrders.cpp | 62 +++++++++++++------ src/server/sparkd/cmds/QuickTest.cpp | 53 ++++------------ src/web/CMakeDeps.cmake | 2 +- 6 files changed, 64 insertions(+), 63 deletions(-) diff --git a/src/lib/orderman/orders/NativeOrder.cpp b/src/lib/orderman/orders/NativeOrder.cpp index b7abfcd07..be637b6d4 100644 --- a/src/lib/orderman/orders/NativeOrder.cpp +++ b/src/lib/orderman/orders/NativeOrder.cpp @@ -526,11 +526,16 @@ void NativeOrder::on_update(Price p, Quantity q, PerfTrace const &t) { me->update_quantity_bm = encoding.overwrite(me->update_quantity_bm, q.value(), quantity_sz()); + tracepoint(bts_trace, trace_order, (char *)"on_update.half_way", 0, + trace.md_sn, trace.order_key); + auto const &ts = me->services->get_time_str(); me->update_transact_time_bm = encoding.overwrite( me->update_transact_time_bm, &ts.value()[0], ts.value().size()); auto buffer = me->session_services->get_fix_buffer(); auto &stream = buffer->fix[0]; + tracepoint(bts_trace, trace_order, (char *)"on_update.before_new_msg", 0, + trace.md_sn, trace.order_key); auto &f = stream.new_msg(jetfix::MessageTypes::CancelReplace); f.append(me->update_encoding); stream.close(); diff --git a/src/lib/orderman/perf_analysis/lttng/trace.sh b/src/lib/orderman/perf_analysis/lttng/trace.sh index bcbda7576..f880e35d8 100755 --- a/src/lib/orderman/perf_analysis/lttng/trace.sh +++ b/src/lib/orderman/perf_analysis/lttng/trace.sh @@ -22,6 +22,6 @@ sleep $TRACE_DURATION lttng stop lttng destroy mkdir -p trace_data -babeltrace ~/lttng-traces/* > trace_data/raw_trace.txt +babeltrace --clock-seconds ~/lttng-traces/* > trace_data/raw_trace.txt diff --git a/src/lib/utils/PBUtils.h b/src/lib/utils/PBUtils.h index af760fd85..dff0d4da7 100755 --- a/src/lib/utils/PBUtils.h +++ b/src/lib/utils/PBUtils.h @@ -73,6 +73,9 @@ inline bool equal(google::protobuf::Timestamp const &t1, google::protobuf::Times return t1.seconds() == t2.seconds() && t1.nanos() == t2.nanos(); } +inline double to_double_time(google::protobuf::Timestamp const &t1) +{return t1.seconds() + t1.nanos()/1e9;} + #endif }}} diff --git a/src/server/sparkd/cmds/PrintHedgeOrders.cpp b/src/server/sparkd/cmds/PrintHedgeOrders.cpp index 3acf45c27..eb3cf8e32 100644 --- a/src/server/sparkd/cmds/PrintHedgeOrders.cpp +++ b/src/server/sparkd/cmds/PrintHedgeOrders.cpp @@ -1,36 +1,58 @@ #include "server/sparkd/cmds/PrintHedgeOrders.h" -#include "lib/persistence/SqliteStore.h" #include "lib/api/services/OrderService.pb.h" +#include "lib/persistence/SqliteStore.h" #include "lib/utils/PBUtils.h" namespace bts { namespace cmd { int PrintHedgeOrders::execute(std::vector const &) { - persistence::SqliteStore store("orders"); - auto all = store.retrieve_all()["orders"]; + persistence::SqliteStore order_store("orders"); + auto all_orders = order_store.retrieve_all()["orders"]; - std::cout << "order_key,time_to_completed" << "\n"; - api::orderman::OrderRecord rec; - for (auto const &kvp : all) - if (utils::pb::from_string(kvp.second, &rec)) { - auto &def = rec.def(); - auto &state = rec.state(); - if (rec.parent_key() && - def.custom_def().has_limit() && - def.sub_type() == api::orderman::OrderSubType::ORDER_SUB_TYPE_HEDGING_LEG) { - auto created = state.created().seconds()* 1e9 + state.created().nanos(); - auto updated = state.last_change().seconds()* 1e9 + state.last_change().nanos(); - std::cout << kvp.first << "," << (updated-created) / 1000 / 1000 / 1000 << "\n"; + std::map> fill_times; + persistence::SqliteStore fill_store("fills"); + auto all_fills = fill_store.retrieve_all()["fills"]; + for (auto const &kvp : all_fills) { + api::orderman::Fill fill_rec; + if (utils::pb::from_string(kvp.second, &fill_rec)) { + auto ts = utils::pb::to_double_time(fill_rec.timestamp()); + auto &p = fill_times[fill_rec.order_key()]; + auto &min_time = p.second; + if (min_time < ts) { + p.first = kvp.first; + min_time = ts; } } + } + + std::cout << "order_key,time_to_first_fill,fill_id" + << "\n"; + api::orderman::OrderRecord rec; + for (auto const &kvp : all_orders) + if (utils::pb::from_string(kvp.second, + &rec)) { + auto &def = rec.def(); + auto &state = rec.state(); + if (rec.parent_key() && def.custom_def().has_limit() && + def.sub_type() == + api::orderman::OrderSubType::ORDER_SUB_TYPE_HEDGING_LEG) { + auto create_ts = utils::pb::to_double_time(state.created()); + auto &first_fill = fill_times[rec.key()]; + auto delta = first_fill.second - create_ts; + if (first_fill.first.size()) + std::cout << kvp.first << "," << delta << "," + << first_fill.first << "\n"; + } + } + return 0; } -std::string PrintHedgeOrders::help(){ - return - "Print out order ids for all hedge orders" - "which were completed at least one second being created"; +std::string PrintHedgeOrders::help() { + return "Print out order ids for all hedge orders" + "which were completed at least one second being created"; } -}} +} // namespace cmd +} // namespace bts diff --git a/src/server/sparkd/cmds/QuickTest.cpp b/src/server/sparkd/cmds/QuickTest.cpp index c20dbedb6..f97740319 100644 --- a/src/server/sparkd/cmds/QuickTest.cpp +++ b/src/server/sparkd/cmds/QuickTest.cpp @@ -3,54 +3,25 @@ #include "lib/mercury/actors/PingPong.h" #include "lib/mercury/executor/Executor.h" +#include "lib/utils/thread_manager.h" #include namespace bts { namespace cmd { -void test_ping_pong_mercury2() -{ - using namespace mercury; - - Executor ex1; - Executor ex2; - - ex1.init_neighbours(std::vector {&ex2}); - ex2.init_neighbours(std::vector {&ex1}); - - ex1.spawn(); - //ex1.spawn(); - ex2.spawn(); - - auto t = std::thread([&ex2]() { - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(1, &cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - - while (true) - ex2.do_work(); - }); - - bts::sleep_for(2s); - - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(0, &cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - - while (true) { - ex1.do_work(); - bts::sleep_for(100ms); - } -} - - - int QuickTest::execute(std::vector const &) { - test_ping_pong_mercury2(); - return 0; + threading::configure_current_thread("busy_poll"); + std::set s; + for (int i = 0; i < 1<<23;i++) + s.insert(i); + + auto sum = 0; + for(;;) { + for (auto &b : s) + sum+=b; + } + return sum; } std::string QuickTest::help() { diff --git a/src/web/CMakeDeps.cmake b/src/web/CMakeDeps.cmake index 050dc8062..65f907171 100644 --- a/src/web/CMakeDeps.cmake +++ b/src/web/CMakeDeps.cmake @@ -1 +1 @@ -set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataAuxiliaryService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/cssstyle/scripts/run_tests.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs) \ No newline at end of file +set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataAuxiliaryService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs) \ No newline at end of file From bb82590e5ed32a395128543e1a73663d7c31acf6 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Mon, 29 Oct 2018 20:17:04 +0000 Subject: [PATCH 08/29] Added sim execution for globex securities, this should facilitate production testing --- .../api/service_helpers/AdminServiceUtils.cpp | 40 +++++++++++-------- src/web/CMakeDeps.cmake | 2 +- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/lib/api/service_helpers/AdminServiceUtils.cpp b/src/lib/api/service_helpers/AdminServiceUtils.cpp index 40b5bfdec..f9e5a4a7f 100644 --- a/src/lib/api/service_helpers/AdminServiceUtils.cpp +++ b/src/lib/api/service_helpers/AdminServiceUtils.cpp @@ -4,7 +4,10 @@ #include "lib/config/protos/cme_reference_data.pb.h" #include "lib/config/protos/jetfix.pb.h" #include "lib/config/config.h" +#include "lib/config/protos/system.pb.h" + #include +#include namespace bts{ namespace admin{ @@ -83,8 +86,7 @@ AdminServiceUtils::resolve_cme_connection(const bts::api::admin::AdminData& data const bts::api::admin::ExchangeConnection* AdminServiceUtils::resolve_sim_connection(const bts::api::admin::AdminData& data, const bts::api::admin::BTSAccount& account, - const bts::api::Security& sec){ - bts_assert(sec.exchange() == api::Venue::VENUE_SIM); + const bts::api::Security& ){ if(account.has_connections()) for (const std::string& conn_name : account.connections().exchange_connection_names()){ const bts::api::admin::ExchangeConnection* conn = find_connection(data, conn_name); @@ -100,24 +102,30 @@ AdminServiceUtils::resolve_connection(const bts::api::admin::AdminData& data, const bts::api::Security& sec){ const bts::api::admin::ExchangeConnection* rv = nullptr; switch(sec.exchange()){ - case api::Venue::VENUE_GLBX: - rv = resolve_cme_connection(data, account, sec); - break; - case api::Venue::VENUE_UNSET: - case api::Venue::VENUE_BTS: - case api::Venue::VENUE_SIM: + case api::Venue::VENUE_GLBX: { + auto deployment_type = + boost::to_lower_copy(config::get().type()); + rv = resolve_cme_connection(data, account, sec); + if (rv == nullptr && (deployment_type == "dev" || + deployment_type == "demo")) rv = resolve_sim_connection(data, account, sec); - break; - case api::Venue::VENUE_CBOE: - case api::Venue::VENUE_CBOECFE: - case api::Venue::VENUE_ICE: - case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_: + break; + } + case api::Venue::VENUE_UNSET: + case api::Venue::VENUE_BTS: + case api::Venue::VENUE_SIM: + rv = resolve_sim_connection(data, account, sec); + break; + case api::Venue::VENUE_CBOE: + case api::Venue::VENUE_CBOECFE: + case api::Venue::VENUE_ICE: + case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_: case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_: - rv = nullptr; - break; + rv = nullptr; + break; } return rv; -} +} //////////////////////////////////////////// // connection mutators ///////////////////// //////////////////////////////////////////// diff --git a/src/web/CMakeDeps.cmake b/src/web/CMakeDeps.cmake index 65f907171..050dc8062 100644 --- a/src/web/CMakeDeps.cmake +++ b/src/web/CMakeDeps.cmake @@ -1 +1 @@ -set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataAuxiliaryService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs) \ No newline at end of file +set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataAuxiliaryService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/cssstyle/scripts/run_tests.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs) \ No newline at end of file From f433a3163b2ed5808684e849e4cfe85604e0fe6a Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Tue, 30 Oct 2018 12:39:35 -0400 Subject: [PATCH 09/29] Fix rows layout --- src/data_files/files/perf_trace/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index 87b292c29..d1ec445a2 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -64,7 +64,7 @@ function list_rows(show_rows, rows_of, data) { $.each(value.rows, function(key, val) { summary_info += ""; summary_info += "" + val.trace_time + ""; - $.each(value.rows[0], function(key, uval){ + $.each(val, function(key, uval){ if(key !== "trace_time" && key !== "total") { summary_info += "" + uval + ""; From b69958007de12296c35e11771ace0286ca994275 Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Tue, 30 Oct 2018 13:22:20 -0400 Subject: [PATCH 10/29] Fixing typo that any other language would have called an error --- src/data_files/files/perf_trace/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index d1ec445a2..1d82508cd 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -160,7 +160,7 @@ function display_session (quot_val, hed_val) { if(num_rows != null) { session_info += "Rows: " + quot_val.n_rows + ""; - session_info += "Rows: " + head_val.n_rows + ""; + session_info += "Rows: " + hed_val.n_rows + ""; } else { session_info += "Rows: " + quot_val.n_rows + ""; From 3233187fd93477068e3edc2dfe3d234dca80d060 Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Wed, 31 Oct 2018 10:26:16 -0400 Subject: [PATCH 11/29] Improve perf trace ui handling of incomplete data --- src/data_files/files/perf_trace/main.js | 121 +++++++++++++++--------- 1 file changed, 75 insertions(+), 46 deletions(-) diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index 1d82508cd..ab930b494 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -28,19 +28,32 @@ $( document ).ready(function (){ } else { - if(result.requotes.length > 0){ - let summary_info = "

    Host: " + result.requotes[0].host + "


    "; + if((result.requotes.length + result.hedges.length) > 0) { + let useful_result = (result.requotes.length > 0 ? result.requotes : result.hedges); + let less_useful_result = (result.requotes.length === 0 ? result.requotes : result.hedges); + + let summary_info = "

    Host: " + useful_result[0].host + "


    "; + $("#output").html(summary_info); - $(result.requotes).each(function (index, quot_val){ - $(result.hedges).each( function(index, hed_val){ - if(quot_val.session_name === hed_val.session_name) - { - display_session(quot_val, hed_val); - return false; - } - }); + + $(useful_result).each(function (index, quot_val){ + if(less_useful_result.length > 0){ + $(less_useful_result).each( function(index, hed_val){ + if(quot_val.session_name === hed_val.session_name) + { + display_session(result.requotes[index], result.hedges[index]); + return false; + } + }); + } + else { + display_session(result.requotes[index], result.hedges[index]); + } }); } + else { + + } } }); @@ -149,63 +162,79 @@ function write_summary (histo_id, v) } function display_session (quot_val, hed_val) { + let safe_quot_val = (quot_val != undefined) ? quot_val : { + session_name: hed_val.session_name, + build_type: hed_val.build_type, + version: hed_val.version, + n_rows: 0, + total: 0, + summaries: [] + }; + let safe_hed_val = (hed_val != undefined) ? hed_val : { + session_name: quot_val.session_name, + build_type: quot_val.build_type, + version: quot_val.version, + n_rows: 0, + total: 0, + summaries: [] + }; let session_info = ""; - session_info += ""; + session_info += ""; //column headers session_info += "" if(num_rows != null) { - session_info += ""; - session_info += ""; + session_info += ""; + session_info += ""; } else { - session_info += ""; - session_info += ""; + session_info += ""; + session_info += ""; } - $(quot_val.summaries).each(function(i,v){ + session_info += ""; + session_info += write_summary(safe_quot_val.session_name + "-quot-" + v.value, v); return false } - }); + }); - $(hed_val.summaries).each(function(i,v){ - if(v.value === "total") { - session_info += ""; - return false - } - }); + session_info += ""; + session_info += ""; let loop_val = 0; - if(quot_val.summaries.length >= hed_val.summaries.length ) { - loop_val = quot_val.summaries.length; + if(safe_quot_val.summaries.length >= safe_hed_val.summaries.length ) { + loop_val = safe_quot_val.summaries.length; } else { - loop_val = hed_val.summaries.length; + loop_val = safe_hed_val.summaries.length; } for(let i = 0; i < loop_val; i++) { - if(quot_val.summaries[i].value !== "total") { session_info += ""; - } } session_info += "
    Session: " + quot_val.session_name + "
    "; - session_info += "Build Type: " + quot_val.build_type + "
    "; - session_info += "Version: " + quot_val.version + "

    Session: " + safe_quot_val.session_name + "
    "; + session_info += "Build Type: " + safe_quot_val.build_type + "
    "; + session_info += "Version: " + safe_quot_val.version + "

    RequotesHedges
    Rows: " + quot_val.n_rows + "Rows: " + hed_val.n_rows + "
    Rows: " + safe_quot_val.n_rows + "Rows: " + safe_hed_val.n_rows + "
    Rows: " + quot_val.n_rows + "Rows: " + hed_val.n_rows + "
    Rows: " + safe_quot_val.n_rows + "Rows: " + safe_hed_val.n_rows + "
    "; + $(safe_quot_val.summaries).each(function(i,v){ if(v.value === "total") { - session_info += "
    "; - session_info += write_summary(quot_val.session_name + "-quot-" + v.value, v); - session_info += ""; - session_info += write_summary(hed_val.session_name + "-hed-" + v.value, v); - session_info += "
    "; + + $(safe_hed_val.summaries).each(function(i,v){ + if(v.value === "total") { + session_info += write_summary(safe_hed_val.session_name + "-hed-" + v.value, v); + return false + } + }); + + session_info += "
    "; - if (hed_val.summaries[i] !== undefined) { - session_info += write_summary(quot_val.session_name + "-quot-" + quot_val.summaries[i].value, quot_val.summaries[i]); + if (safe_quot_val.summaries[i] !== undefined && safe_quot_val.summaries[i].value !== "total") { + session_info += write_summary(safe_quot_val.session_name + "-quot-" + safe_quot_val.summaries[i].value, safe_quot_val.summaries[i]); } session_info += ""; - if (hed_val.summaries[i] !== undefined) { - session_info += write_summary(hed_val.session_name + "-hed-" + hed_val.summaries[i].value, hed_val.summaries[i]); + if (safe_hed_val.summaries[i] !== undefined && safe_hed_val.summaries[i].value !== "total") { + session_info += write_summary(safe_hed_val.session_name + "-hed-" + safe_hed_val.summaries[i].value, safe_hed_val.summaries[i]); } session_info += "

    "; @@ -213,7 +242,7 @@ function display_session (quot_val, hed_val) { let quot_val_data = {}; - $(quot_val.rows).each(function(i, row) { + $(safe_quot_val.rows).each(function(i, row) { $.each(row, function(name, v) { if(quot_val_data[name] === undefined){ quot_val_data[name] = [v]; @@ -226,7 +255,7 @@ function display_session (quot_val, hed_val) { let hed_val_data = {}; - $(hed_val.rows).each(function(i, row) { + $(safe_hed_val.rows).each(function(i, row) { $.each(row, function(name, v) { if(hed_val_data[name] === undefined){ hed_val_data[name] = [v]; @@ -237,11 +266,11 @@ function display_session (quot_val, hed_val) { }); }); - $(quot_val.summaries).each(function(i,v){ - generate_histogram(quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); + $(safe_quot_val.summaries).each(function(i,v){ + generate_histogram(safe_quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); }); - $(hed_val.summaries).each(function(i,v){ - generate_histogram(hed_val.session_name + "-hed-" + v.value, hed_val_data[v.value]); - }); + $(safe_hed_val.summaries).each(function(i,v){ + generate_histogram(safe_hed_val.session_name + "-hed-" + v.value, hed_val_data[v.value]); + }); } \ No newline at end of file From 42afdc2994510cadcc0b7bb61322c5115de5b99a Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Fri, 2 Nov 2018 14:41:24 +0000 Subject: [PATCH 12/29] Added a bit more ordermanager perf instrumentation. --- src/lib/mercury/broker/Broker.cpp | 4 +- src/lib/mercury/broker/BrokerProxy.cpp | 1 + src/lib/mercury/broker/BrokerProxy.h | 15 +++++- .../actors/order_manager/OrderServicesData.h | 1 - src/lib/orderman/perf_analysis/load_data.py | 49 +++++++++++++++++++ 5 files changed, 65 insertions(+), 5 deletions(-) create mode 100755 src/lib/orderman/perf_analysis/load_data.py diff --git a/src/lib/mercury/broker/Broker.cpp b/src/lib/mercury/broker/Broker.cpp index bec0c9033..1aafd9755 100644 --- a/src/lib/mercury/broker/Broker.cpp +++ b/src/lib/mercury/broker/Broker.cpp @@ -367,9 +367,9 @@ void Broker::notify(BrokerID, StreamID sid, SubID ex_subid, srec->notify(payload); auto stop = Timer::now(); - LOG(Latency, Diag, "Finished handling event {} on broker {}. Time: {}ns", + LOG(Latency, Diag, "Finished handling event {} on broker {}. Time: {}us", log::CharPtrWrapper{srec->topic_str}, me->my_id.value(), - ns_diff(stop, start)); + us_diff(stop, start)); } } diff --git a/src/lib/mercury/broker/BrokerProxy.cpp b/src/lib/mercury/broker/BrokerProxy.cpp index ef763885c..9968ea385 100644 --- a/src/lib/mercury/broker/BrokerProxy.cpp +++ b/src/lib/mercury/broker/BrokerProxy.cpp @@ -7,6 +7,7 @@ namespace mercury { BrokerProxy::BrokerProxy(ILocalBroker &real_broker) : _real_broker(real_broker), _id(real_broker.id()), + _cycles(0), _outgoing(config::get().queue_size()), _incoming(config::get().queue_size()), _action_pool() {} diff --git a/src/lib/mercury/broker/BrokerProxy.h b/src/lib/mercury/broker/BrokerProxy.h index 85d189944..dcbb762b5 100644 --- a/src/lib/mercury/broker/BrokerProxy.h +++ b/src/lib/mercury/broker/BrokerProxy.h @@ -59,7 +59,7 @@ class BrokerProxy : public ILocalBroker { void local_unsubscribe(LocalSubID) override; // ILocalBroker - void drain() { _outgoing.drain();} + void drain() { _outgoing.drain(); } void schedule_action(std::function const &action); // these are just for performance, we want to allow for @@ -80,6 +80,7 @@ class BrokerProxy : public ILocalBroker { } void do_work() { + _cycles++; _outgoing.consume_all([this](BrokerMsg *m) { switch (m->msg_type) { case BrokerMsgType::ADD_NEIGHBOUR: @@ -101,6 +102,8 @@ class BrokerProxy : public ILocalBroker { _real_broker.unsubscribe(m->broker_id, m->sub_id, m->stream_id); break; case BrokerMsgType::NOTIFY: + LOG(Latency, Diag, "Notify broker {}. Cycles: {}", _id.value(), + _cycles); _real_broker.notify(m->broker_id, m->stream_id, m->sub_id, m->notification); break; @@ -111,9 +114,16 @@ class BrokerProxy : public ILocalBroker { case BrokerMsgType::LOCAL_UNSUBSCRIBE: _real_broker.local_unsubscribe(m->local_sub_id); break; - case BrokerMsgType::EXECUTE_ACTION: + case BrokerMsgType::EXECUTE_ACTION: { + auto start = Timer::now(); + LOG(Latency, Diag, "Executing lambda on broker {}", _id.value()); m->action(); + auto stop = Timer::now(); + LOG(Latency, Diag, + "Finished executing lambda on broker {}. Took: {}us", + _id.value(), us_diff(stop, start)); break; + } default: bts_assert(false); break; @@ -126,6 +136,7 @@ class BrokerProxy : public ILocalBroker { private: ILocalBroker &_real_broker; const BrokerID _id; + uint64_t _cycles; utils::GrowableSPSCQueue _outgoing; utils::GrowableSPSCQueue _incoming; boost::object_pool _action_pool; diff --git a/src/lib/orderman/actors/order_manager/OrderServicesData.h b/src/lib/orderman/actors/order_manager/OrderServicesData.h index b13513e63..07b10bf53 100644 --- a/src/lib/orderman/actors/order_manager/OrderServicesData.h +++ b/src/lib/orderman/actors/order_manager/OrderServicesData.h @@ -88,7 +88,6 @@ class OrderServicesData { std::unique_ptr> order_creation_subs; - mercury::Stream order_state_pub; mercury::Stream activate_order_pub; mercury::Stream update_order_pub; mercury::Stream cancel_order_pub; diff --git a/src/lib/orderman/perf_analysis/load_data.py b/src/lib/orderman/perf_analysis/load_data.py new file mode 100755 index 000000000..de32152ee --- /dev/null +++ b/src/lib/orderman/perf_analysis/load_data.py @@ -0,0 +1,49 @@ +#!/usr/bin/python3 + +import pandas as pd +import sqlite3 +import dateutil +from pathlib import Path + +# dt = dateutil.parser.parse('2018-10-23 16:35:01.566000') +# requotes = requotes[requotes.session_start == dt] +#samples = requotes.resample('2S',on='trace_time').mean() +#samples.plot() + +requotes = None +db_path = "%s/sparkdata/data/databases/perf_trace/perf_trace.sqlite" % str(Path.home()) +c = sqlite3.connect(db_path,uri = True) + +def load(): + raw_data = pd.read_sql_query("select * from trace;", c) + global requotes + + requotes = raw_data[(raw_data.order_update>0) ] + requotes = requotes.assign (total = (requotes.fix_socket_w - requotes.md) / 1000) + requotes = requotes.assign (md = (requotes.spreader_on_book - requotes.md) / 1000) + requotes = requotes.assign (spreader = (requotes.order_update - requotes.spreader_on_book) / 1000) + requotes = requotes.assign (native_order = (requotes.exe_gw - requotes.spreader_on_book) / 1000) + requotes = requotes.assign (fix = (requotes.fix_socket_w - requotes.exe_gw) / 1000) + requotes = requotes.assign (session_start = requotes.session_start.map(dateutil.parser.parse)) + requotes = requotes.assign (trace_time = requotes.trace_time.map(dateutil.parser.parse)) + + + requotes = requotes.drop(['fix_socket_w','spreader_modify_order','send_fix_buffer', + 'order_update','exe_gw','fix_socket_r','md_src','host', + 'order_key','version', + 'build_type', 'spreader_on_book', + 'do_work_begin', + 'spreader_on_child_order_update','md_sn'],axis=1) + + summary() + requotes + +def summary(): + grouped = requotes.groupby(requotes['session_start']) + counts = grouped.count()['total'] + medians = grouped.median() + medians['count'] = counts + print (medians) + +load() + From 6c0cc76773881b8729ade9f2bbbaa7de19004e4b Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Sun, 4 Nov 2018 22:14:14 +0000 Subject: [PATCH 13/29] Significantly improved engine performance when updating multiple orders. --- .../actors/order_manager/OrderManager.cpp | 160 +++++--- .../actors/order_manager/OrderManager.h | 33 +- .../actors/order_manager/OrderServices.h | 71 ++-- .../order_manager/OrderServicesData.cpp | 2 +- .../actors/order_manager/OrderServicesData.h | 11 +- src/lib/orderman/events/OutFIXMsgEvent.h | 6 +- src/lib/orderman/orders/NativeOrder.cpp | 61 +-- src/lib/orderman/orders/NativeOrder.h | 1 + src/lib/orderman/perf_analysis/load_data.py | 14 +- .../orderman/server/OrderServiceServer.cpp | 2 +- src/lib/utils/inplace_function.h | 361 ++++++++++++++++++ src/server/sparkd/cmds/Benchmark.cpp | 57 ++- 12 files changed, 628 insertions(+), 151 deletions(-) create mode 100644 src/lib/utils/inplace_function.h diff --git a/src/lib/orderman/actors/order_manager/OrderManager.cpp b/src/lib/orderman/actors/order_manager/OrderManager.cpp index 176dd1246..3338b7cf0 100644 --- a/src/lib/orderman/actors/order_manager/OrderManager.cpp +++ b/src/lib/orderman/actors/order_manager/OrderManager.cpp @@ -11,7 +11,9 @@ #include "lib/orderman/order_factory/OrderFactory.h" #include "lib/orderman/orders/Order.h" #include "lib/orderman/securities/ISecurityDB.h" +#include "lib/utils/inplace_function.h" +#include #include namespace bts { @@ -40,10 +42,15 @@ struct OrderManager::OrderInfo { }; struct OrderManager::PImpl { - PImpl(Actor &owner) : state(State::WAIT_ADMIN), services_data(owner) {} + PImpl(OrderManager &owner) : state(State::WAIT_ADMIN), services_data(owner) { + pending_order_events.reserve(1000); + } State state; std::unordered_map orders; + + std::vector pending_order_events; + mercury::Actor::SubHandle stored_order_sub; mercury::Actor::SubHandle stored_fills_sub; OrderServicesData services_data; @@ -192,66 +199,82 @@ void OrderManager::on_execution_report( } } +void OrderManager::queue_order_event(PendingOrderEvent const &event_handler) { + me->pending_order_events.push_back(event_handler); +} + void OrderManager::on_activate_order( const mercury::Update &m) { if (m.events) - for (auto const &ev : *m.events) { - auto order = ev.order; - auto k = order->key(); - bts_assert(me->orders.find(k) == me->orders.end()); - OrderInfo oi{*order, me->services_data}; - auto serv_ptr = oi.order_services.get(); - me->orders[k] = std::move(oi); - order->on_activate(ev.price, ev.quantity, *serv_ptr, ev.trace); - } + for (auto const &ev : *m.events) + queue_order_event(ev); +} + +void OrderManager::handle_order_event(ActivateOrderEvent const &ev) { + auto order = ev.order; + auto k = order->key(); + bts_assert(me->orders.find(k) == me->orders.end()); + OrderInfo oi{*order, me->services_data}; + auto serv_ptr = oi.order_services.get(); + me->orders[k] = std::move(oi); + order->on_activate(ev.price, ev.quantity, *serv_ptr, ev.trace); } void OrderManager::on_update_order(const mercury::Update &m) { if (m.events) - for (auto const &ev : *m.events) { - auto k = ev.key(); - auto it = me->orders.find(k); - if (it != me->orders.end()) - it->second.order->on_update(ev.price, ev.quantity, ev.trace); - else { - LOG(OrderMan, Error, - "Received an update request for an unknown order {}. " - "This should not happen and likely indicates a serious bug. ", - ev.key().value()); - } - } + for (auto const &ev : *m.events) + queue_order_event(ev); +} + +void OrderManager::handle_order_event(UpdateOrderEvent const &ev) { + auto k = ev.key(); + auto it = me->orders.find(k); + if (it != me->orders.end()) + it->second.order->on_update(ev.price, ev.quantity, ev.trace); + else { + LOG(OrderMan, Error, + "Received an update request for an unknown order {}. " + "This should not happen and likely indicates a serious bug. ", + ev.key().value()); + } } void OrderManager::on_cancel_order(const mercury::Update &m) { if (m.events) - for (auto const &ev : *m.events) { - auto k = ev.key(); - auto it = me->orders.find(k); - if (it != me->orders.end()) - it->second.order->on_cancel(ev.trace); - else { - LOG(OrderMan, Error, - "Received a cancel request for an unknown order {}. " - "This should not happen and likely indicates a serious bug. ", - ev.key().value()); - } - } + for (auto const &ev : *m.events) + queue_order_event(ev); +} + +void OrderManager::handle_order_event(CancelOrderEvent const &ev) { + auto k = ev.key(); + auto it = me->orders.find(k); + if (it != me->orders.end()) + it->second.order->on_cancel(ev.trace); + else { + LOG(OrderMan, Error, + "Received a cancel request for an unknown order {}. " + "This should not happen and likely indicates a serious bug. ", + ev.key().value()); + } } void OrderManager::on_crack_order(const mercury::Update &m) { if (m.events) - for (auto const &ev : *m.events) { - auto k = ev.key(); - auto it = me->orders.find(k); - if (it != me->orders.end()) - it->second.order->on_crack(ev.trace); - else { - LOG(OrderMan, Error, - "Received a crack request for an unknown order {}. " - "This should not happen and likely indicates a serious bug. ", - ev.key().value()); - } - } + for (auto const &ev : *m.events) + queue_order_event(ev); +} + +void OrderManager::handle_order_event(CrackOrderEvent const &ev) { + auto k = ev.key(); + auto it = me->orders.find(k); + if (it != me->orders.end()) + it->second.order->on_crack(ev.trace); + else { + LOG(OrderMan, Error, + "Received a crack request for an unknown order {}. " + "This should not happen and likely indicates a serious bug. ", + ev.key().value()); + } } void OrderManager::on_gateway_state( @@ -276,6 +299,13 @@ void OrderManager::on_timer(const mercury::Update &m) { if (m.events) for (auto ev : *m.events) me->services_data.last_timer_ev = ev; + + for (auto &osd : me->services_data.sessions) { + if (fix_buffer_pool_size > osd->free_buffers.size()) { + auto need = fix_buffer_pool_size - osd->free_buffers.size(); + publish(me->services_data.create_fix_req_pub, need, osd->cfg); + } + } } std::vector & @@ -338,6 +368,7 @@ void OrderManager::init_order_services() { // FIX output s->out_fix_pub = make_stream(gw_name); + reload_fix_buffer(*s); } // Order creation and maintenance @@ -359,7 +390,6 @@ void OrderManager::init_order_services() { [this](auto const &ev) { this->on_new_fix_buffer(ev); }); // Outputs - me->services_data.order_state_pub = make_stream(); me->services_data.activate_order_pub = make_stream(); me->services_data.update_order_pub = make_stream(); me->services_data.cancel_order_pub = make_stream(); @@ -370,7 +400,8 @@ void OrderManager::init_order_services() { me->services_data.create_fix_req_pub = make_stream(); me->services_data.md_request_pub = make_stream(); - me->services_data.settlement_request_pub= make_stream(); + me->services_data.settlement_request_pub = + make_stream(); me->services_data.report_order_state_pub = make_stream(); me->pub_ready = make_stream(); @@ -389,12 +420,43 @@ void OrderManager::init_order_services() { me->services_data.md_subs = std::make_unique>(*this, on_md_sub); me->services_data.settlement_subs = - std::make_unique>(*this,on_settlement_sub); + std::make_unique>( + *this, on_settlement_sub); me->services_data.time_subs = std::make_unique>(*this); me->services_data.order_creation_subs = std::make_unique>(*this); } +void OrderManager::on_poll() { + if (me->state == State::READY) { + for (size_t i = 0; i < me->pending_order_events.size(); i++) + me->pending_order_events[i](*this); + me->pending_order_events.clear(); + for (auto &osd : me->services_data.sessions) { + auto &fix_stream = osd->current_buffer->first_stream(); + if (fix_stream.n_msgs()) { + fix_stream.close(); + publish(osd->out_fix_pub, osd->current_buffer, osd->current_traces); + osd->current_traces.clear(); + reload_fix_buffer(*osd); + } + } + } +} + +void OrderManager::reload_fix_buffer(SessionServicesData &dt) { + if (dt.free_buffers.size()) { + dt.current_buffer = dt.free_buffers.back(); + dt.free_buffers.pop_back(); + } else { + LOG(OrderMan, Warn, + "Ran out of fix buffers in {}. Will allocate directly. " + "This will have an impact on performance", + dt.cfg.name()); + dt.current_buffer = std::make_shared(dt.cfg); + } +} + } // namespace orderman } // namespace bts diff --git a/src/lib/orderman/actors/order_manager/OrderManager.h b/src/lib/orderman/actors/order_manager/OrderManager.h index 78981cf34..8ef2f29e4 100644 --- a/src/lib/orderman/actors/order_manager/OrderManager.h +++ b/src/lib/orderman/actors/order_manager/OrderManager.h @@ -3,6 +3,13 @@ #include "lib/config/protos/jetfix.pb.h" #include "lib/jetfix/common/OutFIXPtr.h" #include "lib/mercury/actors/Actor.h" +#include "lib/mercury/actors/IPollableActor.h" +#include "lib/utils/inplace_function.h" +#include "lib/orderman/events/ActivateOrderEvent.h" +#include "lib/orderman/events/UpdateOrderEvent.h" +#include "lib/orderman/events/CancelOrderEvent.h" +#include "lib/orderman/events/CrackOrderEvent.h" + #include // fwd @@ -22,6 +29,7 @@ class StoredFillEvent; class CreateFIXBufferReplyEvent; class GatewayStatusChangeEvent; class NewAdminDataEvent; +struct SessionServicesData; } } @@ -49,13 +57,16 @@ namespace orderman { // - crack // - update -class OrderManager : public mercury::Actor { +class OrderManager : public mercury::Actor, + public mercury::IPollableActor +{ public: OrderManager(); ~OrderManager(); void init() override; private: + friend class OrderServices; void on_securities(const mercury::Update &); void on_fill_recovery(const mercury::Update &); void on_order_recovery(const mercury::Update &); @@ -70,6 +81,26 @@ class OrderManager : public mercury::Actor { void on_admin_data(const mercury::Update &); void init_order_services(); + + void on_poll() override; + + using PendingOrderEvent = stdext::inplace_function< + void(OrderManager &), + std::max({128ul, sizeof(ActivateOrderEvent), sizeof(UpdateOrderEvent), + sizeof(CancelOrderEvent), sizeof(CrackOrderEvent)})>; + + template + void queue_order_event(EV const&ev) { + queue_order_event(PendingOrderEvent( [ev] (auto &om) { + om.handle_order_event(ev); + })); + } + void queue_order_event(PendingOrderEvent const&ev); + void handle_order_event(ActivateOrderEvent const &); + void handle_order_event(UpdateOrderEvent const &); + void handle_order_event(CancelOrderEvent const &); + void handle_order_event(CrackOrderEvent const&); + void reload_fix_buffer(SessionServicesData &dt); std::vector &free_buffers(std::string const&); enum class State; diff --git a/src/lib/orderman/actors/order_manager/OrderServices.h b/src/lib/orderman/actors/order_manager/OrderServices.h index 4e50f804f..ac5826b57 100644 --- a/src/lib/orderman/actors/order_manager/OrderServices.h +++ b/src/lib/orderman/actors/order_manager/OrderServices.h @@ -3,10 +3,12 @@ #include "lib/api/services/OrderService.pb.h" #include "lib/jetfix/common/OutFIX.h" #include "lib/logging/logging.h" +#include "lib/orderman/actors/order_manager/OrderManager.h" #include "lib/orderman/actors/order_manager/OrderServicesData.h" #include "lib/orderman/governor/Governor.h" #include "lib/orderman/orderman_utils/EventStream.h" #include "lib/orderman/orders/Order.h" + #include namespace bts { @@ -15,69 +17,44 @@ namespace orderman { class SessionServices { public: - SessionServices(SessionServicesData &session_data, OrderServicesData &data) + SessionServices(SessionServicesData &session_data) : exe_reports(*session_data.exe_report_subs), cancel_rejects(*session_data.cancel_reject_subs), gateway_status(*session_data.gateway_status_subs), - _session_data(&session_data), _data(&data) {} + _session_data(&session_data) {} std::string const &session_name() const { return _session_data->session; } + config::JetFIX::Connection const &session_cfg() const { return _session_data->cfg; } - jetfix::OutFIXPtr get_fix_buffer() { - jetfix::OutFIXPtr result; - if (_session_data->free_buffers.size()) { - result = _session_data->free_buffers.back(); - _session_data->free_buffers.pop_back(); - } else { - LOG(OrderMan, Warn, - "Ran out of fix buffers in {}. Will allocate directly. " - "This will have an impact on performance", - _session_data->cfg.name()); - result = std::make_shared(_session_data->cfg); - } - return result; - } - - void refill_fix_buffer_pool() - { - if (fix_buffer_pool_size > _session_data->free_buffers.size()) { - auto need = fix_buffer_pool_size - _session_data->free_buffers.size(); - _data->owner.publish(_data->create_fix_req_pub, need, - _session_data->cfg); - } + void queue_fix(jetfix::MessageTypes mt, jetfix::FIXFragment const&f,PerfTrace const&trace) { + auto &stream = _session_data->current_buffer->first_stream(); + stream.new_msg(mt).append(f); + _session_data->current_traces.push_back(trace); } bool is_gateway_connected() const { return _session_data->gw_connected; } - - void send_fix_buffer(jetfix::OutFIXPtr const &fix, PerfTrace &trace) { - trace.send_fix_buffer = utils::TimeStamp::now(); - _data->owner.publish(_session_data->out_fix_pub, trace, fix); - } + Governor &governor() { return _session_data->governor; } EventStream exe_reports; EventStream cancel_rejects; EventStream gateway_status; - Governor &governor() { return _session_data->governor; } private: SessionServicesData *_session_data; - OrderServicesData *_data; }; class OrderServices { public: OrderServices(Order &owner, OrderServicesData &data) - : book_updates(*data.md_subs), - settlement_updates(*data.settlement_subs), - child_updates(*data.child_order_subs), - time_change(*data.time_subs), + : book_updates(*data.md_subs), settlement_updates(*data.settlement_subs), + child_updates(*data.child_order_subs), time_change(*data.time_subs), order_creations(*data.order_creation_subs), _owner(owner), _data(data), _sessions() { for (auto &sd : data.sessions) - _sessions.push_back(std::make_unique(*sd, data)); + _sessions.push_back(std::make_unique(*sd)); } EventStream book_updates; @@ -119,7 +96,7 @@ class OrderServices { bts_assert(false); } - void schedule_action(std::function const&action) { + void schedule_action(std::function const &action) { _data.owner.schedule_action(action); } @@ -136,29 +113,33 @@ class OrderServices { } friend class ChildOrder; + + template void queue_order_op(const OP &op) { + _data.owner.queue_order_event(op); + } void send_activate(Order &o, Price p, Quantity q, PerfTrace const &trace) { - _data.owner.publish(_data.activate_order_pub, o, p, q, trace); + queue_order_op(ActivateOrderEvent{o, p, q, trace}); } void send_activate(Order &o, Price p, Quantity q) { - _data.owner.publish(_data.activate_order_pub, o, p, q, PerfTrace()); + queue_order_op(ActivateOrderEvent{o, p, q, PerfTrace()}); } void send_update(OrderKey k, Price p, Quantity q, PerfTrace const &trace) { - _data.owner.publish(_data.update_order_pub, k, p, q, trace); + queue_order_op(UpdateOrderEvent{k, p, q, trace}); } void send_update(OrderKey k, Price p, Quantity q) { - _data.owner.publish(_data.update_order_pub, k, p, q, PerfTrace()); + queue_order_op(UpdateOrderEvent{k, p, q, PerfTrace()}); } void send_crack(OrderKey k, PerfTrace const &trace) { - _data.owner.publish(_data.crack_order_pub, k, trace); + queue_order_op(CrackOrderEvent{k, trace}); } void send_crack(OrderKey k) { - _data.owner.publish(_data.crack_order_pub, k, PerfTrace()); + queue_order_op(CrackOrderEvent{k, PerfTrace()}); } void send_cancel(OrderKey k, PerfTrace const &trace) { - _data.owner.publish(_data.cancel_order_pub, k, trace); + queue_order_op(CancelOrderEvent{k, trace}); } void send_cancel(OrderKey k) { - _data.owner.publish(_data.cancel_order_pub, k, PerfTrace()); + queue_order_op(CancelOrderEvent{k, PerfTrace()}); } Order &_owner; diff --git a/src/lib/orderman/actors/order_manager/OrderServicesData.cpp b/src/lib/orderman/actors/order_manager/OrderServicesData.cpp index b868f5ced..f074d502a 100644 --- a/src/lib/orderman/actors/order_manager/OrderServicesData.cpp +++ b/src/lib/orderman/actors/order_manager/OrderServicesData.cpp @@ -5,7 +5,7 @@ namespace bts { namespace orderman { -OrderServicesData::OrderServicesData(mercury::Actor &owner) +OrderServicesData::OrderServicesData(OrderManager &owner) : owner(owner), order_router(), order_factory(sec_db, order_router), last_timer_ev( Timer::now(), diff --git a/src/lib/orderman/actors/order_manager/OrderServicesData.h b/src/lib/orderman/actors/order_manager/OrderServicesData.h index 07b10bf53..13748a639 100644 --- a/src/lib/orderman/actors/order_manager/OrderServicesData.h +++ b/src/lib/orderman/actors/order_manager/OrderServicesData.h @@ -35,6 +35,7 @@ namespace bts { namespace orderman { +class OrderManager; struct ParentKey { OrderKey operator()(const OrderStateUpdateEvent &ev) { @@ -49,7 +50,9 @@ struct SessionServicesData { cfg(cfg), governor(cfg.max_order_msgs_per_window(), cfg.window_duration_msecs()) - {} + { + current_traces.reserve(1000); + } std::string session; std::vector free_buffers; @@ -65,12 +68,14 @@ struct SessionServicesData { gateway_status_subs; Governor governor; + jetfix::OutFIXPtr current_buffer; + std::vector current_traces; }; class OrderServicesData { public: - OrderServicesData(mercury::Actor &owner); - mercury::Actor &owner; + OrderServicesData(OrderManager &owner); + OrderManager &owner; securities::MapSecurityDB sec_db; OrderRouter order_router; Limiter limiter; diff --git a/src/lib/orderman/events/OutFIXMsgEvent.h b/src/lib/orderman/events/OutFIXMsgEvent.h index dd483643c..5b0556fba 100644 --- a/src/lib/orderman/events/OutFIXMsgEvent.h +++ b/src/lib/orderman/events/OutFIXMsgEvent.h @@ -21,12 +21,12 @@ public: // missed. using SynopsisPolicy = mercury::NoSynopsis; - OutFIXMsgEvent (PerfTrace trace, jetfix::OutFIXPtr const&fix) : - trace(trace), msg(fix) + OutFIXMsgEvent (jetfix::OutFIXPtr const&fix,std::vector const&traces) : + msg(fix),trace(traces[0]) {} + jetfix::OutFIXPtr msg; PerfTrace trace; - jetfix::OutFIXPtr msg; }; }} diff --git a/src/lib/orderman/orders/NativeOrder.cpp b/src/lib/orderman/orders/NativeOrder.cpp index be637b6d4..e9aa82549 100644 --- a/src/lib/orderman/orders/NativeOrder.cpp +++ b/src/lib/orderman/orders/NativeOrder.cpp @@ -384,18 +384,9 @@ void NativeOrder::on_activate(Price p, Quantity q, auto const &ts = services.get_time_str(); me->create_transact_time_bm = encoding.overwrite( me->create_transact_time_bm, &ts.value()[0], ts.value().size()); - auto buffer = me->session_services->get_fix_buffer(); - auto &stream = buffer->fix[0]; - auto &f = stream.new_msg(jetfix::MessageTypes::NewOrderSingle); - f.append(me->create_encoding); - stream.close(); - - // Send it - me->session_services->send_fix_buffer(buffer, trace); - - // post send book keeping + me->session_services->queue_fix(jetfix::MessageTypes::NewOrderSingle, + me->create_encoding, trace); me->session_services->governor().record_sent(); - me->session_services->refill_fix_buffer_pool(); me->state.set_status(ORDER_STATUS_PENDING_WORKING); LOG(OrderMan, Info, "Sent new order with key {} to gateway", @@ -532,31 +523,14 @@ void NativeOrder::on_update(Price p, Quantity q, PerfTrace const &t) { auto const &ts = me->services->get_time_str(); me->update_transact_time_bm = encoding.overwrite( me->update_transact_time_bm, &ts.value()[0], ts.value().size()); - auto buffer = me->session_services->get_fix_buffer(); - auto &stream = buffer->fix[0]; - tracepoint(bts_trace, trace_order, (char *)"on_update.before_new_msg", 0, - trace.md_sn, trace.order_key); - auto &f = stream.new_msg(jetfix::MessageTypes::CancelReplace); - f.append(me->update_encoding); - stream.close(); - // send it - tracepoint(bts_trace, trace_order, (char *)"on_update.before_send_fix", 0, - trace.md_sn, trace.order_key); - me->session_services->send_fix_buffer(buffer, trace); + me->session_services->queue_fix(jetfix::MessageTypes::CancelReplace, + me->update_encoding, trace); + me->session_services->governor().record_sent(); - tracepoint(bts_trace, trace_order, (char *)"on_update.end", 0, - trace.md_sn, trace.order_key); - // post send book keeping - - // these are slow and we need to return out of this handler so - // that we can process the fix - me->services->schedule_action([this]() { - me->session_services->refill_fix_buffer_pool(); - if (me->state.last_msg().size()) - me->state.set_last_msg(""); - report_state(); - }); + update_working_position(); + if (me->state.last_msg().size()) + me->state.set_last_msg(""); // early return so we skip report_state (for speed) return; @@ -590,16 +564,10 @@ void NativeOrder::on_cancel(PerfTrace const &trace) { auto const &ts = me->services->get_time_str(); me->cancel_transact_time_bm = encoding.overwrite( me->cancel_transact_time_bm, &ts.value()[0], ts.value().size()); - auto buffer = me->session_services->get_fix_buffer(); - auto &stream = buffer->fix[0]; - auto &f = stream.new_msg(jetfix::MessageTypes::Cancel); - f.append(me->cancel_encoding); - stream.close(); - auto trace_cpy = trace; - me->session_services->send_fix_buffer(buffer, trace_cpy); - // post send book keeping - me->session_services->refill_fix_buffer_pool(); + me->session_services->queue_fix(jetfix::MessageTypes::Cancel, + me->cancel_encoding, trace); + break; } @@ -807,7 +775,7 @@ void NativeOrder::on_gateway_status(const GatewayStatusChangeEvent &ev) { report_state(); } -void NativeOrder::report_state(PerfTrace const &trace) { +void NativeOrder::update_working_position() { if (me->sec) { auto current_position = position_contribution(); auto previous_position = me->previous_position_contribution; @@ -828,7 +796,10 @@ void NativeOrder::report_state(PerfTrace const &trace) { "Order {} ignored for purposes of limit enforcing " "because it references unknown security {} ", key().value(), me->definition.security_key()); +} +void NativeOrder::report_state(PerfTrace const &trace) { + update_working_position(); me->services->report_state(me->state, trace); } @@ -1043,7 +1014,7 @@ void NativeOrder::transition(api::orderman::OrderStatus new_status) { else LOG(OrderMan, Diag, "Transitioning order {} from {} to {}", key().value(), from, to); - + me->state.set_status(new_status); } diff --git a/src/lib/orderman/orders/NativeOrder.h b/src/lib/orderman/orders/NativeOrder.h index 93cefe450..d1b52279c 100644 --- a/src/lib/orderman/orders/NativeOrder.h +++ b/src/lib/orderman/orders/NativeOrder.h @@ -46,6 +46,7 @@ private: void transition_to_error(api::orderman::NativeOrderState::SubError sub_error, std::string const&msg); + void update_working_position(); bool has_exchange_order_id() ; Quantity position_contribution(); bool is_old_exe_report( api::orderman::NativeOrderState &, const NewExecutionReportEvent &) const; diff --git a/src/lib/orderman/perf_analysis/load_data.py b/src/lib/orderman/perf_analysis/load_data.py index de32152ee..3e3f9130e 100755 --- a/src/lib/orderman/perf_analysis/load_data.py +++ b/src/lib/orderman/perf_analysis/load_data.py @@ -3,6 +3,9 @@ import pandas as pd import sqlite3 import dateutil +import matplotlib.pyplot as plt +import numpy as np + from pathlib import Path # dt = dateutil.parser.parse('2018-10-23 16:35:01.566000') @@ -13,11 +16,13 @@ from pathlib import Path requotes = None db_path = "%s/sparkdata/data/databases/perf_trace/perf_trace.sqlite" % str(Path.home()) c = sqlite3.connect(db_path,uri = True) +raw_data = None def load(): - raw_data = pd.read_sql_query("select * from trace;", c) + global raw_data global requotes + raw_data = pd.read_sql_query("select * from trace;", c) requotes = raw_data[(raw_data.order_update>0) ] requotes = requotes.assign (total = (requotes.fix_socket_w - requotes.md) / 1000) requotes = requotes.assign (md = (requotes.spreader_on_book - requotes.md) / 1000) @@ -38,6 +43,13 @@ def load(): summary() requotes +def plot(n): + plt.clf() + p = requotes[-n:][['trace_time','total']] + q = p.set_index('trace_time') + plt.plot(q) + + def summary(): grouped = requotes.groupby(requotes['session_start']) counts = grouped.count()['total'] diff --git a/src/lib/orderman/server/OrderServiceServer.cpp b/src/lib/orderman/server/OrderServiceServer.cpp index a7fdb9853..5c06f88b1 100644 --- a/src/lib/orderman/server/OrderServiceServer.cpp +++ b/src/lib/orderman/server/OrderServiceServer.cpp @@ -20,7 +20,7 @@ #include "lib/utils/bts_chrono.h" #include "lib/utils/thread_manager.h" #include "lib/utils/type_name.h" - + #include namespace bts { diff --git a/src/lib/utils/inplace_function.h b/src/lib/utils/inplace_function.h new file mode 100644 index 000000000..40677f74f --- /dev/null +++ b/src/lib/utils/inplace_function.h @@ -0,0 +1,361 @@ +/* + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include + +namespace stdext { + +namespace inplace_function_detail { + +static constexpr size_t InplaceFunctionDefaultCapacity = 32; + +#if defined(__GLIBCXX__) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61458 +template +union aligned_storage_helper { + struct double1 { double a; }; + struct double4 { double a[4]; }; + template using maybe = std::conditional_t<(Cap >= sizeof(T)), T, char>; + char real_data[Cap]; + maybe a; + maybe b; + maybe c; + maybe d; + maybe e; + maybe f; + maybe g; + maybe h; +}; + +template>::value> +struct aligned_storage { + using type = std::aligned_storage_t; +}; + +template>::value> +using aligned_storage_t = typename aligned_storage::type; +#else +using std::aligned_storage; +using std::aligned_storage_t; +#endif + +template struct wrapper +{ + using type = T; +}; + +template struct vtable +{ + using storage_ptr_t = void*; + + using invoke_ptr_t = R(*)(storage_ptr_t, Args&&...); + using process_ptr_t = void(*)(storage_ptr_t, storage_ptr_t); + using destructor_ptr_t = void(*)(storage_ptr_t); + + const invoke_ptr_t invoke_ptr; + const process_ptr_t copy_ptr; + const process_ptr_t relocate_ptr; + const destructor_ptr_t destructor_ptr; + + explicit constexpr vtable() noexcept : + invoke_ptr{ [](storage_ptr_t, Args&&...) -> R + { throw std::bad_function_call(); } + }, + copy_ptr{ [](storage_ptr_t, storage_ptr_t) noexcept -> void {} }, + relocate_ptr{ [](storage_ptr_t, storage_ptr_t) noexcept -> void {} }, + destructor_ptr{ [](storage_ptr_t) noexcept -> void {} } + {} + + template explicit constexpr vtable(wrapper) noexcept : + invoke_ptr{ [](storage_ptr_t storage_ptr, Args&&... args) + noexcept(noexcept(std::declval()(args...))) -> R + { return (*static_cast(storage_ptr))( + std::forward(args)... + ); } + }, + copy_ptr{ [](storage_ptr_t dst_ptr, storage_ptr_t src_ptr) + noexcept(std::is_nothrow_copy_constructible::value) -> void + { ::new (dst_ptr) C{ (*static_cast(src_ptr)) }; } + }, + relocate_ptr{ [](storage_ptr_t dst_ptr, storage_ptr_t src_ptr) + noexcept(std::is_nothrow_move_constructible::value) -> void + { + ::new (dst_ptr) C{ std::move(*static_cast(src_ptr)) }; + static_cast(src_ptr)->~C(); + } + }, + destructor_ptr{ [](storage_ptr_t src_ptr) + noexcept -> void + { static_cast(src_ptr)->~C(); } + } + {} + + vtable(const vtable&) = delete; + vtable(vtable&&) = delete; + + vtable& operator= (const vtable&) = delete; + vtable& operator= (vtable&&) = delete; + + ~vtable() = default; +}; + +template +#if __cplusplus >= 201703L +inline constexpr +#endif +vtable empty_vtable{}; + +template +struct is_valid_inplace_dst : std::true_type +{ + static_assert(DstCap >= SrcCap, + "Can't squeeze larger inplace_function into a smaller one" + ); + + static_assert(DstAlign % SrcAlign == 0, + "Incompatible inplace_function alignments" + ); +}; + +} // namespace inplace_function_detail + +template< + typename Signature, + size_t Capacity = inplace_function_detail::InplaceFunctionDefaultCapacity, + size_t Alignment = std::alignment_of>::value +> +class inplace_function; // unspecified + +template< + typename R, + typename... Args, + size_t Capacity, + size_t Alignment +> +class inplace_function +{ +public: + using capacity = std::integral_constant; + using alignment = std::integral_constant; + + using storage_t = inplace_function_detail::aligned_storage_t; + using vtable_t = inplace_function_detail::vtable; + using vtable_ptr_t = const vtable_t*; + + template friend class inplace_function; + + inplace_function() noexcept : + vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable)} + {} + + template< + typename T, + typename C = std::decay_t, + typename = std::enable_if_t< + !(std::is_same::value + || std::is_convertible::value) + > + > + inplace_function(T&& closure) + { +#if __cplusplus >= 201703L + static_assert(std::is_invocable_r::value, + "inplace_function cannot be constructed from non-callable type" + ); +#endif + static_assert(std::is_copy_constructible::value, + "inplace_function cannot be constructed from non-copyable type" + ); + + static_assert(sizeof(C) <= Capacity, + "inplace_function cannot be constructed from object with this (large) size" + ); + + static_assert(Alignment % std::alignment_of::value == 0, + "inplace_function cannot be constructed from object with this (large) alignment" + ); + + static const vtable_t vt{inplace_function_detail::wrapper{}}; + vtable_ptr_ = std::addressof(vt); + + ::new (std::addressof(storage_)) C{std::forward(closure)}; + } + + inplace_function(std::nullptr_t) noexcept : + vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable)} + {} + + inplace_function(const inplace_function& other) : + vtable_ptr_{other.vtable_ptr_} + { + vtable_ptr_->copy_ptr( + std::addressof(storage_), + std::addressof(other.storage_) + ); + } + + inplace_function(inplace_function&& other) : + vtable_ptr_{std::exchange(other.vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable))} + { + vtable_ptr_->relocate_ptr( + std::addressof(storage_), + std::addressof(other.storage_) + ); + } + + inplace_function& operator= (std::nullptr_t) noexcept + { + vtable_ptr_->destructor_ptr(std::addressof(storage_)); + vtable_ptr_ = std::addressof(inplace_function_detail::empty_vtable); + return *this; + } + + inplace_function& operator= (const inplace_function& other) + { + if(this != std::addressof(other)) + { + vtable_ptr_->destructor_ptr(std::addressof(storage_)); + + vtable_ptr_ = other.vtable_ptr_; + vtable_ptr_->copy_ptr( + std::addressof(storage_), + std::addressof(other.storage_) + ); + } + return *this; + } + + inplace_function& operator= (inplace_function&& other) + { + if(this != std::addressof(other)) + { + vtable_ptr_->destructor_ptr(std::addressof(storage_)); + + vtable_ptr_ = std::exchange(other.vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable)); + vtable_ptr_->relocate_ptr( + std::addressof(storage_), + std::addressof(other.storage_) + ); + } + return *this; + } + + ~inplace_function() + { + vtable_ptr_->destructor_ptr(std::addressof(storage_)); + } + + R operator() (Args... args) const + { + return vtable_ptr_->invoke_ptr( + std::addressof(storage_), + std::forward(args)... + ); + } + + constexpr bool operator== (std::nullptr_t) const noexcept + { + return !operator bool(); + } + + constexpr bool operator!= (std::nullptr_t) const noexcept + { + return operator bool(); + } + + explicit constexpr operator bool() const noexcept + { + return vtable_ptr_ != std::addressof(inplace_function_detail::empty_vtable); + } + + template + operator inplace_function() const& + { + static_assert(inplace_function_detail::is_valid_inplace_dst< + Cap, Align, Capacity, Alignment + >::value, "conversion not allowed"); + + return {vtable_ptr_, vtable_ptr_->copy_ptr, std::addressof(storage_)}; + } + + template + operator inplace_function() && + { + static_assert(inplace_function_detail::is_valid_inplace_dst< + Cap, Align, Capacity, Alignment + >::value, "conversion not allowed"); + + auto vtable_ptr = std::exchange(vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable)); + + return {vtable_ptr, vtable_ptr->relocate_ptr, std::addressof(storage_)}; + } + + void swap(inplace_function& other) + { + if (this == std::addressof(other)) return; + + storage_t tmp; + vtable_ptr_->relocate_ptr( + std::addressof(tmp), + std::addressof(storage_) + ); + + other.vtable_ptr_->relocate_ptr( + std::addressof(storage_), + std::addressof(other.storage_) + ); + + vtable_ptr_->relocate_ptr( + std::addressof(other.storage_), + std::addressof(tmp) + ); + + std::swap(vtable_ptr_, other.vtable_ptr_); + } + + friend void swap(inplace_function& lhs, inplace_function& rhs) + { + lhs.swap(rhs); + } + +private: + vtable_ptr_t vtable_ptr_; + mutable storage_t storage_; + + inplace_function( + vtable_ptr_t vtable_ptr, + typename vtable_t::process_ptr_t process_ptr, + typename vtable_t::storage_ptr_t storage_ptr + ) : vtable_ptr_{vtable_ptr} + { + process_ptr(std::addressof(storage_), storage_ptr); + } +}; + +} // namespace stdext diff --git a/src/server/sparkd/cmds/Benchmark.cpp b/src/server/sparkd/cmds/Benchmark.cpp index 76c83eab7..aa308cc04 100644 --- a/src/server/sparkd/cmds/Benchmark.cpp +++ b/src/server/sparkd/cmds/Benchmark.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -446,7 +447,6 @@ static void tbb_concurrent_queue(benchmark::State &state) { } BENCHMARK(tbb_concurrent_queue); - static void boost_spsc(benchmark::State &state) { boost::lockfree::spsc_queue q(10000); @@ -652,7 +652,7 @@ static void moodycamel_concurrent_queue(benchmark::State &state) { using Q = moodycamel::ConcurrentQueue; Q queue(8); int i = 0; - + for (auto _ : state) { queue.enqueue(++i); // NOLINT benchmark::DoNotOptimize(queue.try_dequeue(i)); @@ -672,6 +672,59 @@ static void moodycamel_spsc_queue(benchmark::State &state) { } BENCHMARK(moodycamel_spsc_queue); +struct MyBase { + virtual int inc(int &x) = 0; +}; +struct MyDerived : MyBase { + int inc(int &x) override { return x += 1; }; +}; + +struct MyDirect { + int inc(int &x) { return x += 1; }; +}; + +static void derived_call(benchmark::State &state) { + int x = 0; + MyDerived d; + MyBase &b = d; + + for (auto _ : state) { + benchmark::DoNotOptimize(b.inc(x)); + } +} +BENCHMARK(derived_call); + +static void direct_call(benchmark::State &state) { + int x = 0; + MyDerived b; + + for (auto _ : state) { + benchmark::DoNotOptimize(b.inc(x)); + } +} +BENCHMARK(direct_call); + +static void get_time_of_day(benchmark::State &state) { + std::string result(strlen("20121204-14:44:02.999"), ' '); + struct timeval tv; + for (auto _ : state) { + gettimeofday(&tv, nullptr); + auto tm=localtime(&tv.tv_sec); + sprintf(&result[0], "%d%02d%02d-%02d:%02d:%02d.%03d", + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min,tm->tm_sec, 0); + } +} +BENCHMARK(get_time_of_day); + +static void fix_time_stamp(benchmark::State &state) { + std::string r (128,32);auto now = datetime::now(); + for (auto _ : state) { + datetime::FIX_timestamp(now,&r); + } +} +BENCHMARK(fix_time_stamp); + std::string Benchmark::help() { return "Run micro-benchmarks. Use --benchmark_filter=regex to run only " "specific benchmarks."; From ced485856ef5fd425f748ed51d34153fa184e46f Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Mon, 5 Nov 2018 14:24:00 +0000 Subject: [PATCH 14/29] Added some experimental perf related code. --- src/lib/CMakeDeps.cmake | 2 +- src/lib/orderman2/IOrderManagerObserver.h | 28 ++++++++ src/lib/orderman2/OrderManager2.cpp | 7 ++ src/lib/orderman2/OrderManager2.h | 37 ++++++++++ src/lib/orderman2/orderman_utils/Book.h | 72 +++++++++++++++++++ .../orderman2/orderman_utils/orderman_utils.h | 10 +++ 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/lib/orderman2/IOrderManagerObserver.h create mode 100644 src/lib/orderman2/OrderManager2.cpp create mode 100644 src/lib/orderman2/OrderManager2.h create mode 100644 src/lib/orderman2/orderman_utils/Book.h create mode 100644 src/lib/orderman2/orderman_utils/orderman_utils.h diff --git a/src/lib/CMakeDeps.cmake b/src/lib/CMakeDeps.cmake index 9979952dc..2899c6359 100644 --- a/src/lib/CMakeDeps.cmake +++ b/src/lib/CMakeDeps.cmake @@ -1 +1 @@ -set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/dynamic_orders.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/IPollableActor.cpp;mercury/broker/Broker.cpp;mercury/broker/BrokerProxy.cpp;mercury/broker/ILocalBroker.cpp;mercury/broker/IRemoteBroker.cpp;mercury/common/mercury_common.cpp;mercury/events/TimerEvent.cpp;mercury/executor/Executor.cpp;mercury/topics/Topic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/MDSupplementarySource.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/OrderFactory.cpp;orderman/order_router/OrderRouter.cpp;orderman/orderman_utils/PerfTraceLog.cpp;orderman/orderman_utils/fix_order_codec.cpp;orderman/orders/DynamicOrder.cpp;orderman/orders/IcebergOrder.cpp;orderman/orders/NativeOrder.cpp;orderman/orders/Order.cpp;orderman/orders/TimeBoxOrder.cpp;orderman/orders/TriggerOrder.cpp;orderman/orders/book_algos/BookAlgo.cpp;orderman/orders/book_algos/CoverOrder.cpp;orderman/orders/book_algos/JoinOrder.cpp;orderman/orders/book_algos/LeanOrder.cpp;orderman/orders/book_algos/TickOrder.cpp;orderman/orders/book_algos/TopOrder.cpp;orderman/orders/spreader_orders/SpreaderOrder.cpp;orderman/orders/spreader_orders/spreader/LegPropertyData.cpp;orderman/orders/spreader_orders/spreader/QuoteLegPriceQuantityState.cpp;orderman/orders/spreader_orders/spreader/SingleFillHedger.cpp;orderman/orders/spreader_orders/spreader/SingleLegQuoter.cpp;orderman/orders/spreader_orders/spreader/SpreaderBookkeepingData.cpp;orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.cpp;orderman/orders/spreader_orders/spreader/SpreaderLegData.cpp;orderman/orders/spreader_orders/spreader/SpreaderUtils.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderBuilder.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderServices.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderPreActivationOrderServices.cpp;orderman/orders/spreader_orders/spreader/hedger/UnhedgedDelta.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerEndStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerStartStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForCancelAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForFirstAckCancelledStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForFirstAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWorkingStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteDriverSet.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteDriverSetHistory.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteLegDriver.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterEndStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterStartStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForCancelAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForFirstAckCancelledWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForFirstAckWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForIOCWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForSizeStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWorkingStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderEndStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderStartStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWaitingForCancelAllStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWorkingStateWorker.cpp;orderman/orders/spreader_orders/tests/spreader_tests.cpp;orderman/server/OrderServiceServer.cpp;orderman/tests/fat_wrapper_tests.cpp;os/os.cpp;os/tests/os_tests.cpp;persistence/IStore.cpp;persistence/PersistenceServiceServer.cpp;persistence/SqliteStore.cpp;persistence/persistence_utils.cpp;persistence/tests/PersistenceServiceTests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/thread_manager.cpp) \ No newline at end of file +set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/dynamic_orders.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/IPollableActor.cpp;mercury/broker/Broker.cpp;mercury/broker/BrokerProxy.cpp;mercury/broker/ILocalBroker.cpp;mercury/broker/IRemoteBroker.cpp;mercury/common/mercury_common.cpp;mercury/events/TimerEvent.cpp;mercury/executor/Executor.cpp;mercury/topics/Topic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/MDSupplementarySource.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/OrderFactory.cpp;orderman/order_router/OrderRouter.cpp;orderman/orderman_utils/PerfTraceLog.cpp;orderman/orderman_utils/fix_order_codec.cpp;orderman/orders/DynamicOrder.cpp;orderman/orders/IcebergOrder.cpp;orderman/orders/NativeOrder.cpp;orderman/orders/Order.cpp;orderman/orders/TimeBoxOrder.cpp;orderman/orders/TriggerOrder.cpp;orderman/orders/book_algos/BookAlgo.cpp;orderman/orders/book_algos/CoverOrder.cpp;orderman/orders/book_algos/JoinOrder.cpp;orderman/orders/book_algos/LeanOrder.cpp;orderman/orders/book_algos/TickOrder.cpp;orderman/orders/book_algos/TopOrder.cpp;orderman/orders/spreader_orders/SpreaderOrder.cpp;orderman/orders/spreader_orders/spreader/LegPropertyData.cpp;orderman/orders/spreader_orders/spreader/QuoteLegPriceQuantityState.cpp;orderman/orders/spreader_orders/spreader/SingleFillHedger.cpp;orderman/orders/spreader_orders/spreader/SingleLegQuoter.cpp;orderman/orders/spreader_orders/spreader/SpreaderBookkeepingData.cpp;orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.cpp;orderman/orders/spreader_orders/spreader/SpreaderLegData.cpp;orderman/orders/spreader_orders/spreader/SpreaderUtils.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderBuilder.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderServices.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderPreActivationOrderServices.cpp;orderman/orders/spreader_orders/spreader/hedger/UnhedgedDelta.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerEndStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerStartStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForCancelAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForFirstAckCancelledStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForFirstAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWorkingStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteDriverSet.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteDriverSetHistory.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteLegDriver.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterEndStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterStartStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForCancelAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForFirstAckCancelledWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForFirstAckWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForIOCWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForSizeStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWorkingStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderEndStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderStartStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWaitingForCancelAllStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWorkingStateWorker.cpp;orderman/orders/spreader_orders/tests/spreader_tests.cpp;orderman/server/OrderServiceServer.cpp;orderman/tests/fat_wrapper_tests.cpp;orderman2/OrderManager2.cpp;os/os.cpp;os/tests/os_tests.cpp;persistence/IStore.cpp;persistence/PersistenceServiceServer.cpp;persistence/SqliteStore.cpp;persistence/persistence_utils.cpp;persistence/tests/PersistenceServiceTests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/thread_manager.cpp) \ No newline at end of file diff --git a/src/lib/orderman2/IOrderManagerObserver.h b/src/lib/orderman2/IOrderManagerObserver.h new file mode 100644 index 000000000..f5596b663 --- /dev/null +++ b/src/lib/orderman2/IOrderManagerObserver.h @@ -0,0 +1,28 @@ +#pragma once + +#include "lib/config/protos/jetfix.pb.h" +#include "lib/domain_model/SecurityKey.h" +#include "orderman_utils/orderman_utils.h" + +namespace bts { +namespace api { +namespace orderman { +class OrderDefinition; +} +} // namespace api +namespace orderman2 { + +class OrderState; + +class IOrderManagerObserver { + public: + void subscribe_book(SecurityKey, void *sub); + void request_new_fill_buffers(config::JetFIX::Connection const &, + size_t n_buffers, void *sub); + void request_new_orders(api::orderman::OrderDefinition const &, + OrderKey parent_key, size_t n_orders, void *sub); + void send_fix(size_t gw_idx, jetfix::OutFIXPtr const &); +}; + +} // namespace orderman2 +} // namespace bts diff --git a/src/lib/orderman2/OrderManager2.cpp b/src/lib/orderman2/OrderManager2.cpp new file mode 100644 index 000000000..44949ac83 --- /dev/null +++ b/src/lib/orderman2/OrderManager2.cpp @@ -0,0 +1,7 @@ +#include "OrderManager2.h" +#include "IOrderManagerObserver.h" + +namespace bts { +namespace orderman2 { + +}} diff --git a/src/lib/orderman2/OrderManager2.h b/src/lib/orderman2/OrderManager2.h new file mode 100644 index 000000000..1f761b75b --- /dev/null +++ b/src/lib/orderman2/OrderManager2.h @@ -0,0 +1,37 @@ +#pragma once + +#include "orderman_utils/orderman_utils.h" +#include "orderman_utils/Book.h" +#include "lib/jetfix/common/OutFIXPtr.h" + +#include + +namespace bts { +namespace api { class Security;} +namespace orderman2 { + +class Order; +class IOrderManagerObserver; +class ExecutionReport; + +class OrderManager { + OrderManager(); + + void init(IOrderManagerObserver &observer); + + void on_activate(Order &, Price , Quantity); + void on_update(Order&, Price , Quantity); + void on_cancel(Order&); + void on_book_update(Book const&b,void*sub); + void on_execution_report(ExecutionReport &); + + void on_securities(std::vector const&); + void on_new_fill_buffers(std::vector const&,void*sub); + void on_new_orders(std::vector const&,void*sub); + +private: + struct PImpl; + std::unique_ptr me; +}; + +}} diff --git a/src/lib/orderman2/orderman_utils/Book.h b/src/lib/orderman2/orderman_utils/Book.h new file mode 100644 index 000000000..3e505b38a --- /dev/null +++ b/src/lib/orderman2/orderman_utils/Book.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include "lib/domain_model/common.h" +#include "lib/config/protos/MarketData.pb.h" +#include "lib/md/PriceSize.h" + + +namespace bts { +namespace orderman2 { + +using BookSide = std::array ; + +class Book { +public: + Book () : + _security_key(), + _book() + {} + + Book (SecurityKey key) : + _security_key(key), + _book() + {} + + Book (SecurityKey key, + BookSide const&bid, + BookSide const&ask) : + _security_key(key), + _book {bid,ask} + {} + + Book (Book const&rhs) + : _security_key(rhs._security_key), + _book(rhs._book) + {} + + Book &operator=(Book const &rhs) + { + _security_key = rhs._security_key; + _book = rhs._book; + return *this; + } + + SecurityKey security_key() const {return _security_key;} ; + + BookSide const &bid () const {return _book[0];} + BookSide const &ask () const {return _book[1];} + BookSide &bid () {return _book[0];} + BookSide &ask () {return _book[1];} + + size_t n_levels() const {return std::tuple_size();} + + BookSide const& side(api::Side bs) const + { + bts_assert_d(bs != api::SIDE_UNDEFINED); + return _book[bs - api::SIDE_BUY]; + } + + BookSide & side(api::Side bs) + { + bts_assert_d(bs != api::SIDE_UNDEFINED); + return _book[bs - api::SIDE_BUY]; + } + +private: + friend class MDSource; + SecurityKey _security_key; + std::array _book; +}; + +}} diff --git a/src/lib/orderman2/orderman_utils/orderman_utils.h b/src/lib/orderman2/orderman_utils/orderman_utils.h new file mode 100644 index 000000000..540f6a9a3 --- /dev/null +++ b/src/lib/orderman2/orderman_utils/orderman_utils.h @@ -0,0 +1,10 @@ +#pragma once + +#include "lib/utils/ValueWrapper.h" + +namespace bts { +namespace orderman2 { +using Price = utils::ValueWrapper; +using Quantity = utils::ValueWrapper; +using OrderKey = utils::ValueWrapper; +}} From 80d830782209c7b6904ff69a4f86e111543f64b8 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Tue, 6 Nov 2018 13:41:45 +0000 Subject: [PATCH 15/29] Cleaned up docs build. --- doc/user/CMakeDeps.cmake | 2 +- doc/user/CMakeLists.txt | 1 + doc/user/build.sh | 11 ++++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/user/CMakeDeps.cmake b/doc/user/CMakeDeps.cmake index 17c3ebfe8..00bd7e37b 100644 --- a/doc/user/CMakeDeps.cmake +++ b/doc/user/CMakeDeps.cmake @@ -1 +1 @@ -set(sources bts-help-theme/404.html;bts-help-theme/base.html;bts-help-theme/content.html;bts-help-theme/css/base.css;bts-help-theme/css/bts.css;bts-help-theme/css/font-awesome.min.css;bts-help-theme/css/highlight.css;bts-help-theme/css/local.css;bts-help-theme/fonts/fontawesome-webfont.eot;bts-help-theme/fonts/glyphicons-halflings-regular.eot;bts-help-theme/img/favicon.ico;bts-help-theme/js/base.js;bts-help-theme/js/bootstrap-3.0.3.min.js;bts-help-theme/js/highlight.pack.js;bts-help-theme/js/jquery-1.10.2.min.js;bts-help-theme/keyboard-modal.html;bts-help-theme/main.html;bts-help-theme/nav-sub.html;bts-help-theme/nav.html;bts-help-theme/search-modal.html;bts-help-theme/toc.html;docs/Help.md;docs/Launcher.md;docs/Logging-In-to-the-System.md;docs/Market.md;docs/My-Windows.md;docs/Settings.md;docs/Spreader.md;docs/Trading.md;docs/images/image1.png;docs/images/image10.png;docs/images/image11.png;docs/images/image12.png;docs/images/image13.png;docs/images/image14.png;docs/images/image15.png;docs/images/image16.png;docs/images/image17.png;docs/images/image18.png;docs/images/image19.png;docs/images/image2.png;docs/images/image20.png;docs/images/image21.png;docs/images/image22.png;docs/images/image23.png;docs/images/image24.png;docs/images/image25.png;docs/images/image26.png;docs/images/image27.png;docs/images/image28.png;docs/images/image29.png;docs/images/image3.png;docs/images/image30.png;docs/images/image31.png;docs/images/image32.png;docs/images/image33.png;docs/images/image34.png;docs/images/image35.png;docs/images/image36.png;docs/images/image37.png;docs/images/image38.png;docs/images/image39.png;docs/images/image4.png;docs/images/image40.png;docs/images/image41.png;docs/images/image42.png;docs/images/image43.png;docs/images/image44.png;docs/images/image45.png;docs/images/image46.png;docs/images/image47.png;docs/images/image48.png;docs/images/image49.png;docs/images/image5.png;docs/images/image50.png;docs/images/image51.png;docs/images/image52.png;docs/images/image53.png;docs/images/image54.png;docs/images/image55.png;docs/images/image56.png;docs/images/image57.png;docs/images/image58.png;docs/images/image59.png;docs/images/image6.png;docs/images/image60.png;docs/images/image61.png;docs/images/image62.png;docs/images/image63.png;docs/images/image64.png;docs/images/image65.png;docs/images/image66.png;docs/images/image67.png;docs/images/image68.png;docs/images/image69.png;docs/images/image7.png;docs/images/image70.png;docs/images/image71.png;docs/images/image72.png;docs/images/image73.png;docs/images/image74.png;docs/images/image76.png;docs/images/image8.png;docs/images/image9.png;docs/index.md;docs/release_notes.md) \ No newline at end of file +set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;/home/ppinto/Dropbox/bts/spark/doc/user/mkdocs.yml;bts-help-theme/404.html;bts-help-theme/base.html;bts-help-theme/content.html;bts-help-theme/css/base.css;bts-help-theme/css/bts.css;bts-help-theme/css/font-awesome.min.css;bts-help-theme/css/highlight.css;bts-help-theme/css/local.css;bts-help-theme/fonts/fontawesome-webfont.eot;bts-help-theme/fonts/glyphicons-halflings-regular.eot;bts-help-theme/img/favicon.ico;bts-help-theme/js/base.js;bts-help-theme/js/bootstrap-3.0.3.min.js;bts-help-theme/js/highlight.pack.js;bts-help-theme/js/jquery-1.10.2.min.js;bts-help-theme/keyboard-modal.html;bts-help-theme/main.html;bts-help-theme/nav-sub.html;bts-help-theme/nav.html;bts-help-theme/search-modal.html;bts-help-theme/toc.html;docs/Help.md;docs/Launcher.md;docs/Logging-In-to-the-System.md;docs/Market.md;docs/My-Windows.md;docs/Settings.md;docs/Spreader.md;docs/Trading.md;docs/images/image1.png;docs/images/image10.png;docs/images/image11.png;docs/images/image12.png;docs/images/image13.png;docs/images/image14.png;docs/images/image15.png;docs/images/image16.png;docs/images/image17.png;docs/images/image18.png;docs/images/image19.png;docs/images/image2.png;docs/images/image20.png;docs/images/image21.png;docs/images/image22.png;docs/images/image23.png;docs/images/image24.png;docs/images/image25.png;docs/images/image26.png;docs/images/image27.png;docs/images/image28.png;docs/images/image29.png;docs/images/image3.png;docs/images/image30.png;docs/images/image31.png;docs/images/image32.png;docs/images/image33.png;docs/images/image34.png;docs/images/image35.png;docs/images/image36.png;docs/images/image37.png;docs/images/image38.png;docs/images/image39.png;docs/images/image4.png;docs/images/image40.png;docs/images/image41.png;docs/images/image42.png;docs/images/image43.png;docs/images/image44.png;docs/images/image45.png;docs/images/image46.png;docs/images/image47.png;docs/images/image48.png;docs/images/image49.png;docs/images/image5.png;docs/images/image50.png;docs/images/image51.png;docs/images/image52.png;docs/images/image53.png;docs/images/image54.png;docs/images/image55.png;docs/images/image56.png;docs/images/image57.png;docs/images/image58.png;docs/images/image59.png;docs/images/image6.png;docs/images/image60.png;docs/images/image61.png;docs/images/image62.png;docs/images/image63.png;docs/images/image64.png;docs/images/image65.png;docs/images/image66.png;docs/images/image67.png;docs/images/image68.png;docs/images/image69.png;docs/images/image7.png;docs/images/image70.png;docs/images/image71.png;docs/images/image72.png;docs/images/image73.png;docs/images/image74.png;docs/images/image76.png;docs/images/image8.png;docs/images/image9.png;docs/index.md;docs/release_notes.md) \ No newline at end of file diff --git a/doc/user/CMakeLists.txt b/doc/user/CMakeLists.txt index 1dfa4d6c5..60f50698f 100644 --- a/doc/user/CMakeLists.txt +++ b/doc/user/CMakeLists.txt @@ -16,6 +16,7 @@ set(DOC_GLOBS favicon.ico ) file (GLOB_RECURSE All_Deps RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_GLOBS}) +set (All_Deps ${All_Deps} ${CMAKE_CURRENT_SOURCE_DIR}/build.sh ${CMAKE_CURRENT_SOURCE_DIR}/mkdocs.yml) update_deps_file("${All_Deps}") # END DEPENDENCIES diff --git a/doc/user/build.sh b/doc/user/build.sh index 8cab9f9f8..a961f6060 100644 --- a/doc/user/build.sh +++ b/doc/user/build.sh @@ -1,2 +1,11 @@ #!/bin/bash -python -m mkdocs build -d $1 \ No newline at end of file +tmpfile=$(mktemp /tmp/quiet_build_log.XXXX) +python -m mkdocs build -d $1 >$tmpfile 2>&1 +if [ $? -eq 0 ] +then + rm $tmpfile + exit 0 +else + cat $tmpfile + exit 1 +fi From e2f314d0075dde46c1d6733975f9e1b75165cf9a Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Tue, 6 Nov 2018 13:43:37 +0000 Subject: [PATCH 16/29] Added optional pause between orders to iceberg. --- src/lib/api/services/OrderService.proto | 2 + src/lib/orderman/orders/IcebergOrder.cpp | 67 ++++++++++++++++++------ src/lib/orderman/orders/IcebergOrder.h | 3 ++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/lib/api/services/OrderService.proto b/src/lib/api/services/OrderService.proto index d3ca42c59..c15e167d3 100644 --- a/src/lib/api/services/OrderService.proto +++ b/src/lib/api/services/OrderService.proto @@ -90,7 +90,9 @@ message StopLimitOrderDefinition { message IcebergOrderDefinition { double show_quantity = 1; CustomOrderDefinition child = 2; + uint32 seconds_between_orders = 3; } + message SpreaderOrderDefinition { api.Security security = 1; spark.ExecutionStrategy execution_strategy = 2; diff --git a/src/lib/orderman/orders/IcebergOrder.cpp b/src/lib/orderman/orders/IcebergOrder.cpp index 6a9ee43e5..b33e03fd0 100644 --- a/src/lib/orderman/orders/IcebergOrder.cpp +++ b/src/lib/orderman/orders/IcebergOrder.cpp @@ -1,7 +1,10 @@ #include "IcebergOrder.h" #include "lib/logging/logging.h" -#include "lib/utils/PBUtils.h" #include "lib/orderman/actors/order_manager/OrderBuilder.h" +#include "lib/utils/PBUtils.h" +#include "lib/utils/bts_chrono.h" +#include "lib/mercury/events/TimerEvent.h" + #include namespace bts { @@ -16,8 +19,14 @@ struct IcebergOrder::ActiveChild { void clear() { state = api::orderman::OrderState(); } }; +enum class IcebergOrder::WorkingSubStatus { WORKING, PAUSED }; + struct IcebergOrder::PImpl { - PImpl() : services(nullptr), child() {} + PImpl() + : services(nullptr), child(), + working_sub_status(WorkingSubStatus::PAUSED), + start_of_pause(Timer::now()) + {} OrderServices *services; api::orderman::OrderDefinition def; @@ -25,6 +34,9 @@ struct IcebergOrder::PImpl { OrderBuilder child_builder; ActiveChild child; Quantity show_quantity; + WorkingSubStatus working_sub_status; + TimeStamp start_of_pause; + uint32_t pause_between_orders; }; IcebergOrder::IcebergOrder() : me(new PImpl()) {} @@ -39,10 +51,11 @@ void IcebergOrder::on_init_new(api::orderman::OrderDefinition const &def, const PreActivationOrderServices &services) { me->def = def; me->state.mutable_iceberg(); - + auto const &iceberg_def = def.custom_def().iceberg(); me->show_quantity = Quantity(iceberg_def.show_quantity()); - + me->pause_between_orders = iceberg_def.seconds_between_orders(); + auto child_def = def; *child_def.mutable_custom_def() = iceberg_def.child(); if (me->show_quantity.value() != 0) { @@ -89,7 +102,7 @@ void IcebergOrder::on_init_recovered(api::orderman::OrderRecord const &rec, } void IcebergOrder::on_activate(Price p, Quantity q, OrderServices &services, - PerfTrace const&) { + PerfTrace const &) { bts_assert(!me->services); me->services = &services; me->child_builder.activate(services); @@ -98,9 +111,13 @@ void IcebergOrder::on_activate(Price p, Quantity q, OrderServices &services, case ORDER_STATUS_INACTIVE: me->state.set_price(p.value()); me->state.set_quantity(q.value()); + if (me->pause_between_orders) + services.time_change.sub( + [this](auto const &time) { this->on_time(time); }); services.child_updates.sub( key(), [this](auto const &os) { this->on_child_order_update(os); }); transition(ORDER_STATUS_WORKING); + me->working_sub_status = WorkingSubStatus::WORKING; send_next_child_order(); break; @@ -126,7 +143,7 @@ void IcebergOrder::on_activate(Price p, Quantity q, OrderServices &services, report_state(); } -void IcebergOrder::on_update(Price p, Quantity q, PerfTrace const&) { +void IcebergOrder::on_update(Price p, Quantity q, PerfTrace const &) { switch (me->state.status()) { case ORDER_STATUS_WORKING: case ORDER_STATUS_PENDING_WORKING: @@ -152,9 +169,9 @@ void IcebergOrder::on_update(Price p, Quantity q, PerfTrace const&) { report_state(); } -void IcebergOrder::on_crack(PerfTrace const&) {} +void IcebergOrder::on_crack(PerfTrace const &) {} -void IcebergOrder::on_cancel(PerfTrace const&) { +void IcebergOrder::on_cancel(PerfTrace const &) { switch (me->state.status()) { case ORDER_STATUS_WORKING: LOG(OrderMan, Info, "Canceling Iceberg Order {}", key().value()); @@ -253,14 +270,20 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { break; case ORDER_STATUS_COMPLETED: { - api::orderman::OrderState merged_state; - merge_states(me->state, me->child.state, &merged_state); - me->state = merged_state; - me->child.clear(); - if (me->state.quantity() > me->state.filled_quantity()) + api::orderman::OrderState merged_state; + merge_states(me->state, me->child.state, &merged_state); + me->state = merged_state; + me->child.clear(); + if (me->state.quantity() > me->state.filled_quantity()) { + if (me->pause_between_orders) { + me->working_sub_status = WorkingSubStatus::PAUSED; + me->start_of_pause = Timer::now(); + } + else send_next_child_order(); - else - transition(ORDER_STATUS_COMPLETED); + } + else + transition(ORDER_STATUS_COMPLETED); break; } @@ -268,8 +291,7 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { LOG(OrderMan, Info, "Unexpected cancel of child {} in Iceberg Order {}. Canceling " "parent", - ev.key.value(), - key().value()); + ev.key.value(), key().value()); transition(ORDER_STATUS_CANCELED); break; @@ -312,5 +334,16 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { } report_state(); } + +void IcebergOrder::on_time(mercury::TimerEvent const &t) { + bts_assert(me->pause_between_orders); + if (sec_diff(t.ts,me->start_of_pause) >= me->pause_between_orders && + me->state.status() == ORDER_STATUS_WORKING && + me->working_sub_status == WorkingSubStatus::PAUSED) { + me->working_sub_status = WorkingSubStatus::WORKING; + send_next_child_order(); + } +} + } // namespace orderman } // namespace bts diff --git a/src/lib/orderman/orders/IcebergOrder.h b/src/lib/orderman/orders/IcebergOrder.h index b7abcc04d..a7442b923 100644 --- a/src/lib/orderman/orders/IcebergOrder.h +++ b/src/lib/orderman/orders/IcebergOrder.h @@ -5,6 +5,7 @@ #include "lib/api/services/OrderService.server.pb.h" namespace bts { +namespace mercury {class TimerEvent;} namespace orderman { class OrderStateUpdateEvent; @@ -35,7 +36,9 @@ private: void on_child_order_update(OrderStateUpdateEvent const&); void transition(api::orderman::OrderStatus new_state,std::string const&msg); void transition(api::orderman::OrderStatus new_state); + void on_time (mercury::TimerEvent const&); + enum class WorkingSubStatus; struct ActiveChild; struct PImpl; std::unique_ptr me; From b9d3a4d04c922f880f515178fbac2d63d63f3c19 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Tue, 6 Nov 2018 17:14:05 +0000 Subject: [PATCH 17/29] Fixed typos in SocketConnection perf log. --- src/lib/jetfix/connection/SocketConnection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/jetfix/connection/SocketConnection.cpp b/src/lib/jetfix/connection/SocketConnection.cpp index ae1e8e52a..384c3efcd 100644 --- a/src/lib/jetfix/connection/SocketConnection.cpp +++ b/src/lib/jetfix/connection/SocketConnection.cpp @@ -157,8 +157,8 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size, trace_cpy.spreader_modify_order.to_uint64(), trace_cpy.spreader_on_child_order_update.to_uint64(), trace_cpy.order_update.to_uint64(), trace_cpy.exe_gw.to_uint64(), - trace_cpy.fix_socket_w.to_uint64(), trace_cpy.md_sn, trace.order_key, - trace.send_fix_buffer.to_uint64()); + trace_cpy.fix_socket_w.to_uint64(), trace_cpy.md_sn, trace_cpy.order_key, + trace_cpy.send_fix_buffer.to_uint64()); _perf_log.log(trace_cpy); } From b35dae9fab61f29f013b4847783f970db25291d1 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Tue, 6 Nov 2018 17:17:21 +0000 Subject: [PATCH 18/29] Improved logging of hedge trace. --- src/lib/api/services/OrderService.proto | 2 - src/lib/config/protos/orderman_cfg.proto | 1 + .../jetfix/connection/SocketConnection.cpp | 1 + src/lib/orderman/actors/ServiceBridge.cpp | 2 +- src/lib/orderman/orders/IcebergOrder.cpp | 22 +++++----- src/lib/orderman/orders/NativeOrder.cpp | 11 ++++- .../orders/spreader_orders/SpreaderOrder.cpp | 2 + .../spreader/SpreaderChildOrderState.h | 2 +- .../spreader_orders/tests/spreader_tests.cpp | 6 +-- src/lib/orderman/perf_analysis/load_data.py | 42 +++++++++++++++---- 10 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/lib/api/services/OrderService.proto b/src/lib/api/services/OrderService.proto index c15e167d3..d3ca42c59 100644 --- a/src/lib/api/services/OrderService.proto +++ b/src/lib/api/services/OrderService.proto @@ -90,9 +90,7 @@ message StopLimitOrderDefinition { message IcebergOrderDefinition { double show_quantity = 1; CustomOrderDefinition child = 2; - uint32 seconds_between_orders = 3; } - message SpreaderOrderDefinition { api.Security security = 1; spark.ExecutionStrategy execution_strategy = 2; diff --git a/src/lib/config/protos/orderman_cfg.proto b/src/lib/config/protos/orderman_cfg.proto index 3870d46f3..5d899ea95 100644 --- a/src/lib/config/protos/orderman_cfg.proto +++ b/src/lib/config/protos/orderman_cfg.proto @@ -8,4 +8,5 @@ message OrdermanCfg { repeated string hosted_actor = 3; } repeated Executor executor = 1; + optional uint32 default_iceberg_pause_secs = 2 [default = 0]; } diff --git a/src/lib/jetfix/connection/SocketConnection.cpp b/src/lib/jetfix/connection/SocketConnection.cpp index 384c3efcd..22cfce945 100644 --- a/src/lib/jetfix/connection/SocketConnection.cpp +++ b/src/lib/jetfix/connection/SocketConnection.cpp @@ -122,6 +122,7 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size, trace.md_sn, s2s.microseconds()); } + LOG(Latency, Diag, "perf_event before_socket_write"); auto result = ::writev(_fd, iv, (int)vec_size); if (trace.md.to_uint64()) { diff --git a/src/lib/orderman/actors/ServiceBridge.cpp b/src/lib/orderman/actors/ServiceBridge.cpp index d57c2ba77..f8d0cd3a7 100644 --- a/src/lib/orderman/actors/ServiceBridge.cpp +++ b/src/lib/orderman/actors/ServiceBridge.cpp @@ -147,7 +147,7 @@ ServiceBridge::create_order(api::orderman::Create const &c) { me->order_factory.create(null_order_key(), c.new_order()); me->known_orders.insert(order.key()); publish(me->activate_order_pub, order, Price(c.price()), - Quantity(c.quantity())); + Quantity(c.quantity()), PerfTrace()); r.set_order_key(order.key().value()); r.set_error_code(api::orderman::ORDER_ERROR_OK); } else diff --git a/src/lib/orderman/orders/IcebergOrder.cpp b/src/lib/orderman/orders/IcebergOrder.cpp index b33e03fd0..3c81cb1b8 100644 --- a/src/lib/orderman/orders/IcebergOrder.cpp +++ b/src/lib/orderman/orders/IcebergOrder.cpp @@ -1,9 +1,11 @@ #include "IcebergOrder.h" #include "lib/logging/logging.h" +#include "lib/mercury/events/TimerEvent.h" #include "lib/orderman/actors/order_manager/OrderBuilder.h" #include "lib/utils/PBUtils.h" #include "lib/utils/bts_chrono.h" -#include "lib/mercury/events/TimerEvent.h" +#include "lib/config/config.h" +#include "lib/config/protos/orderman_cfg.pb.h" #include @@ -25,8 +27,7 @@ struct IcebergOrder::PImpl { PImpl() : services(nullptr), child(), working_sub_status(WorkingSubStatus::PAUSED), - start_of_pause(Timer::now()) - {} + start_of_pause(Timer::now()) {} OrderServices *services; api::orderman::OrderDefinition def; @@ -51,11 +52,12 @@ void IcebergOrder::on_init_new(api::orderman::OrderDefinition const &def, const PreActivationOrderServices &services) { me->def = def; me->state.mutable_iceberg(); - + auto const &iceberg_def = def.custom_def().iceberg(); me->show_quantity = Quantity(iceberg_def.show_quantity()); - me->pause_between_orders = iceberg_def.seconds_between_orders(); - + me->pause_between_orders = + config::get().default_iceberg_pause_secs(); + auto child_def = def; *child_def.mutable_custom_def() = iceberg_def.child(); if (me->show_quantity.value() != 0) { @@ -278,11 +280,9 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { if (me->pause_between_orders) { me->working_sub_status = WorkingSubStatus::PAUSED; me->start_of_pause = Timer::now(); - } - else + } else send_next_child_order(); - } - else + } else transition(ORDER_STATUS_COMPLETED); break; } @@ -337,7 +337,7 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { void IcebergOrder::on_time(mercury::TimerEvent const &t) { bts_assert(me->pause_between_orders); - if (sec_diff(t.ts,me->start_of_pause) >= me->pause_between_orders && + if (sec_diff(t.ts, me->start_of_pause) >= me->pause_between_orders && me->state.status() == ORDER_STATUS_WORKING && me->working_sub_status == WorkingSubStatus::PAUSED) { me->working_sub_status = WorkingSubStatus::WORKING; diff --git a/src/lib/orderman/orders/NativeOrder.cpp b/src/lib/orderman/orders/NativeOrder.cpp index e9aa82549..4c0fe8657 100644 --- a/src/lib/orderman/orders/NativeOrder.cpp +++ b/src/lib/orderman/orders/NativeOrder.cpp @@ -12,6 +12,7 @@ #include "lib/orderman/securities/ISecurityDB.h" #include "lib/tracing/bts_trace.h" #include "lib/utils/PBUtils.h" +#include "lib/utils/bts_chrono.h" #include "lib/orderman/actors/order_manager/OrderServices.h" @@ -273,10 +274,13 @@ NativeOrder::~NativeOrder() {} void NativeOrder::on_activate(Price p, Quantity q, bts::orderman::OrderServices &services, PerfTrace const &t) { + LOG(Latency,Info, "on_activate start {}", key().value()); + auto trace = t; trace.order_key = key().value(); - - tracepoint(bts_trace, trace_order, (char *)"on_activate", 0, trace.md_sn, 0); + trace.order_update = utils::TimeStamp::now(); + + tracepoint(bts_trace, trace_order, (char *)"on_activate", 0, trace.md_sn, key().value()); bts_assert(!me->services); me->services = &services; @@ -384,6 +388,7 @@ void NativeOrder::on_activate(Price p, Quantity q, auto const &ts = services.get_time_str(); me->create_transact_time_bm = encoding.overwrite( me->create_transact_time_bm, &ts.value()[0], ts.value().size()); + trace.send_fix_buffer = utils::TimeStamp::now(); me->session_services->queue_fix(jetfix::MessageTypes::NewOrderSingle, me->create_encoding, trace); me->session_services->governor().record_sent(); @@ -446,6 +451,8 @@ void NativeOrder::on_activate(Price p, Quantity q, break; } report_state(); + LOG(Latency,Diag, "on_activate done fix {} t: {}us", key().value(), + (utils::TimeStamp::now() - trace.order_update).microseconds()); } void NativeOrder::on_update(Price p, Quantity q, PerfTrace const &t) { diff --git a/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp b/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp index 600959052..ad1dedd42 100644 --- a/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp +++ b/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp @@ -186,6 +186,8 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){ } _send_check_termination(true); _report_state(); + LOG(Latency,Diag, "_on_child_order_update k:{} t:{}us", key().value(), + (utils::TimeStamp::now() - trace.spreader_on_child_order_update).microseconds()); } // State Transformations //////////////////// ///////////////////////////////////////////// diff --git a/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h b/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h index 3bc115e8a..de47468a2 100644 --- a/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h +++ b/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h @@ -125,7 +125,7 @@ public: ///////////////////////////////////// void place_order(Price price, Quantity quantity, - const PerfTrace & trace = PerfTrace()){ + const PerfTrace & trace){ _out_price = price; _out_quantity = quantity; bts_assert(_n_place_orders == 0); diff --git a/src/lib/orderman/orders/spreader_orders/tests/spreader_tests.cpp b/src/lib/orderman/orders/spreader_orders/tests/spreader_tests.cpp index 4d2ab8287..0472ba2ee 100644 --- a/src/lib/orderman/orders/spreader_orders/tests/spreader_tests.cpp +++ b/src/lib/orderman/orders/spreader_orders/tests/spreader_tests.cpp @@ -47,7 +47,7 @@ TEST_CASE ("quoter price quantity state", "[spreader]") REQUIRE (s.out_price() == Price (0.0)); REQUIRE (s.out_quantity() == Quantity (0)); // set out price and quantity - order.place_order(Price (-0.35), Quantity (123)); + order.place_order(Price (-0.35), Quantity (123),PerfTrace()); REQUIRE (s.target_spread_price() == Price (-1.0)); REQUIRE (s.target_leg_quantity() == Quantity (200)); REQUIRE (s.aggregated_filled_quantity() == Quantity (25)); @@ -100,7 +100,7 @@ TEST_CASE ("quoter price quantity state", "[spreader]") s.add_hedged_reduction (Quantity(5)); s.add_hedged_reduction (Quantity(15)); // set out values - order_2.place_order (Price(1), Quantity (50)); + order_2.place_order (Price(1), Quantity (50),PerfTrace()); REQUIRE (s.target_spread_price() == Price (-1.0)); REQUIRE (s.target_leg_quantity() == Quantity (200)); REQUIRE (s.aggregated_filled_quantity() == Quantity (40)); @@ -121,7 +121,7 @@ TEST_CASE ("quoter price quantity state", "[spreader]") on_order_update (order_2, api::orderman::OrderStatus::ORDER_STATUS_WORKING, Quantity (10), Price (2000)); s.add_hedged_reduction (Quantity(3)); s.add_hedged_reduction (Quantity(7)); - order_2.place_order (Price(0.75), Quantity (50)); + order_2.place_order (Price(0.75), Quantity (50),PerfTrace()); REQUIRE (s.target_spread_price() == Price (-1.0)); REQUIRE (s.target_leg_quantity() == Quantity (200)); REQUIRE (s.aggregated_filled_quantity() == Quantity (10)); diff --git a/src/lib/orderman/perf_analysis/load_data.py b/src/lib/orderman/perf_analysis/load_data.py index 3e3f9130e..16292e713 100755 --- a/src/lib/orderman/perf_analysis/load_data.py +++ b/src/lib/orderman/perf_analysis/load_data.py @@ -5,7 +5,7 @@ import sqlite3 import dateutil import matplotlib.pyplot as plt import numpy as np - +import sys from pathlib import Path # dt = dateutil.parser.parse('2018-10-23 16:35:01.566000') @@ -14,16 +14,20 @@ from pathlib import Path #samples.plot() requotes = None +hedges = None db_path = "%s/sparkdata/data/databases/perf_trace/perf_trace.sqlite" % str(Path.home()) -c = sqlite3.connect(db_path,uri = True) raw_data = None def load(): global raw_data global requotes - + global hedges + + c = sqlite3.connect(db_path,uri = True) raw_data = pd.read_sql_query("select * from trace;", c) - requotes = raw_data[(raw_data.order_update>0) ] + c.close() + + requotes = raw_data[(raw_data.md>0) ] requotes = requotes.assign (total = (requotes.fix_socket_w - requotes.md) / 1000) requotes = requotes.assign (md = (requotes.spreader_on_book - requotes.md) / 1000) requotes = requotes.assign (spreader = (requotes.order_update - requotes.spreader_on_book) / 1000) @@ -34,12 +38,24 @@ def load(): requotes = requotes.drop(['fix_socket_w','spreader_modify_order','send_fix_buffer', - 'order_update','exe_gw','fix_socket_r','md_src','host', + 'order_update','exe_gw','fix_socket_r','md_src','host', 'do_work_begin', 'order_key','version', 'build_type', 'spreader_on_book', - 'do_work_begin', 'spreader_on_child_order_update','md_sn'],axis=1) - + + hedges = raw_data[(raw_data.spreader_on_child_order_update>0)] + hedges = hedges.assign (total = (hedges.fix_socket_w - hedges.fix_socket_r) / 1000) + hedges = hedges.assign (fix_in = (hedges.spreader_on_child_order_update - hedges.fix_socket_r) / 1000) + hedges = hedges.assign (spreader = (hedges.order_update - hedges.spreader_on_child_order_update)/ 1000) + hedges = hedges.assign (native_order = (hedges.exe_gw - hedges.order_update)/ 1000) + hedges = hedges.assign (fix_out = (hedges.fix_socket_w - hedges.exe_gw)/ 1000) + + hedges = hedges.assign (in_native_order = (hedges.send_fix_buffer - hedges.order_update)/ 1000) + hedges = hedges.drop(['fix_socket_w','spreader_modify_order','send_fix_buffer', + 'order_update','exe_gw','fix_socket_r','md_src','host','do_work_begin', + 'order_key','version', + 'build_type', 'spreader_on_book', + 'spreader_on_child_order_update','md_sn'],axis=1) summary() requotes @@ -55,7 +71,19 @@ def summary(): counts = grouped.count()['total'] medians = grouped.median() medians['count'] = counts + print ("\n\nRequotes") print (medians) + grouped = hedges.groupby(hedges['session_start']) + counts = grouped.count()['total'] + medians = grouped.median() + medians['count'] = counts + print ("\n\nHedges") + print (medians) + + +if len(sys.argv) > 1: + db_path = sys.argv[1] + load() From 361491ebd27db152b854e7d0e23635f7458bf7e1 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Thu, 8 Nov 2018 15:01:23 +0000 Subject: [PATCH 19/29] Removed obsolete test. --- testing/manual/algos/tick.txt | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 testing/manual/algos/tick.txt diff --git a/testing/manual/algos/tick.txt b/testing/manual/algos/tick.txt deleted file mode 100644 index 0aafd36da..000000000 --- a/testing/manual/algos/tick.txt +++ /dev/null @@ -1,32 +0,0 @@ - -- Open up a ladder for a liquid future -- Make sure you have limits to trade this future -- Select Tick order from the menu -Label 1) Set cross thresh to absolute 10 -Label 2) Set initial tick offset to 1 - - -The goal of the tick order is to watch the opposite-inside market size and *cross when that size goes below the threshold -(this also implies a cross if that size goes to zero and the market trades away from you) -(if the market trades toward you, the algo will 'detach' or become a regular limit order by default) - -*cross means take an order working on the bid and 'cross' by buying into the asks. This is also called 'paying up' - -- Open up order book and fills -Label 3) Put an order in to way down in the bid side of the book -- Because of the parameter in label 2, the order should instead join at the best bid -- Watch the opposite inside market, if it dips below the threshold or the market trades away make sure the order moves itself to cross -- Verify that the order filled at the offer price -- If the opposite inside market does not dip below threshhold, you should expect to be eventually filled at the bid price -- If the opposite inside market trades toward you, you should see the algo detach and the limit be left working -- Verify that these fills come in at the proper price, crosses at the offer, working fills at the bid - - -Goto Label 2 and join the ask instead of the bid - { - } -Goto Label l and test the ratio threshold - { - - Use a threshold of at least 1.0 - - Test with a larger order (say 100) to trigger crosses more quickly and across different price levels - } From efd222133e11156bb2c428bf410d69bdcb2427ca Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Thu, 8 Nov 2018 15:01:36 +0000 Subject: [PATCH 20/29] Better perf tools. --- src/lib/orderman/perf_analysis/load_data.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/orderman/perf_analysis/load_data.py b/src/lib/orderman/perf_analysis/load_data.py index 16292e713..e3241996c 100755 --- a/src/lib/orderman/perf_analysis/load_data.py +++ b/src/lib/orderman/perf_analysis/load_data.py @@ -12,6 +12,7 @@ from pathlib import Path # requotes = requotes[requotes.session_start == dt] #samples = requotes.resample('2S',on='trace_time').mean() #samples.plot() +#plotable = requotes[(requotes.total < 1000) & (requotes.trace_time > '2018-11-06')][-200:].set_index('trace_time') requotes = None hedges = None From a4d542067acf9b31469ade97267c6a32b987da05 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Thu, 8 Nov 2018 15:01:46 +0000 Subject: [PATCH 21/29] Benchmarked order state copy. Its slow. --- src/server/sparkd/cmds/Benchmark.cpp | 91 ++++++++++++++-------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/src/server/sparkd/cmds/Benchmark.cpp b/src/server/sparkd/cmds/Benchmark.cpp index aa308cc04..1fb08b323 100644 --- a/src/server/sparkd/cmds/Benchmark.cpp +++ b/src/server/sparkd/cmds/Benchmark.cpp @@ -78,36 +78,36 @@ auto order_str = " order_key: 189285\n" " cti_code: CTI_CTI1\n" " order_status: OS_UNACKNOWLEDGED\n"; -auto order_state_str = " status: ORDER_STATUS_COMPLETED\n" - " price: 65.56\n" - " quantity: 5\n" - " filled_quantity: 5\n" - " last_price: 65.56\n" - " avg_price: 65.56\n" - " last_change {\n" - " seconds: 1532982945\n" - " nanos: 378466000\n" - " }\n" - " limit {\n" - " native_state {\n" - " exchange_order_id: \"12345678901234567\"\n" - " native_status: NATIVE_ORDER_STATUS_FILLED\n" - " last_msg_seq_num: 868\n" - " routing_record {\n" - " session: \"sim\"\n" - " account: \"ca_ACC A\"\n" - " operator_id: \"op_id_bts\"\n" - " cti_code: CTI_CODE_CTI_CODE1\n" - " customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n" - " location: \"us,nc\"\n" - " }\n" - " native_type: NATIVE_ORDER_TYPE_LIMIT\n" - " }\n" - " }\n" - " created {\n" - " seconds: 1532962902\n" - " nanos: 989007000\n" - " }\n"; +auto order_state_str = " status: ORDER_STATUS_WORKING\n" + " price: 73.42\n" + " quantity: 25\n" + " last_msg: \"\"\n" + // " last_change {\n" + // " seconds: 1541621138\n" + // " nanos: 899901000\n" + // " }\n" + // " limit {\n" + // " native_state {\n" + // " exchange_order_id: \"12345678901234567\"\n" + // " native_status: NATIVE_ORDER_STATUS_REPLACED\n" + // " last_msg_seq_num: 31869\n" + // " routing_record {\n" + // " session: \"sim\"\n" + // " account: \"ACC A\"\n" + // " operator_id: \"op_id_bts\"\n" + // " cti_code: CTI_CODE_CTI_CODE1\n" + // " customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n" + // " location: \"us,nc\"\n" + // " }\n" + // " native_type: NATIVE_ORDER_TYPE_LIMIT\n" + // " last_transact_time: \"20181107-20:00:46.000\"\n" + // " }\n" + // " }\n" + // " created {\n" + // " seconds: 1541619812\n" + // " nanos: 895210000\n" + // " }\n"; + ; static void gen_id(benchmark::State &state) { std::string scope = "benchmark"; @@ -161,16 +161,15 @@ static void copy_perf_trace(benchmark::State &state) { } BENCHMARK(copy_perf_trace); -// static void serialize_order(benchmark::State &state) { -// auto order_state = -// utils::pb::from_string(order_state_str); -// auto -// auto order_state_cpy = order_state; -// for (auto _ : state) { -// order_state_cpy = order_state; -// } -// } -// BENCHMARK(copy_order); +static void copy_order_state(benchmark::State &state) { + auto order_state = + utils::pb::from_string(order_state_str); + auto order_state_cpy = order_state; + for (auto _ : state) { + order_state_cpy = order_state; + } +} +BENCHMARK(copy_order_state); static void serialize_update(benchmark::State &state) { api::orderman::Update update; @@ -709,18 +708,18 @@ static void get_time_of_day(benchmark::State &state) { struct timeval tv; for (auto _ : state) { gettimeofday(&tv, nullptr); - auto tm=localtime(&tv.tv_sec); - sprintf(&result[0], "%d%02d%02d-%02d:%02d:%02d.%03d", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min,tm->tm_sec, 0); + auto tm = localtime(&tv.tv_sec); + sprintf(&result[0], "%d%02d%02d-%02d:%02d:%02d.%03d", tm->tm_year, + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0); } } BENCHMARK(get_time_of_day); static void fix_time_stamp(benchmark::State &state) { - std::string r (128,32);auto now = datetime::now(); + std::string r(128, 32); + auto now = datetime::now(); for (auto _ : state) { - datetime::FIX_timestamp(now,&r); + datetime::FIX_timestamp(now, &r); } } BENCHMARK(fix_time_stamp); From b49c764c544599b76aba43796555a950937a760f Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Tue, 13 Nov 2018 22:15:30 +0000 Subject: [PATCH 22/29] Sped up hedging. --- src/lib/api/services/OrderService.proto | 14 +- src/lib/jetfix/connection/AsyncReader.cpp | 1 + .../jetfix/connection/SocketConnection.cpp | 1 + src/lib/jetfix/gateway/CoreGateway.cpp | 2 + src/lib/jetfix/gateway/JetFIXGateway.h | 2 + src/lib/jetfix/gateway/Session.cpp | 1 + src/lib/mercury/broker/BrokerProxy.h | 2 +- src/lib/mercury/common/mercury_common.h | 2 +- src/lib/orderman/actors/ExecutionGateway.cpp | 1 + src/lib/orderman/actors/OrderStore.cpp | 13 +- .../orderman/events/OrderStateUpdateEvent.h | 142 +++++++++++++- src/lib/orderman/orders/IcebergOrder.cpp | 6 +- src/lib/orderman/orders/NativeOrder.cpp | 24 ++- src/lib/orderman/orders/TimeBoxOrder.cpp | 4 +- src/lib/orderman/orders/TriggerOrder.cpp | 9 +- .../orderman/orders/book_algos/BookAlgo.cpp | 6 +- .../orderman/orders/book_algos/CoverOrder.cpp | 4 +- .../orders/spreader_orders/SpreaderOrder.cpp | 14 +- .../orders/spreader_orders/SpreaderOrder.h | 6 +- .../spreader/SpreaderChildOrderState.h | 10 +- .../spreader_orders/spreader/SpreaderUtils.h | 4 +- .../spreader_orders/tests/tests_common.h | 1 - .../orderman/perf_analysis/analyze_logs.py | 27 +++ src/lib/orderman/perf_analysis/load_data.py | 2 +- src/server/sparkd/cmds/Benchmark.cpp | 175 ++++++++++++++---- src/server/sparkd/cmds/QuickTest.cpp | 26 +-- tools/logging/import.sh | 8 +- tools/logging/log.sh | 2 +- 28 files changed, 400 insertions(+), 109 deletions(-) create mode 100755 src/lib/orderman/perf_analysis/analyze_logs.py mode change 100644 => 100755 tools/logging/import.sh mode change 100644 => 100755 tools/logging/log.sh diff --git a/src/lib/api/services/OrderService.proto b/src/lib/api/services/OrderService.proto index d3ca42c59..8c9a00de1 100644 --- a/src/lib/api/services/OrderService.proto +++ b/src/lib/api/services/OrderService.proto @@ -204,7 +204,7 @@ message OrderState { CoverOrderState cover = 22; OffsetOrderState offset = 24; - DynamicOrderState dynamic = 1000; + DynamicOrderState dynamic = 255; // do not use anything bigger than 255, or things will break } } @@ -267,7 +267,7 @@ message LimitOrderState {NativeOrderState native_state = 1;} message StopOrderState {NativeOrderState native_state = 1;} message StopLimitOrderState {NativeOrderState native_state = 1;} message IcebergOrderState {} -message SpreaderOrderState {SpreaderChildKind child_kind = 1;} +message SpreaderOrderState {} message TimeBoxOrderState {} message TickOrderState {} message LeanOrderState {} @@ -276,9 +276,7 @@ message TopOrderState {} message TriggerOrderState {} message CoverOrderState {} message OffsetOrderState {} -message DynamicOrderState { - map state = 1; -} +message DynamicOrderState {} enum OrderStatus { @@ -403,12 +401,6 @@ enum ExecType EXEC_TYPE_TRADE_CANCEL = 72 ; } -enum SpreaderChildKind { - SPREADER_CHILD_KIND_UNDEFINED = 0; - SPREADER_CHILD_KIND_SPREADER_HEDGING = 1; - SPREADER_CHILD_KIND_SPREADER_QUOTING = 2; -} - enum OrderError { ORDER_ERROR_UNDEFINED = 0; diff --git a/src/lib/jetfix/connection/AsyncReader.cpp b/src/lib/jetfix/connection/AsyncReader.cpp index 348f98b5e..4c513f5a5 100644 --- a/src/lib/jetfix/connection/AsyncReader.cpp +++ b/src/lib/jetfix/connection/AsyncReader.cpp @@ -163,6 +163,7 @@ void AsyncReader::dispatch () for (auto &msg : framed_msgs) { msg.set_trace(trace); + LOG(Latency, Diag, "perf_event AsyncReader.on_fix"); tracepoint(bts_trace, trace_order, (char *)"AsyncReader.on_fix", 0, msg.get_seq_num(), 0); me->sink.in_msg_raw (msg); diff --git a/src/lib/jetfix/connection/SocketConnection.cpp b/src/lib/jetfix/connection/SocketConnection.cpp index 22cfce945..10fd1907f 100644 --- a/src/lib/jetfix/connection/SocketConnection.cpp +++ b/src/lib/jetfix/connection/SocketConnection.cpp @@ -83,6 +83,7 @@ int SocketConnection::read(char *to_buffer, size_t read_count) { bts_assert(_fd >= 0); auto result = ::read(_fd, to_buffer, read_count); + LOG(Latency, Diag, "perf_event after_socket_read"); if (_log && result > 0) { _in_log.write(to_buffer, result); _in_log.flush(); diff --git a/src/lib/jetfix/gateway/CoreGateway.cpp b/src/lib/jetfix/gateway/CoreGateway.cpp index a22887e93..1f062ea2f 100644 --- a/src/lib/jetfix/gateway/CoreGateway.cpp +++ b/src/lib/jetfix/gateway/CoreGateway.cpp @@ -394,6 +394,7 @@ void CoreGateway::sync_reader_disconnected(EventData const &) { } void CoreGateway::sync_in_msg_raw(EventData const &ev) { + LOG(Latency, Diag, "perf_event sync_in_msg_raw"); switch (me->state) { case State::OFF: case State::PAUSED: @@ -412,6 +413,7 @@ void CoreGateway::sync_in_msg_raw(EventData const &ev) { } void CoreGateway::sync_in_msg_sequenced(EventData const &ev) { + LOG(Latency, Diag, "perf_event sync_in_msg_sequenced"); switch (me->state) { case State::OFF: case State::PAUSED: diff --git a/src/lib/jetfix/gateway/JetFIXGateway.h b/src/lib/jetfix/gateway/JetFIXGateway.h index fd342cb37..6578bb8fd 100644 --- a/src/lib/jetfix/gateway/JetFIXGateway.h +++ b/src/lib/jetfix/gateway/JetFIXGateway.h @@ -83,8 +83,10 @@ private: void dispatch (InMsgBuffer const&in_msg) override { + LOG(Latency, Diag, "perf_event JetFIXGateway::before_parse"); msg.read (in_msg.data (),in_msg.size ()); msg.set_trace(in_msg.trace()); + LOG(Latency, Diag, "perf_event JetFIXGateway::after_parse"); handler (msg); } diff --git a/src/lib/jetfix/gateway/Session.cpp b/src/lib/jetfix/gateway/Session.cpp index 2ba66f07d..232469c06 100644 --- a/src/lib/jetfix/gateway/Session.cpp +++ b/src/lib/jetfix/gateway/Session.cpp @@ -467,6 +467,7 @@ void Session::on_hb(InMsgBuffer const &msg) { } void Session::on_app(InMsgBuffer const &msg) { + LOG(Latency, Diag, "perf_event on_app"); switch (me->state) { case State::WLOGON: terminate_session( diff --git a/src/lib/mercury/broker/BrokerProxy.h b/src/lib/mercury/broker/BrokerProxy.h index dcbb762b5..225127c79 100644 --- a/src/lib/mercury/broker/BrokerProxy.h +++ b/src/lib/mercury/broker/BrokerProxy.h @@ -12,7 +12,7 @@ namespace bts { namespace mercury { class BrokerProxy : public ILocalBroker { - protected: + public: friend class ActorBroker; enum class BrokerMsgType { ADD_NEIGHBOUR, diff --git a/src/lib/mercury/common/mercury_common.h b/src/lib/mercury/common/mercury_common.h index 4cea2d210..493b0780d 100644 --- a/src/lib/mercury/common/mercury_common.h +++ b/src/lib/mercury/common/mercury_common.h @@ -14,7 +14,7 @@ using TopicFilter = std::function ; using StreamID = utils::ValueWrapper; using SubID = utils::ValueWrapper; -using Notification = FatWrapper<80>; +using Notification = FatWrapper<112>; using LocalSubID = utils::ValueWrapper; using BrokerID = utils::ValueWrapper; diff --git a/src/lib/orderman/actors/ExecutionGateway.cpp b/src/lib/orderman/actors/ExecutionGateway.cpp index a82315897..fbc4c53f0 100644 --- a/src/lib/orderman/actors/ExecutionGateway.cpp +++ b/src/lib/orderman/actors/ExecutionGateway.cpp @@ -78,6 +78,7 @@ void ExecutionGateway::on_securities( // subscribe to gateway events me->gw.on() = [this](auto const &msg) { + LOG(Latency, Diag, "perf_event ExecutionGateway::after_parse"); this->on_exe_report(msg); }; me->gw.on() = [this](auto const &msg) { diff --git a/src/lib/orderman/actors/OrderStore.cpp b/src/lib/orderman/actors/OrderStore.cpp index 1c51b6d22..db6dd64b4 100644 --- a/src/lib/orderman/actors/OrderStore.cpp +++ b/src/lib/orderman/actors/OrderStore.cpp @@ -29,7 +29,7 @@ struct OrderStore::PImpl { State state; const GatewayName gw_name; - std::unordered_map known_orders; + std::unordered_map known_orders; std::unique_ptr store; mercury::Stream order_stream; mercury::Actor::SubHandle stored_sec_sub; @@ -93,7 +93,7 @@ void OrderStore::init() { } else { if (!_order_cutoff(rec)) stored_batch.emplace_back(rec); - me->known_orders[ok] = rec.state().created(); + me->known_orders[ok] = rec.state(); } } else LOG(OrderMan, Error, @@ -122,19 +122,22 @@ void OrderStore::on_order_state_update( order.set_key(ev.key.value()); order.set_parent_key(ev.parent_key.value()); *order.mutable_def() = *ev.definition; - *order.mutable_state() = ev.state; + *order.mutable_state() = ev.rebuild_state(); *order.mutable_state()->mutable_last_change() = utils::pb::pb_now(); auto it = me->known_orders.find(ev.key); if (it == me->known_orders.end()) { // new order auto now = utils::pb::pb_now(); - me->known_orders[ev.key] = now; *order.mutable_state()->mutable_created() = now; + me->known_orders[ev.key] = order.state(); me->store->insert(orders_ns, std::to_string(order.key()), utils::pb::to_string(order)); } else { - *order.mutable_state()->mutable_created() = it->second; + // existing order + auto &existing_state = it->second; + existing_state.MergeFrom(order.state()); + *order.mutable_state() = existing_state; me->store->update(orders_ns, std::to_string(order.key()), utils::pb::to_string(order)); } diff --git a/src/lib/orderman/events/OrderStateUpdateEvent.h b/src/lib/orderman/events/OrderStateUpdateEvent.h index 5758a350b..5e888040c 100644 --- a/src/lib/orderman/events/OrderStateUpdateEvent.h +++ b/src/lib/orderman/events/OrderStateUpdateEvent.h @@ -16,13 +16,147 @@ class OrderStateUpdateEvent : public mercury::Event { api::orderman::OrderDefinition const &def, api::orderman::OrderState const &state, PerfTrace const &trace = PerfTrace()) - : key(key), parent_key(parent_key), definition(&def), state(state), - trace(trace) {} + : key(key), parent_key(parent_key), trace(trace), definition(&def) { + + status = state.status(); + price = state.price(); + quantity = state.quantity(); + filled_quantity = state.filled_quantity(); + last_price = state.last_price(); + avg_price = state.avg_price(); + last_msg = state.last_msg(); + custom = state.custom_case(); + + auto native_state = get_native_state(state); + if (native_state) { + exchange_order_id = native_state->exchange_order_id(); + last_msg_seq_num = native_state->last_msg_seq_num(); + sub_error_code = native_state->sub_error_code(); + native_status = native_state->native_status(); + routing_record = native_state->routing_record(); + native_type = native_state->native_type(); + orderman::str_to(native_state->last_transact_time(), + &last_transact_time); + } + } OrderKey key; OrderKey parent_key; - api::orderman::OrderDefinition const *definition; - api::orderman::OrderState state; + + // common state + api::orderman::OrderStatus status; + double price; + uint32_t quantity; + uint32_t filled_quantity; + double last_price; + double avg_price; + std::string last_msg; + PerfTrace trace; + api::orderman::OrderState::CustomCase custom; + + // native order state + std::string exchange_order_id; + uint64_t last_msg_seq_num; + api::orderman::NativeOrderState::SubError sub_error_code; + api::orderman::NativeOrderStatus native_status; + api::orderman::RoutingRecord routing_record; + api::orderman::NativeOrderType native_type; + mercury::TimeStampStr last_transact_time; + + api::orderman::OrderDefinition const *definition; + + api::orderman::OrderState rebuild_state() const { + api::orderman::OrderState result; + result.set_status(status); + result.set_price(price); + result.set_quantity(quantity); + result.set_filled_quantity(filled_quantity); + result.set_last_price(last_price); + result.set_avg_price(avg_price); + result.set_last_msg(last_msg); + + switch (custom) { + case api::orderman::OrderState::kMarket: + rebuild_native_state(result.mutable_market()->mutable_native_state()); + break; + case api::orderman::OrderState::kLimit: + rebuild_native_state(result.mutable_limit()->mutable_native_state()); + break; + case api::orderman::OrderState::kStop: + rebuild_native_state(result.mutable_stop()->mutable_native_state()); + break; + case api::orderman::OrderState::kStopLimit: + rebuild_native_state(result.mutable_stop_limit()->mutable_native_state()); + break; + case api::orderman::OrderState::kIceberg: + result.mutable_iceberg(); + break; + case api::orderman::OrderState::kSpreader: + result.mutable_spreader(); + break; + case api::orderman::OrderState::kTimeBox: + result.mutable_time_box(); + break; + case api::orderman::OrderState::kTick: + result.mutable_tick(); + break; + case api::orderman::OrderState::kLean: + result.mutable_lean(); + break; + case api::orderman::OrderState::kJoin: + result.mutable_join(); + break; + case api::orderman::OrderState::kTop: + result.mutable_top(); + break; + case api::orderman::OrderState::kTrigger: + result.mutable_trigger(); + break; + case api::orderman::OrderState::kCover: + result.mutable_cover(); + break; + case api::orderman::OrderState::kOffset: + result.mutable_offset(); + break; + case api::orderman::OrderState::kDynamic: + result.mutable_dynamic(); + break; + case api::orderman::OrderState::CUSTOM_NOT_SET: + break; + } + + return result; + } + +private: + void rebuild_native_state(api::orderman::NativeOrderState *st) const + { + st->set_exchange_order_id(exchange_order_id); + st->set_last_msg_seq_num(last_msg_seq_num); + st->set_sub_error_code(sub_error_code); + st->set_native_status(native_status); + *st->mutable_routing_record() = routing_record; + st->set_native_type(native_type); + st->set_last_transact_time(to_str(last_transact_time)); + } + + + api::orderman::NativeOrderState const * + get_native_state(api::orderman::OrderState const &st) { + switch (st.custom_case()) { + case api::orderman::OrderState::kMarket: + return &st.market().native_state(); + case api::orderman::OrderState::kLimit: + return &st.limit().native_state(); + case api::orderman::OrderState::kStop: + return &st.stop().native_state(); + case api::orderman::OrderState::kStopLimit: + return &st.stop_limit().native_state(); + default: + return nullptr; + }; + } + }; } // namespace orderman diff --git a/src/lib/orderman/orders/IcebergOrder.cpp b/src/lib/orderman/orders/IcebergOrder.cpp index 3c81cb1b8..f533f50f3 100644 --- a/src/lib/orderman/orders/IcebergOrder.cpp +++ b/src/lib/orderman/orders/IcebergOrder.cpp @@ -262,9 +262,9 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { switch (me->state.status()) { case ORDER_STATUS_WORKING: if (ev.key == me->child.order.key()) { - me->child.state = ev.state; + me->child.state = ev.rebuild_state(); - switch (ev.state.status()) { + switch (ev.status) { case ORDER_STATUS_WORKING: case ORDER_STATUS_PENDING_WORKING: @@ -314,7 +314,7 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) { "Iceberg order {} received update for non active child order {}." "update state = {}", key().value(), me->child.order.key().value(), - utils::pb::to_string(ev.state)); + utils::pb::to_string(ev.rebuild_state())); } break; diff --git a/src/lib/orderman/orders/NativeOrder.cpp b/src/lib/orderman/orders/NativeOrder.cpp index 4c0fe8657..8d8ab3757 100644 --- a/src/lib/orderman/orders/NativeOrder.cpp +++ b/src/lib/orderman/orders/NativeOrder.cpp @@ -30,7 +30,7 @@ struct NativeOrder::PImpl { PImpl() : services(nullptr), session_services(), sec(nullptr), previous_position_contribution(0), definition(), state(), - price_encoding_precision(7) {} + price_encoding_precision(7),have_exchange_order_id(false) {} OrderServices *services; SessionServices *session_services; @@ -41,7 +41,8 @@ struct NativeOrder::PImpl { OrderDefinition definition; OrderState state; int price_encoding_precision; - + bool have_exchange_order_id; + jetfix::FIXFragment update_encoding; jetfix::FIXFragment::Bookmark update_price_bm; jetfix::FIXFragment::Bookmark update_quantity_bm; @@ -394,9 +395,12 @@ void NativeOrder::on_activate(Price p, Quantity q, me->session_services->governor().record_sent(); me->state.set_status(ORDER_STATUS_PENDING_WORKING); + LOG(Latency,Diag, "on_activate done fix {} t: {}us", key().value(), + (utils::TimeStamp::now() - trace.order_update).microseconds()); LOG(OrderMan, Info, "Sent new order with key {} to gateway", key().value()); - break; + // early return so we skip the expensive report_state() call + return; } // all cases below are for orders recovered from disk @@ -451,8 +455,6 @@ void NativeOrder::on_activate(Price p, Quantity q, break; } report_state(); - LOG(Latency,Diag, "on_activate done fix {} t: {}us", key().value(), - (utils::TimeStamp::now() - trace.order_update).microseconds()); } void NativeOrder::on_update(Price p, Quantity q, PerfTrace const &t) { @@ -669,7 +671,8 @@ void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) { native_state.set_native_status(er.data->order_status); native_state.set_native_type(er.data->order_type); - if (native_state.exchange_order_id().empty()) { + bool got_first_exchange_order_id = !me->have_exchange_order_id; + if (got_first_exchange_order_id) { auto ts = to_trim_str(er.data->exchange_order_id.value()); native_state.set_exchange_order_id(std::string(ts.first, ts.second)); add_exchange_order_id_to_fix(); @@ -712,6 +715,15 @@ void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) { break; } report_state(er.trace); + + // we only need the exhange order id and the routing record + // reported once, since they are both immutable, so we clear them + // after their first report to make subsquent state updates faster + if (got_first_exchange_order_id) { + me->have_exchange_order_id = true; + native_state.clear_exchange_order_id(); + native_state.mutable_routing_record()->Clear(); + } } void NativeOrder::on_cancel_reject(const orderman::CancelRejectEvent &cr) { diff --git a/src/lib/orderman/orders/TimeBoxOrder.cpp b/src/lib/orderman/orders/TimeBoxOrder.cpp index f4fe5893e..542d86a06 100644 --- a/src/lib/orderman/orders/TimeBoxOrder.cpp +++ b/src/lib/orderman/orders/TimeBoxOrder.cpp @@ -320,11 +320,11 @@ void TimeBoxOrder::on_time_change() { void TimeBoxOrder::on_child_order_update(OrderStateUpdateEvent const&ev) { - me->child_state = ev.state; + me->child_state = ev.rebuild_state(); switch (me->state.status()) { case ORDER_STATUS_WORKING: - switch (ev.state.status()) { + switch (ev.status) { case ORDER_STATUS_WORKING: case ORDER_STATUS_PENDING_WORKING: diff --git a/src/lib/orderman/orders/TriggerOrder.cpp b/src/lib/orderman/orders/TriggerOrder.cpp index 7d40227bc..f84235f59 100644 --- a/src/lib/orderman/orders/TriggerOrder.cpp +++ b/src/lib/orderman/orders/TriggerOrder.cpp @@ -232,22 +232,23 @@ void TriggerOrder::_on_book_update(const BookUpdateEvent& b_event){ } void TriggerOrder::_on_child_order_update(const OrderStateUpdateEvent& o_ev){ if(o_ev.key==me->child_order.key()){ - me->child_state=o_ev.state; + auto ev_state = o_ev.rebuild_state(); + me->child_state=ev_state; switch (_state){ case State::START: case State::WAITING_FOR_TRIGGER: bts_assert(false); break; case State::WAITING_FOR_FIRST_ACK: - if(SpreaderUtils::order_acknowledged(o_ev.state.status())){ - if(SpreaderUtils::order_in_terminal_state(o_ev.state.status())) + if(SpreaderUtils::order_acknowledged(o_ev.status)){ + if(SpreaderUtils::order_in_terminal_state(o_ev.status)) _switch_state(State::END); else _switch_state(State::STEADY); } break; case State::STEADY: - if(SpreaderUtils::order_in_terminal_state(o_ev.state.status())) + if(SpreaderUtils::order_in_terminal_state(ev_state.status())) _switch_state(State::END); break; case State::END: diff --git a/src/lib/orderman/orders/book_algos/BookAlgo.cpp b/src/lib/orderman/orders/book_algos/BookAlgo.cpp index 0c463b739..5e3ea18ae 100644 --- a/src/lib/orderman/orders/book_algos/BookAlgo.cpp +++ b/src/lib/orderman/orders/book_algos/BookAlgo.cpp @@ -343,15 +343,15 @@ void BookAlgo::on_child_order_update(const OrderStateUpdateEvent& ev) if(me->fake_detached_child) return; if(ev.key != me->child.key()) - me->hedges_state[ev.key] = ev.state; + me->hedges_state[ev.key] = ev.rebuild_state(); else { api::orderman::OrderState orig_state = child_state(); - me->child_state = ev.state; + me->child_state = ev.rebuild_state(); switch (this_state().status()) { case ORDER_STATUS_WORKING: - switch (ev.state.status()) + switch (ev.status) { case ORDER_STATUS_PENDING_WORKING: break; diff --git a/src/lib/orderman/orders/book_algos/CoverOrder.cpp b/src/lib/orderman/orders/book_algos/CoverOrder.cpp index 886598e94..de1f773be 100644 --- a/src/lib/orderman/orders/book_algos/CoverOrder.cpp +++ b/src/lib/orderman/orders/book_algos/CoverOrder.cpp @@ -52,10 +52,10 @@ bool CoverOrder::setup_hedge(const api::orderman::OrderDefinition& this_def, con void CoverOrder::send_hedge_if_new_fills(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state) { - uint32_t qty = new_state.state.filled_quantity() - orig_state.filled_quantity(); + uint32_t qty = new_state.filled_quantity - orig_state.filled_quantity(); if(qty > 0) { - double prx = new_state.state.last_price(); + double prx = new_state.last_price; if(definition().side() == api::SIDE_BUY) //if this is a buy, I'm going to sell my hedge, nticks higher than the fill price prx = prx + tick_size() * me->hedge_ticks; else diff --git a/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp b/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp index ad1dedd42..cccba1190 100644 --- a/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp +++ b/src/lib/orderman/orders/spreader_orders/SpreaderOrder.cpp @@ -121,11 +121,11 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){ if (!_active) return; SecurityKey sec_key = SecurityKey(ord_ev.definition->security_key()); OrderKey order_key = ord_ev.key; - bts::api::orderman::OrderStatus status = ord_ev.state.status(); + bts::api::orderman::OrderStatus status = ord_ev.status; - Quantity filled_qty = Quantity (ord_ev.state.filled_quantity()); - Price last_price = Price(ord_ev.state.last_price()), - order_price=Price(ord_ev.state.price()); + Quantity filled_qty = Quantity (ord_ev.filled_quantity); + Price last_price = Price(ord_ev.last_price), + order_price=Price(ord_ev.price); if (!SpreaderUtils::order_acknowledged(status)){ LOG(OrderMan, Diag, "SpreaderOrder::_on_child_order_update, unack'ed " "callback for key:{} sec_key:{} order_key:{} " @@ -146,7 +146,7 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){ key(), sec_key, static_cast(_state_worker->state()), order_key, status, filled_qty, order_price, last_price, - ord_ev.state.last_msg(), static_cast(order_error)); + ord_ev.last_msg, static_cast(order_error)); leg_data.order_update_message().on_order_update(ord_ev); if (order_error == ChildOrderError::NONE){ if (leg_data.order_update_message().last_update_filled_quantity().value() > 0) @@ -170,7 +170,7 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){ key(), sec_key, static_cast(_state_worker->state()), order_key, status, filled_qty, order_price, last_price, - ord_ev.state.last_msg (), static_cast(order_error)); + ord_ev.last_msg, static_cast(order_error)); hedger->order_state().on_order_update(ord_ev); if (order_error == ChildOrderError::NONE) _state_worker->on_hedger_order_update (*hedger); @@ -182,7 +182,7 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){ "key:{} sec_key:{} order_key:{} status:{} " "filled_qty:{} last_price:{} msg:{}", key(), sec_key, order_key, status, filled_qty, - last_price, ord_ev.state.last_msg ()); + last_price, ord_ev.last_msg); } _send_check_termination(true); _report_state(); diff --git a/src/lib/orderman/orders/spreader_orders/SpreaderOrder.h b/src/lib/orderman/orders/spreader_orders/SpreaderOrder.h index c04930980..9b377d948 100644 --- a/src/lib/orderman/orders/spreader_orders/SpreaderOrder.h +++ b/src/lib/orderman/orders/spreader_orders/SpreaderOrder.h @@ -209,7 +209,7 @@ private: static ChildOrderError _get_order_error (const OrderStateUpdateEvent& ord_ev, bool expecting_cancel){ - bts::api::orderman::OrderStatus order_status = ord_ev.state.status(); + bts::api::orderman::OrderStatus order_status = ord_ev.status; if (SpreaderUtils::order_in_error_state(order_status)) return ChildOrderError::ORDER_STATE_ERROR; if (SpreaderUtils::SpreaderUtils::order_in_cancelled_state(order_status)){ @@ -218,12 +218,12 @@ private: // i. cancels with messages are always an error state // ii. when we get a cancel when not expecting thats also // an error state - if(ord_ev.state.last_msg().length() > 0 || !expecting_cancel) + if(ord_ev.last_msg.length() > 0 || !expecting_cancel) return ChildOrderError::UNEXPECTED_CANCEL_ERROR; } // this is an inelegant way to detect modify errors if (!SpreaderUtils::order_in_terminal_state(order_status) && - ord_ev.state.last_msg().length() > 0) + ord_ev.last_msg.length() > 0) return ChildOrderError::MODIFY_ERROR; return ChildOrderError::NONE; } diff --git a/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h b/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h index de47468a2..4d7ccc4d2 100644 --- a/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h +++ b/src/lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h @@ -109,11 +109,11 @@ public: // last filled price void on_order_update(const bts::orderman::OrderStateUpdateEvent& e){ bts_assert(!_is_live || e.key == order_key()); - bts_assert(e.state.filled_quantity() >= _filled_quantity.value()); - _status = e.state.status(); - _last_filled_quantity = Quantity(e.state.filled_quantity() - _filled_quantity.value()); - _last_filled_price = Price(e.state.last_price()); - _last_reported_order_price=Price(e.state.price()); + bts_assert(e.filled_quantity >= _filled_quantity.value()); + _status = e.status; + _last_filled_quantity = Quantity(e.filled_quantity - _filled_quantity.value()); + _last_filled_price = Price(e.last_price); + _last_reported_order_price=Price(e.price); SpreaderUtils::compute_average_price(_filled_price, _filled_quantity, _last_filled_price, diff --git a/src/lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h b/src/lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h index 792b7a4c6..37a7f37c9 100644 --- a/src/lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h +++ b/src/lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h @@ -72,9 +72,9 @@ public: // this function checks for the order status (above) or // for the message size (todo:this is a temporary fix) static bool order_in_error_state(const bts::orderman::OrderStateUpdateEvent& ord_ev){ - bts::api::orderman::OrderStatus order_status = ord_ev.state.status(); + bts::api::orderman::OrderStatus order_status = ord_ev.status; return order_in_error_state(order_status) || - (!order_in_terminal_state (order_status) && ord_ev.state.last_msg().length() > 0); + (!order_in_terminal_state (order_status) && ord_ev.last_msg.length() > 0); } // checks for the 4 states that are designated error states static bool order_in_terminal_state(bts::api::orderman::OrderStatus order_status){ diff --git a/src/lib/orderman/orders/spreader_orders/tests/tests_common.h b/src/lib/orderman/orders/spreader_orders/tests/tests_common.h index 487cb6021..7792d29c3 100644 --- a/src/lib/orderman/orders/spreader_orders/tests/tests_common.h +++ b/src/lib/orderman/orders/spreader_orders/tests/tests_common.h @@ -103,7 +103,6 @@ void on_order_update (SpreaderChildOrderState& order, order_state.set_filled_quantity (filled_quantity.value()); bts::api::orderman::OrderDefinition order_def; OrderStateUpdateEvent e (OrderKey(),OrderKey(),order_def, order_state); - e.state = order_state; order.on_order_update(e); } /**********************************************************************/ diff --git a/src/lib/orderman/perf_analysis/analyze_logs.py b/src/lib/orderman/perf_analysis/analyze_logs.py new file mode 100755 index 000000000..8ad7e9234 --- /dev/null +++ b/src/lib/orderman/perf_analysis/analyze_logs.py @@ -0,0 +1,27 @@ +#!/usr/bin/python3 + +import pandas as pd +import sqlite3 +import dateutil +import matplotlib.pyplot as plt +import numpy as np +import sys +from pathlib import Path + +log_path = "%s/sparkdata/data/logging/log" % str(Path.home()) +raw_data = None + +def load(): + global raw_data + global requotes + global hedges + + raw_data = pd.read_csv(log_path,sep='|',names=['time','ts','ss','ll','tid','tn','pid','loc','dt','msg'], + usecols=lambda x: x in ['time','ts','tn','msg'], + parse_dates=True) + +if len(sys.argv) > 1: + log_path = sys.argv[1] + +load() + diff --git a/src/lib/orderman/perf_analysis/load_data.py b/src/lib/orderman/perf_analysis/load_data.py index e3241996c..09b4e0340 100755 --- a/src/lib/orderman/perf_analysis/load_data.py +++ b/src/lib/orderman/perf_analysis/load_data.py @@ -16,7 +16,7 @@ from pathlib import Path requotes = None hedges = None -db_path = "%s/sparkdata/data/databases/perf_trace/perf_trace.sqlite" % str(Path.home()) +db_path = "file:%s/sparkdata/data/databases/perf_trace/perf_trace.sqlite?mode=ro" % str(Path.home()) raw_data = None def load(): diff --git a/src/server/sparkd/cmds/Benchmark.cpp b/src/server/sparkd/cmds/Benchmark.cpp index 1fb08b323..e25268b4c 100644 --- a/src/server/sparkd/cmds/Benchmark.cpp +++ b/src/server/sparkd/cmds/Benchmark.cpp @@ -6,6 +6,7 @@ #include "lib/mercury/actors/Actor.h" #include "lib/mercury/common/FatWrapper.h" #include "lib/mercury/executor/Executor.h" +#include "lib/orderman/events/OrderStateUpdateEvent.h" #include "lib/os/os.h" #include "lib/utils/PBUtils.h" #include "lib/utils/Puid.h" @@ -37,6 +38,80 @@ namespace bts { namespace cmd { +using namespace orderman; + +api::orderman::NativeOrderState const * +get_native_state(api::orderman::OrderState const &st) { + switch (st.custom_case()) { + case api::orderman::OrderState::kMarket: + return &st.market().native_state(); + case api::orderman::OrderState::kLimit: + return &st.limit().native_state(); + case api::orderman::OrderState::kStop: + return &st.stop().native_state(); + case api::orderman::OrderState::kStopLimit: + return &st.stop_limit().native_state(); + default: + return nullptr; + }; +} + +class QuickOrderStateUpdateEvent { + public: + QuickOrderStateUpdateEvent(OrderKey key, OrderKey parent_key, + api::orderman::OrderDefinition const &def, + api::orderman::OrderState const &state, + PerfTrace const &trace = PerfTrace()) + : key(key), parent_key(parent_key), trace(trace), definition(&def) { + + status = state.status(); + price = state.price(); + quantity = state.quantity(); + filled_quantity = state.quantity(); + last_price = state.last_price(); + avg_price = state.avg_price(); + last_msg = state.last_msg(); + custom = state.custom_case(); + + auto native_state = get_native_state(state); + if (native_state) { + exchange_order_id = native_state->exchange_order_id(); + last_msg_seq_num = native_state->last_msg_seq_num(); + sub_error_code = native_state->sub_error_code(); + native_status = native_state->native_status(); + routing_record = native_state->routing_record(); + native_type = native_state->native_type(); + orderman::str_to(native_state->last_transact_time(),&last_transact_time); + } + } + + OrderKey key; + OrderKey parent_key; + + // common state + api::orderman::OrderStatus status; + double price; + uint32_t quantity; + uint32_t filled_quantity; + double last_price; + double avg_price; + std::string last_msg; + + PerfTrace trace; + api::orderman::OrderState::CustomCase custom; + + // native order state + std::string exchange_order_id; + uint64_t last_msg_seq_num; + api::orderman::NativeOrderState::SubError sub_error_code; + api::orderman::NativeOrderStatus native_status; + api::orderman::RoutingRecord routing_record; + api::orderman::NativeOrderType native_type; + mercury::TimeStampStr last_transact_time; + + api::orderman::OrderDefinition const *definition; +}; + auto sec_str = " id: 3\n" " symbol: \"ES\"\n" " exchange: VENUE_GLBX\n" @@ -82,32 +157,54 @@ auto order_state_str = " status: ORDER_STATUS_WORKING\n" " price: 73.42\n" " quantity: 25\n" " last_msg: \"\"\n" - // " last_change {\n" - // " seconds: 1541621138\n" - // " nanos: 899901000\n" - // " }\n" - // " limit {\n" - // " native_state {\n" - // " exchange_order_id: \"12345678901234567\"\n" - // " native_status: NATIVE_ORDER_STATUS_REPLACED\n" - // " last_msg_seq_num: 31869\n" - // " routing_record {\n" - // " session: \"sim\"\n" - // " account: \"ACC A\"\n" - // " operator_id: \"op_id_bts\"\n" - // " cti_code: CTI_CODE_CTI_CODE1\n" - // " customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n" - // " location: \"us,nc\"\n" - // " }\n" - // " native_type: NATIVE_ORDER_TYPE_LIMIT\n" - // " last_transact_time: \"20181107-20:00:46.000\"\n" - // " }\n" - // " }\n" - // " created {\n" - // " seconds: 1541619812\n" - // " nanos: 895210000\n" - // " }\n"; - ; + " last_change {\n" + " seconds: 1541621138\n" + " nanos: 899901000\n" + " }\n" + " limit {\n" + " native_state {\n" + " exchange_order_id: \"12345678901234567\"\n" + " native_status: NATIVE_ORDER_STATUS_REPLACED\n" + " last_msg_seq_num: 31869\n" + " routing_record {\n" + " session: \"sim\"\n" + " account: \"ACC A\"\n" + " operator_id: \"op_id_bts\"\n" + " cti_code: CTI_CODE_CTI_CODE1\n" + " customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n" + " location: \"us,nc\"\n" + " }\n" + " native_type: NATIVE_ORDER_TYPE_LIMIT\n" + " last_transact_time: \"20181107-20:00:46.000\"\n" + " }\n" + " }\n" + " created {\n" + " seconds: 1541619812\n" + " nanos: 895210000\n" + " }\n"; + +auto clean_os = + " status: ORDER_STATUS_WORKING\n" + " price: 73.42\n" + " quantity: 25\n" + " last_msg: \"\"\n" + " limit {\n" + " native_state {\n" + //" exchange_order_id: \"12345678901234567\"\n" + " native_status: NATIVE_ORDER_STATUS_REPLACED\n" + " last_msg_seq_num: 31869\n" + // " routing_record {\n" + // " session: \"sim\"\n" + // " account: \"ACC A\"\n" + // " operator_id: \"op_id_bts\"\n" + // " cti_code: CTI_CODE_CTI_CODE1\n" + // " customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n" + // " location: \"us,nc\"\n" + // " }\n" + " native_type: NATIVE_ORDER_TYPE_LIMIT\n" + " last_transact_time: \"20181107-20:00:46.000\"\n" + " }\n" + " }\n"; static void gen_id(benchmark::State &state) { std::string scope = "benchmark"; @@ -161,15 +258,29 @@ static void copy_perf_trace(benchmark::State &state) { } BENCHMARK(copy_perf_trace); -static void copy_order_state(benchmark::State &state) { +static void init_with_clean_os(benchmark::State &state) { + api::orderman::OrderDefinition def; + auto order_state = + utils::pb::from_string(clean_os); + PerfTrace trace; + OrderKey k(1); + for (auto _ : state) + benchmark::DoNotOptimize( + QuickOrderStateUpdateEvent(k, k, def, order_state, trace)); +} +BENCHMARK(init_with_clean_os); + +static void init_with_old_order_update(benchmark::State &state) { + api::orderman::OrderDefinition def; auto order_state = utils::pb::from_string(order_state_str); - auto order_state_cpy = order_state; - for (auto _ : state) { - order_state_cpy = order_state; - } + PerfTrace trace; + OrderKey k(1); + for (auto _ : state) + benchmark::DoNotOptimize( + orderman::OrderStateUpdateEvent(k, k, def, order_state, trace)); } -BENCHMARK(copy_order_state); +BENCHMARK(init_with_old_order_update); static void serialize_update(benchmark::State &state) { api::orderman::Update update; diff --git a/src/server/sparkd/cmds/QuickTest.cpp b/src/server/sparkd/cmds/QuickTest.cpp index f97740319..84d9931e1 100644 --- a/src/server/sparkd/cmds/QuickTest.cpp +++ b/src/server/sparkd/cmds/QuickTest.cpp @@ -1,32 +1,36 @@ #include "QuickTest.h" #include "ICmd.h" +#include "lib/api/services/OrderService.server.pb.h" #include "lib/mercury/actors/PingPong.h" +#include "lib/mercury/broker/BrokerProxy.h" +#include "lib/mercury/common/mercury_common.h" #include "lib/mercury/executor/Executor.h" +#include "lib/utils/PBUtils.h" #include "lib/utils/thread_manager.h" +#include "lib/orderman/events/OrderStateUpdateEvent.h" #include namespace bts { namespace cmd { -int QuickTest::execute(std::vector const &) { - threading::configure_current_thread("busy_poll"); - std::set s; - for (int i = 0; i < 1<<23;i++) - s.insert(i); +using namespace bts::mercury; +using namespace bts::orderman; - auto sum = 0; - for(;;) { - for (auto &b : s) - sum+=b; +int QuickTest::execute(std::vector const &) { + sleep_for(10s); + for (int i = 0; i < 100; i++) { + auto t = utils::TimeStamp::now(); + LOG(OrderMan,Info,"Now: {}", (utils::TimeStamp::now() - t).nanoseconds()); } - return sum; + sleep_for(10s); + return 0; } std::string QuickTest::help() { return "This is a place holder to make it easy to quickly write discardable " - "test code"; + "test code"; } } // namespace cmd } // namespace bts diff --git a/tools/logging/import.sh b/tools/logging/import.sh old mode 100644 new mode 100755 index 5d980061c..8e18118c5 --- a/tools/logging/import.sh +++ b/tools/logging/import.sh @@ -1,11 +1,11 @@ #!/bin/bash -sed 's/[ \t]*|/|/g' sparkdata/data/logging/log >clean +grep '|' ~/sparkdata/data/logging/log | sed 's/[ \t]*|/|/g' > clean_db rm log_db sqlite3 log_db < log.csv diff --git a/tools/logging/log.sh b/tools/logging/log.sh old mode 100644 new mode 100755 index 160c58d00..67f624c81 --- a/tools/logging/log.sh +++ b/tools/logging/log.sh @@ -1,3 +1,3 @@ #!/bin/bash -tac ~/.bts/data/logging/log | grep "Sparkd launched" -m 1 -B 999999 | tac | sort -n -t '|' -k 2,5 | sed 's/[ \t]*|/|/g' | column -t -s'|' +grep Latency ~/sparkdata/data/logging/log | sort -n -t '|' -k 2,5 From 141e1a4ea06d0bf9b0958c8be5b2ef546f1f03d0 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Tue, 13 Nov 2018 22:39:57 +0000 Subject: [PATCH 23/29] Fixed build. --- src/lib/CMakeDeps.cmake | 2 +- src/lib/md/MDProducerHandle.h | 2 +- src/sdk/examples/order_plugin_example.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/CMakeDeps.cmake b/src/lib/CMakeDeps.cmake index 1552418c6..cd221187f 100644 --- a/src/lib/CMakeDeps.cmake +++ b/src/lib/CMakeDeps.cmake @@ -1 +1 @@ -set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;os/os.cpp;os/tests/os_tests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/thread_manager.cpp) \ No newline at end of file +set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/IPollableActor.cpp;mercury/broker/Broker.cpp;mercury/broker/BrokerProxy.cpp;mercury/broker/ILocalBroker.cpp;mercury/broker/IRemoteBroker.cpp;mercury/common/mercury_common.cpp;mercury/events/TimerEvent.cpp;mercury/executor/Executor.cpp;mercury/topics/Topic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/MDSupplementarySource.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/DynamicOrderRegistry.cpp;orderman/order_factory/OrderFactory.cpp;orderman/order_router/OrderRouter.cpp;orderman/orderman_utils/PerfTraceLog.cpp;orderman/orderman_utils/fix_order_codec.cpp;orderman/orders/DynamicOrder.cpp;orderman/orders/IcebergOrder.cpp;orderman/orders/NativeOrder.cpp;orderman/orders/Order.cpp;orderman/orders/TimeBoxOrder.cpp;orderman/orders/TriggerOrder.cpp;orderman/orders/book_algos/BookAlgo.cpp;orderman/orders/book_algos/CoverOrder.cpp;orderman/orders/book_algos/JoinOrder.cpp;orderman/orders/book_algos/LeanOrder.cpp;orderman/orders/book_algos/OffsetOrder.cpp;orderman/orders/book_algos/TickOrder.cpp;orderman/orders/book_algos/TopOrder.cpp;orderman/orders/spreader_orders/SpreaderOrder.cpp;orderman/orders/spreader_orders/spreader/LegPropertyData.cpp;orderman/orders/spreader_orders/spreader/QuoteLegPriceQuantityState.cpp;orderman/orders/spreader_orders/spreader/SingleFillHedger.cpp;orderman/orders/spreader_orders/spreader/SingleLegQuoter.cpp;orderman/orders/spreader_orders/spreader/SpreaderBookkeepingData.cpp;orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.cpp;orderman/orders/spreader_orders/spreader/SpreaderLegData.cpp;orderman/orders/spreader_orders/spreader/SpreaderUtils.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderBuilder.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderServices.cpp;orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderPreActivationOrderServices.cpp;orderman/orders/spreader_orders/spreader/hedger/UnhedgedDelta.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerEndStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerStartStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForCancelAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForFirstAckCancelledStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWaitingForFirstAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerWorkingStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteDriverSet.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteDriverSetHistory.cpp;orderman/orders/spreader_orders/spreader/quoter/QuoteLegDriver.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterEndStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterStartStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForCancelAckStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForFirstAckCancelledWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForFirstAckWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForIOCWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForSizeStateWorker.cpp;orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWorkingStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderEndStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderStartStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWaitingForCancelAllStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWaitingForInitialDataStateWorker.cpp;orderman/orders/spreader_orders/spreader_states/SpreaderWorkingStateWorker.cpp;orderman/orders/spreader_orders/tests/spreader_tests.cpp;orderman/server/OrderServiceServer.cpp;orderman/tests/fat_wrapper_tests.cpp;orderman2/OrderManager2.cpp;os/os.cpp;os/tests/os_tests.cpp;persistence/IStore.cpp;persistence/PersistenceServiceServer.cpp;persistence/SqliteStore.cpp;persistence/persistence_utils.cpp;persistence/tests/PersistenceServiceTests.cpp;plugin/SparkServices.cpp;plugin/plugin.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/thread_manager.cpp) \ No newline at end of file diff --git a/src/lib/md/MDProducerHandle.h b/src/lib/md/MDProducerHandle.h index 5f5e5f52b..2d864f927 100644 --- a/src/lib/md/MDProducerHandle.h +++ b/src/lib/md/MDProducerHandle.h @@ -118,7 +118,7 @@ private: // Private default constructor allows friend classes to store this class in a concurrent_queue MDProducerHandle(); friend class tbb::concurrent_queue < MDProducerHandle > ; - friend class SecurityIDRecorderState; + friend struct SecurityIDRecorderState; friend struct bts::co2::Work; HotEntry& hdata() const { diff --git a/src/sdk/examples/order_plugin_example.cpp b/src/sdk/examples/order_plugin_example.cpp index dd42a6e00..c7eb0e2b8 100644 --- a/src/sdk/examples/order_plugin_example.cpp +++ b/src/sdk/examples/order_plugin_example.cpp @@ -264,9 +264,9 @@ void DynamicIcebergOrder::on_child_order_update( switch (me->state.status()) { case ORDER_STATUS_WORKING: if (ev.key == me->child.order.key()) { - me->child.state = ev.state; + me->child.state = ev.rebuild_state(); - switch (ev.state.status()) { + switch (me->child.state.status()) { case ORDER_STATUS_WORKING: case ORDER_STATUS_PENDING_WORKING: @@ -312,7 +312,7 @@ void DynamicIcebergOrder::on_child_order_update( "DynamicIceberg order {} received update for non active child " "order{} . update state = {} ", key().value(), me->child.order.key().value(), - utils::pb::to_string(ev.state)); + utils::pb::to_string(ev.rebuild_state())); } break; From c2dfcbe3436d3ccedde17e88ce8f183cf5063a11 Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Wed, 14 Nov 2018 20:56:41 +0000 Subject: [PATCH 24/29] Made sql store a bit more tolerant to errors. --- src/lib/persistence/SqliteStore.cpp | 70 ++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/src/lib/persistence/SqliteStore.cpp b/src/lib/persistence/SqliteStore.cpp index 814ae95f1..1c4a2c833 100644 --- a/src/lib/persistence/SqliteStore.cpp +++ b/src/lib/persistence/SqliteStore.cpp @@ -2,12 +2,13 @@ #include "lib/logging/logging.h" #include "lib/os/os.h" +#include "lib/persistence/persistence_utils.h" #include "lib/utils/Sqlite_utils.h" #include "lib/utils/bts_assert.h" +#include "lib/utils/bts_chrono.h" #include "lib/utils/bts_no_copy.h" #include "lib/utils/defer.h" #include "lib/utils/file_utils.h" -#include "lib/persistence/persistence_utils.h" #include #include @@ -15,10 +16,9 @@ namespace bts { namespace persistence { - struct SqliteStore::PImpl { PImpl(std::string const &store_root, std::string const &db_name) - : db(db_name), db_path(persistence::storage_location(db,store_root)), + : db(db_name), db_path(persistence::storage_location(db, store_root)), conn(nullptr, sqlite3_close), insert(nullptr, sqlite3_finalize), remove(nullptr, sqlite3_finalize), remove_all(nullptr, sqlite3_finalize), @@ -155,7 +155,22 @@ void SqliteStore::remove(std::string const &ns, SQLITE_CHK(sqlite3_bind_text(me->remove.get(), 2, k.c_str(), k.size(), SQLITE_TRANSIENT), me->conn); - bts_assert(sqlite3_step(me->remove.get()) == SQLITE_DONE); + auto r = sqlite3_step(me->remove.get()); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Could not delete row in store. Will retry once. error_code: {} " + "ns:{}, k: {}", + r, ns, k); + sleep_for(2s); + r = sqlite3_step(me->remove.get()); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Failed a second time to delete row. Bailing out. error_code: " + "{}", + r); + bts_assert(r == SQLITE_DONE); + } + } SQLITE_CHK(sqlite3_reset(me->remove.get()), me->conn); } } @@ -165,7 +180,22 @@ void SqliteStore::remove_all(std::string const &ns) { SQLITE_CHK(sqlite3_bind_text(me->remove_all.get(), 1, ns.c_str(), ns.size(), SQLITE_TRANSIENT), me->conn); - bts_assert(sqlite3_step(me->remove_all.get()) == SQLITE_DONE); + auto r = sqlite3_step(me->remove_all.get()); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Could not delete all rows in store. Will retry once. error_code: {} " + "ns:{}", + r, ns); + sleep_for(2s); + r = sqlite3_step(me->remove_all.get()); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Failed a second time to delete all rows. Bailing out. error_code: " + "{}", + r); + bts_assert(r == SQLITE_DONE); + } + } SQLITE_CHK(sqlite3_reset(me->remove_all.get()), me->conn); } @@ -181,7 +211,20 @@ void SqliteStore::insert(std::string const &ns, std::string const &k, SQLITE_TRANSIENT), me->conn); auto r = sqlite3_step(me->insert.get()); - bts_assert(r == SQLITE_DONE); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Could not insert row in store. Will retry once. error_code: {} ns: " + "{}, k: {}, v: {}", + r, ns, k, v); + sleep_for(2s); + r = sqlite3_step(me->insert.get()); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Failed a second time to insert row. Bailing out. error_code: {}", + r); + bts_assert(r == SQLITE_DONE); + } + } SQLITE_CHK(sqlite3_reset(me->insert.get()), me->conn); } @@ -197,7 +240,20 @@ void SqliteStore::update(std::string const &ns, std::string const &k, SQLITE_TRANSIENT), me->conn); auto r = sqlite3_step(me->update.get()); - bts_assert(r == SQLITE_DONE); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Could not update row in store. Will retry once. error_code: {} ns: " + "{}, k: {}, v: {}", + r, ns, k, v); + sleep_for(2s); + r = sqlite3_step(me->update.get()); + if (r != SQLITE_DONE) { + LOG(persist, Error, + "Failed a second time to update row. Bailing out. error_code: {}", + r); + bts_assert(r == SQLITE_DONE); + } + } SQLITE_CHK(sqlite3_reset(me->update.get()), me->conn); } From ddb4e55d13d3c79191d5d40ba30ec81aea2766ce Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Wed, 14 Nov 2018 21:36:31 +0000 Subject: [PATCH 25/29] Changed public to protected member access --- src/lib/mercury/broker/BrokerProxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/mercury/broker/BrokerProxy.h b/src/lib/mercury/broker/BrokerProxy.h index 225127c79..dcbb762b5 100644 --- a/src/lib/mercury/broker/BrokerProxy.h +++ b/src/lib/mercury/broker/BrokerProxy.h @@ -12,7 +12,7 @@ namespace bts { namespace mercury { class BrokerProxy : public ILocalBroker { - public: + protected: friend class ActorBroker; enum class BrokerMsgType { ADD_NEIGHBOUR, From 00e9de3b1eabafe0a03fe5ab18ea892656e025d5 Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Wed, 14 Nov 2018 17:01:18 -0500 Subject: [PATCH 26/29] Hedges only shows total --- src/data_files/files/perf_trace/main.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index ab930b494..f738eb790 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -232,7 +232,7 @@ function display_session (quot_val, hed_val) { } session_info += ""; if (safe_hed_val.summaries[i] !== undefined && safe_hed_val.summaries[i].value !== "total") { - session_info += write_summary(safe_hed_val.session_name + "-hed-" + safe_hed_val.summaries[i].value, safe_hed_val.summaries[i]); + //session_info += write_summary(safe_hed_val.session_name + "-hed-" + safe_hed_val.summaries[i].value, safe_hed_val.summaries[i]); } session_info += ""; } @@ -270,7 +270,10 @@ function display_session (quot_val, hed_val) { generate_histogram(safe_quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); }); + generate_histogram(safe_hed_val.session_name + "-hed-total", hed_val_data["total"]); + /* $(safe_hed_val.summaries).each(function(i,v){ generate_histogram(safe_hed_val.session_name + "-hed-" + v.value, hed_val_data[v.value]); }); + */ } \ No newline at end of file From 4f830cdd400a37c157d9db55b1f281bf3637130e Mon Sep 17 00:00:00 2001 From: Pedro Pinto Date: Wed, 14 Nov 2018 22:06:39 +0000 Subject: [PATCH 27/29] Removed obsolete stats. --- src/lib/orderman/orderman_utils/PerfTraceLog.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib/orderman/orderman_utils/PerfTraceLog.cpp b/src/lib/orderman/orderman_utils/PerfTraceLog.cpp index e6ac1e32c..df38650a4 100644 --- a/src/lib/orderman/orderman_utils/PerfTraceLog.cpp +++ b/src/lib/orderman/orderman_utils/PerfTraceLog.cpp @@ -21,7 +21,7 @@ namespace bts { -auto current_schema_version = 2; +auto current_schema_version = 3; auto insert_trace = "insert into trace (" "version," @@ -100,9 +100,9 @@ auto requote_trace_view = "drop view if exists requote_trace; " "trace_time," "order_key," "(fix_socket_w-md) / 1000.0 total," - "(spreader_on_book - md) / 1000.0 md," - "(send_fix_buffer-spreader_on_book)/1000.0 spreader," - "(fix_socket_w-send_fix_buffer)/1000.0 fix " + "0 md," + "0 spreader," + "0 fix " "from " "trace " "where md<>0 and (md_src-md)<1000000"; @@ -112,9 +112,9 @@ auto hedge_trace_view = "CREATE VIEW hedge_trace as " "select version, host, build_type, session_start,trace_time,order_key, " "(fix_socket_w-fix_socket_r) / 1000.0 total, " - "(spreader_on_child_order_update - fix_socket_r) / 1000.0 fix_in, " - "(send_fix_buffer-spreader_on_child_order_update)/1000.0 spreader, " - "(fix_socket_w-send_fix_buffer)/1000.0 fix_out " + "0 fix_in, " + "0 spreader, " + "0 fix_out " "from trace where fix_socket_r<>0 "; auto requote_query = From e32f40caee9a874664c6c82c93ff41abb647fd38 Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Thu, 15 Nov 2018 10:34:56 -0500 Subject: [PATCH 28/29] Fix session handling in perf_trace ui --- src/data_files/files/perf_trace/main.js | 34 +++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index f738eb790..0a54cbf2f 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -36,19 +36,23 @@ $( document ).ready(function (){ $("#output").html(summary_info); - $(useful_result).each(function (index, quot_val){ - if(less_useful_result.length > 0){ - $(less_useful_result).each( function(index, hed_val){ - if(quot_val.session_name === hed_val.session_name) - { - display_session(result.requotes[index], result.hedges[index]); - return false; - } - }); - } - else { - display_session(result.requotes[index], result.hedges[index]); - } + let whole_result = result.requotes.concat(result.hedges); + let unique_sessions = whole_result.filter(function(value, index, self){ + return self.find(function(elm){ + return elm.session_name === value.session_name; + }); + }); + + $(unique_sessions).each(function (index, sess_val){ + let r = result.requotes.find(function(elm){ + return elm.session_name === sess_val.session_name; + }); + + let h = result.hedges.find(function(elm){ + return elm.session_name === sess_val.session_name; + }); + + display_session(r, h); }); } else { @@ -270,7 +274,9 @@ function display_session (quot_val, hed_val) { generate_histogram(safe_quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); }); - generate_histogram(safe_hed_val.session_name + "-hed-total", hed_val_data["total"]); + if(safe_hed_val.summaries.length > 0){ + generate_histogram(safe_hed_val.session_name + "-hed-total", hed_val_data["total"]); + } /* $(safe_hed_val.summaries).each(function(i,v){ generate_histogram(safe_hed_val.session_name + "-hed-" + v.value, hed_val_data[v.value]); From 6f65a958ae97ba84ef10a0dd2cede3d9b9da8b2a Mon Sep 17 00:00:00 2001 From: Michael Harding Date: Fri, 16 Nov 2018 10:25:25 -0500 Subject: [PATCH 29/29] Only show total for requotes in perf_trace UI --- src/data_files/files/perf_trace/main.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/data_files/files/perf_trace/main.js b/src/data_files/files/perf_trace/main.js index 0a54cbf2f..4f2a47030 100644 --- a/src/data_files/files/perf_trace/main.js +++ b/src/data_files/files/perf_trace/main.js @@ -229,6 +229,7 @@ function display_session (quot_val, hed_val) { loop_val = safe_hed_val.summaries.length; } + /* for(let i = 0; i < loop_val; i++) { session_info += ""; if (safe_quot_val.summaries[i] !== undefined && safe_quot_val.summaries[i].value !== "total") { @@ -236,12 +237,13 @@ function display_session (quot_val, hed_val) { } session_info += ""; if (safe_hed_val.summaries[i] !== undefined && safe_hed_val.summaries[i].value !== "total") { - //session_info += write_summary(safe_hed_val.session_name + "-hed-" + safe_hed_val.summaries[i].value, safe_hed_val.summaries[i]); + session_info += write_summary(safe_hed_val.session_name + "-hed-" + safe_hed_val.summaries[i].value, safe_hed_val.summaries[i]); } session_info += ""; } + */ - session_info += "
    "; + session_info += "
    "; $("#output").append(session_info); let quot_val_data = {}; @@ -270,10 +272,14 @@ function display_session (quot_val, hed_val) { }); }); - $(safe_quot_val.summaries).each(function(i,v){ - generate_histogram(safe_quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); - }); - + if(safe_quot_val.summaries.length > 0){ + generate_histogram(safe_quot_val.session_name + "-quot-total", quot_val_data["total"]); + } + /* + $(safe_quot_val.summaries).each(function(i,v){ + generate_histogram(safe_quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]); + }); + */ if(safe_hed_val.summaries.length > 0){ generate_histogram(safe_hed_val.session_name + "-hed-total", hed_val_data["total"]); }