xrpld
Loading...
Searching...
No Matches
FlowDebugInfo.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4#include <xrpl/protocol/AccountID.h>
5#include <xrpl/protocol/IOUAmount.h>
6#include <xrpl/protocol/STAmount.h>
7#include <xrpl/protocol/UintTypes.h>
8#include <xrpl/protocol/XRPAmount.h>
9#include <xrpl/tx/paths/detail/EitherAmount.h>
10
11#include <boost/container/flat_map.hpp>
12
13#include <chrono>
14#include <cstddef>
15#include <sstream>
16#include <string>
17#include <tuple>
18#include <utility>
19#include <vector>
20
22// Track performance information of a single payment
24{
26 using time_point = clock::time_point;
27 boost::container::flat_map<std::string, std::pair<time_point, time_point>> timePoints;
28 boost::container::flat_map<std::string, std::size_t> counts;
29
30 struct PassInfo
31 {
32 PassInfo() = delete;
36 bool const nativeIn;
37 bool const nativeOut;
41
44
45 void
46 reserve(size_t s)
47 {
48 in.reserve(s);
49 out.reserve(s);
50 liquiditySrcIn.reserve(s);
51 liquiditySrcOut.reserve(s);
52 numActive.reserve(s);
53 }
54
55 [[nodiscard]] size_t
56 size() const
57 {
58 return in.size();
59 }
60
61 void
62 pushBack(EitherAmount const& inAmt, EitherAmount const& outAmt, std::size_t active)
63 {
64 in.push_back(inAmt);
65 out.push_back(outAmt);
66 numActive.push_back(active);
67 }
68
69 void
71 {
72 XRPL_ASSERT(
73 !liquiditySrcIn.empty(),
74 "xrpl::path::detail::FlowDebugInfo::pushLiquiditySrc : "
75 "non-empty liquidity source");
76 liquiditySrcIn.back().push_back(eIn);
77 liquiditySrcOut.back().push_back(eOut);
78 }
79
80 void
82 {
83 auto const s = liquiditySrcIn.size();
84 size_t const r = !numActive.empty() ? numActive.back() : 16;
85 liquiditySrcIn.resize(s + 1);
86 liquiditySrcIn.back().reserve(r);
87 liquiditySrcOut.resize(s + 1);
88 liquiditySrcOut.back().reserve(r);
89 }
90 };
91
93
94 FlowDebugInfo() = delete;
95 FlowDebugInfo(bool nativeIn, bool nativeOut) : passInfo(nativeIn, nativeOut)
96 {
97 timePoints.reserve(16);
98 counts.reserve(16);
99 passInfo.reserve(64);
100 }
101
102 [[nodiscard]] auto
103 duration(std::string const& tag) const
104 {
105 auto i = timePoints.find(tag);
106 if (i == timePoints.end())
107 {
108 // LCOV_EXCL_START
109 UNREACHABLE(
110 "xrpl::path::detail::FlowDebugInfo::duration : timepoint not "
111 "found");
113 // LCOV_EXCL_STOP
114 }
115 auto const& t = i->second;
117 }
118
119 [[nodiscard]] std::size_t
120 count(std::string const& tag) const
121 {
122 auto i = counts.find(tag);
123 if (i == counts.end())
124 return 0;
125 return i->second;
126 }
127
128 // Time the duration of the existence of the result
129 auto
131 {
132 struct Stopper
133 {
134 std::string tag;
135 FlowDebugInfo* info;
136 Stopper(std::string name, FlowDebugInfo& pi) : tag(std::move(name)), info(&pi)
137 {
138 auto const start = FlowDebugInfo::clock::now();
139 info->timePoints.emplace(tag, std::make_pair(start, start));
140 }
141 ~Stopper()
142 {
143 auto const end = FlowDebugInfo::clock::now();
144 info->timePoints[tag].second = end;
145 }
146 Stopper(Stopper&&) = default;
147 };
148 return Stopper(std::move(name), *this);
149 }
150
151 void
152 inc(std::string const& tag)
153 {
154 auto i = counts.find(tag);
155 if (i == counts.end())
156 {
157 counts[tag] = 1;
158 }
159 ++i->second;
160 }
161
162 void
164 {
165 counts[tag] = c;
166 }
167
168 [[nodiscard]] std::size_t
169 passCount() const
170 {
171 return passInfo.size();
172 }
173
174 void
175 pushPass(EitherAmount const& in, EitherAmount const& out, std::size_t activeStrands)
176 {
177 passInfo.pushBack(in, out, activeStrands);
178 }
179
180 void
182 {
183 passInfo.pushLiquiditySrc(in, out);
184 }
185
186 void
188 {
189 passInfo.newLiquidityPass();
190 }
191
192 [[nodiscard]] std::string
193 toString(bool writePassInfo) const
194 {
196
197 auto const d = duration("main");
198
199 ostr << "duration: " << d.count() << ", pass_count: " << passCount();
200
201 if (writePassInfo)
202 {
203 auto writeList = [&ostr](auto const& vals, auto&& fun, char delim = ';') {
204 ostr << '[';
205 if (!vals.empty())
206 {
207 ostr << fun(vals[0]);
208 for (size_t i = 1, e = vals.size(); i < e; ++i)
209 ostr << delim << fun(vals[i]);
210 }
211 ostr << ']';
212 };
213 auto writeXrpAmtList = [&writeList](
214 std::vector<EitherAmount> const& amts, char delim = ';') {
215 auto getVal = [](EitherAmount const& a) -> std::string {
216 return xrpl::to_string(a.get<XRPAmount>());
217 };
218 writeList(amts, getVal, delim);
219 };
220 auto writeIouAmtList = [&writeList](
221 std::vector<EitherAmount> const& amts, char delim = ';') {
222 auto getVal = [](EitherAmount const& a) -> std::string {
223 return xrpl::to_string(a.get<IOUAmount>());
224 };
225 writeList(amts, getVal, delim);
226 };
227 auto writeIntList = [&writeList](std::vector<size_t> const& vals, char delim = ';') {
228 // NOLINTNEXTLINE(bugprone-return-const-ref-from-parameter)
229 auto getVal = [](size_t const& v) -> size_t const& { return v; };
230 writeList(vals, getVal);
231 };
232 auto writeNestedIouAmtList =
233 [&ostr, &writeIouAmtList](std::vector<std::vector<EitherAmount>> const& amts) {
234 ostr << '[';
235 if (!amts.empty())
236 {
237 writeIouAmtList(amts[0], '|');
238 for (size_t i = 1, e = amts.size(); i < e; ++i)
239 {
240 ostr << ';';
241 writeIouAmtList(amts[i], '|');
242 }
243 }
244 ostr << ']';
245 };
246 auto writeNestedXrpAmtList =
247 [&ostr, &writeXrpAmtList](std::vector<std::vector<EitherAmount>> const& amts) {
248 ostr << '[';
249 if (!amts.empty())
250 {
251 writeXrpAmtList(amts[0], '|');
252 for (size_t i = 1, e = amts.size(); i < e; ++i)
253 {
254 ostr << ';';
255 writeXrpAmtList(amts[i], '|');
256 }
257 }
258 ostr << ']';
259 };
260
261 ostr << ", in_pass: ";
262 if (passInfo.nativeIn)
263 {
264 writeXrpAmtList(passInfo.in);
265 }
266 else
267 {
268 writeIouAmtList(passInfo.in);
269 }
270 ostr << ", out_pass: ";
271 if (passInfo.nativeOut)
272 {
273 writeXrpAmtList(passInfo.out);
274 }
275 else
276 {
277 writeIouAmtList(passInfo.out);
278 }
279 ostr << ", num_active: ";
280 writeIntList(passInfo.numActive);
281 if (!passInfo.liquiditySrcIn.empty() && !passInfo.liquiditySrcIn.back().empty())
282 {
283 ostr << ", l_src_in: ";
284 if (passInfo.nativeIn)
285 {
286 writeNestedXrpAmtList(passInfo.liquiditySrcIn);
287 }
288 else
289 {
290 writeNestedIouAmtList(passInfo.liquiditySrcIn);
291 }
292 ostr << ", l_src_out: ";
293 if (passInfo.nativeOut)
294 {
295 writeNestedXrpAmtList(passInfo.liquiditySrcOut);
296 }
297 else
298 {
299 writeNestedIouAmtList(passInfo.liquiditySrcOut);
300 }
301 }
302 }
303
304 return ostr.str();
305 }
306};
307
308inline void
310 std::ostringstream& ostr,
312{
313 using namespace std;
314 auto const k = elem.first;
315 auto const v = elem.second;
316 ostr << '[' << get<0>(k) << '|' << get<1>(k) << '|' << get<2>(k) << '|' << v << ']';
317};
318
319template <class Iter>
320void
322{
323 ostr << '[';
324 if (begin != end)
325 {
326 writeDiffElement(ostr, *begin);
327 ++begin;
328 }
329 for (; begin != end; ++begin)
330 {
331 ostr << ';';
332 writeDiffElement(ostr, *begin);
333 }
334 ostr << ']';
335};
336
337} // namespace xrpl::path::detail
T begin(T... args)
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:26
T duration_cast(T... args)
T empty(T... args)
T end(T... args)
T make_pair(T... args)
STL namespace.
void writeDiffs(std::ostringstream &ostr, Iter begin, Iter end)
void writeDiffElement(std::ostringstream &ostr, std::pair< std::tuple< AccountID, AccountID, Currency >, STAmount > const &elem)
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
T size(T... args)
T str(T... args)
std::vector< std::vector< EitherAmount > > liquiditySrcOut
void pushBack(EitherAmount const &inAmt, EitherAmount const &outAmt, std::size_t active)
void pushLiquiditySrc(EitherAmount const &eIn, EitherAmount const &eOut)
PassInfo(bool nativeIn, bool nativeOut)
std::vector< std::vector< EitherAmount > > liquiditySrcIn
void pushPass(EitherAmount const &in, EitherAmount const &out, std::size_t activeStrands)
void pushLiquiditySrc(EitherAmount const &in, EitherAmount const &out)
std::string toString(bool writePassInfo) const
std::size_t count(std::string const &tag) const
FlowDebugInfo(bool nativeIn, bool nativeOut)
boost::container::flat_map< std::string, std::size_t > counts
void inc(std::string const &tag)
void setCount(std::string const &tag, std::size_t c)
auto duration(std::string const &tag) const
auto timeBlock(std::string name)
std::chrono::high_resolution_clock clock
boost::container::flat_map< std::string, std::pair< time_point, time_point > > timePoints