rippled
Loading...
Searching...
No Matches
FlowDebugInfo.h
1#pragma once
2
3#include <xrpl/ledger/PaymentSandbox.h>
4#include <xrpl/protocol/IOUAmount.h>
5#include <xrpl/protocol/XRPAmount.h>
6#include <xrpl/tx/paths/detail/AmountSpec.h>
7
8#include <boost/container/flat_map.hpp>
9
10#include <chrono>
11#include <optional>
12#include <sstream>
13
14namespace xrpl {
15namespace path {
16namespace detail {
17// Track performance information of a single payment
19{
21 using time_point = clock::time_point;
22 boost::container::flat_map<std::string, std::pair<time_point, time_point>> timePoints;
23 boost::container::flat_map<std::string, std::size_t> counts;
24
25 struct PassInfo
26 {
27 PassInfo() = delete;
28 PassInfo(bool nativeIn_, bool nativeOut_) : nativeIn(nativeIn_), nativeOut(nativeOut_)
29 {
30 }
31 bool const nativeIn;
32 bool const nativeOut;
36
39
40 void
41 reserve(size_t s)
42 {
43 in.reserve(s);
44 out.reserve(s);
45 liquiditySrcIn.reserve(s);
46 liquiditySrcOut.reserve(s);
48 }
49
50 size_t
51 size() const
52 {
53 return in.size();
54 }
55
56 void
57 push_back(EitherAmount const& in_amt, EitherAmount const& out_amt, std::size_t active)
58 {
59 in.push_back(in_amt);
60 out.push_back(out_amt);
61 numActive.push_back(active);
62 }
63
64 void
66 {
67 XRPL_ASSERT(
68 !liquiditySrcIn.empty(),
69 "xrpl::path::detail::FlowDebugInfo::pushLiquiditySrc : "
70 "non-empty liquidity source");
71 liquiditySrcIn.back().push_back(eIn);
72 liquiditySrcOut.back().push_back(eOut);
73 }
74
75 void
77 {
78 auto const s = liquiditySrcIn.size();
79 size_t const r = !numActive.empty() ? numActive.back() : 16;
80 liquiditySrcIn.resize(s + 1);
81 liquiditySrcIn.back().reserve(r);
82 liquiditySrcOut.resize(s + 1);
83 liquiditySrcOut.back().reserve(r);
84 }
85 };
86
88
89 FlowDebugInfo() = delete;
90 FlowDebugInfo(bool nativeIn, bool nativeOut) : passInfo(nativeIn, nativeOut)
91 {
93 counts.reserve(16);
94 passInfo.reserve(64);
95 }
96
97 auto
98 duration(std::string const& tag) const
99 {
100 auto i = timePoints.find(tag);
101 if (i == timePoints.end())
102 {
103 // LCOV_EXCL_START
104 UNREACHABLE(
105 "xrpl::path::detail::FlowDebugInfo::duration : timepoint not "
106 "found");
108 // LCOV_EXCL_STOP
109 }
110 auto const& t = i->second;
111 return std::chrono::duration_cast<std::chrono::duration<double>>(t.second - t.first);
112 }
113
115 count(std::string const& tag) const
116 {
117 auto i = counts.find(tag);
118 if (i == counts.end())
119 return 0;
120 return i->second;
121 }
122
123 // Time the duration of the existence of the result
124 auto
126 {
127 struct Stopper
128 {
129 std::string tag;
130 FlowDebugInfo* info;
131 Stopper(std::string name, FlowDebugInfo& pi) : tag(std::move(name)), info(&pi)
132 {
133 auto const start = FlowDebugInfo::clock::now();
134 info->timePoints.emplace(tag, std::make_pair(start, start));
135 }
136 ~Stopper()
137 {
138 auto const end = FlowDebugInfo::clock::now();
139 info->timePoints[tag].second = end;
140 }
141 Stopper(Stopper&&) = default;
142 };
143 return Stopper(std::move(name), *this);
144 }
145
146 void
147 inc(std::string const& tag)
148 {
149 auto i = counts.find(tag);
150 if (i == counts.end())
151 {
152 counts[tag] = 1;
153 }
154 ++i->second;
155 }
156
157 void
159 {
160 counts[tag] = c;
161 }
162
164 passCount() const
165 {
166 return passInfo.size();
167 }
168
169 void
170 pushPass(EitherAmount const& in, EitherAmount const& out, std::size_t activeStrands)
171 {
172 passInfo.push_back(in, out, activeStrands);
173 }
174
175 void
180
181 void
186
188 to_string(bool writePassInfo) const
189 {
191
192 auto const d = duration("main");
193
194 ostr << "duration: " << d.count() << ", pass_count: " << passCount();
195
196 if (writePassInfo)
197 {
198 auto write_list = [&ostr](auto const& vals, auto&& fun, char delim = ';') {
199 ostr << '[';
200 if (!vals.empty())
201 {
202 ostr << fun(vals[0]);
203 for (size_t i = 1, e = vals.size(); i < e; ++i)
204 ostr << delim << fun(vals[i]);
205 }
206 ostr << ']';
207 };
208 auto writeXrpAmtList = [&write_list](
209 std::vector<EitherAmount> const& amts, char delim = ';') {
210 auto get_val = [](EitherAmount const& a) -> std::string {
211 return xrpl::to_string(a.xrp);
212 };
213 write_list(amts, get_val, delim);
214 };
215 auto writeIouAmtList = [&write_list](
216 std::vector<EitherAmount> const& amts, char delim = ';') {
217 auto get_val = [](EitherAmount const& a) -> std::string {
218 return xrpl::to_string(a.iou);
219 };
220 write_list(amts, get_val, delim);
221 };
222 auto writeIntList = [&write_list](std::vector<size_t> const& vals, char delim = ';') {
223 auto get_val = [](size_t const& v) -> size_t const& { return v; };
224 write_list(vals, get_val);
225 };
226 auto writeNestedIouAmtList =
227 [&ostr, &writeIouAmtList](std::vector<std::vector<EitherAmount>> const& amts) {
228 ostr << '[';
229 if (!amts.empty())
230 {
231 writeIouAmtList(amts[0], '|');
232 for (size_t i = 1, e = amts.size(); i < e; ++i)
233 {
234 ostr << ';';
235 writeIouAmtList(amts[i], '|');
236 }
237 }
238 ostr << ']';
239 };
240 auto writeNestedXrpAmtList =
241 [&ostr, &writeXrpAmtList](std::vector<std::vector<EitherAmount>> const& amts) {
242 ostr << '[';
243 if (!amts.empty())
244 {
245 writeXrpAmtList(amts[0], '|');
246 for (size_t i = 1, e = amts.size(); i < e; ++i)
247 {
248 ostr << ';';
249 writeXrpAmtList(amts[i], '|');
250 }
251 }
252 ostr << ']';
253 };
254
255 ostr << ", in_pass: ";
256 if (passInfo.nativeIn)
257 writeXrpAmtList(passInfo.in);
258 else
259 writeIouAmtList(passInfo.in);
260 ostr << ", out_pass: ";
262 writeXrpAmtList(passInfo.out);
263 else
264 writeIouAmtList(passInfo.out);
265 ostr << ", num_active: ";
266 writeIntList(passInfo.numActive);
267 if (!passInfo.liquiditySrcIn.empty() && !passInfo.liquiditySrcIn.back().empty())
268 {
269 ostr << ", l_src_in: ";
270 if (passInfo.nativeIn)
271 writeNestedXrpAmtList(passInfo.liquiditySrcIn);
272 else
273 writeNestedIouAmtList(passInfo.liquiditySrcIn);
274 ostr << ", l_src_out: ";
276 writeNestedXrpAmtList(passInfo.liquiditySrcOut);
277 else
278 writeNestedIouAmtList(passInfo.liquiditySrcOut);
279 }
280 }
281
282 return ostr.str();
283 }
284};
285
286inline void
288 std::ostringstream& ostr,
290{
291 using namespace std;
292 auto const k = elem.first;
293 auto const v = elem.second;
294 ostr << '[' << get<0>(k) << '|' << get<1>(k) << '|' << get<2>(k) << '|' << v << ']';
295};
296
297template <class Iter>
298void
299writeDiffs(std::ostringstream& ostr, Iter begin, Iter end)
300{
301 ostr << '[';
302 if (begin != end)
303 {
304 writeDiffElement(ostr, *begin);
305 ++begin;
306 }
307 for (; begin != end; ++begin)
308 {
309 ostr << ';';
310 writeDiffElement(ostr, *begin);
311 }
312 ostr << ']';
313};
314
317
318inline BalanceDiffs
320{
321 return {sb.balanceChanges(rv), sb.xrpDestroyed()};
322}
323
324inline std::string
326{
327 if (!bd)
328 return std::string{};
329 auto const& diffs = bd->first;
330 auto const& xrpDestroyed = bd->second;
332 ostr << ", xrpDestroyed: " << to_string(xrpDestroyed);
333 ostr << ", balanceDiffs: ";
334 writeDiffs(ostr, diffs.begin(), diffs.end());
335 return ostr.str();
336};
337
338} // namespace detail
339} // namespace path
340} // namespace xrpl
T back(T... args)
A wrapper which makes credits unavailable to balances.
XRPAmount xrpDestroyed() const
std::map< std::tuple< AccountID, AccountID, Currency >, STAmount > balanceChanges(ReadView const &view) const
A view into a ledger.
Definition ReadView.h:31
T empty(T... args)
T make_pair(T... args)
STL namespace.
BalanceDiffs balanceDiffs(PaymentSandbox const &sb, ReadView const &rv)
std::string balanceDiffsToString(std::optional< BalanceDiffs > const &bd)
void writeDiffs(std::ostringstream &ostr, Iter begin, Iter end)
void writeDiffElement(std::ostringstream &ostr, std::pair< std::tuple< AccountID, AccountID, Currency >, STAmount > const &elem)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
T push_back(T... args)
T reserve(T... args)
T size(T... args)
T str(T... args)
PassInfo(bool nativeIn_, bool nativeOut_)
std::vector< std::vector< EitherAmount > > liquiditySrcOut
void pushLiquiditySrc(EitherAmount const &eIn, EitherAmount const &eOut)
void push_back(EitherAmount const &in_amt, EitherAmount const &out_amt, std::size_t active)
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::size_t count(std::string const &tag) const
FlowDebugInfo(bool nativeIn, bool nativeOut)
boost::container::flat_map< std::string, std::size_t > counts
std::string to_string(bool writePassInfo) const
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)
boost::container::flat_map< std::string, std::pair< time_point, time_point > > timePoints