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