rippled
Loading...
Searching...
No Matches
FlowDebugInfo.h
1#ifndef XRPL_PATH_IMPL_FLOWDEBUGINFO_H_INCLUDED
2#define XRPL_PATH_IMPL_FLOWDEBUGINFO_H_INCLUDED
3
4#include <xrpld/app/paths/detail/AmountSpec.h>
5
6#include <xrpl/ledger/PaymentSandbox.h>
7#include <xrpl/protocol/IOUAmount.h>
8#include <xrpl/protocol/XRPAmount.h>
9
10#include <boost/container/flat_map.hpp>
11
12#include <chrono>
13#include <optional>
14#include <sstream>
15
16namespace ripple {
17namespace path {
18namespace detail {
19// Track performance information of a single payment
21{
23 using time_point = clock::time_point;
24 boost::container::flat_map<std::string, std::pair<time_point, time_point>>
26 boost::container::flat_map<std::string, std::size_t> counts;
27
28 struct PassInfo
29 {
30 PassInfo() = delete;
31 PassInfo(bool nativeIn_, bool nativeOut_)
32 : nativeIn(nativeIn_), nativeOut(nativeOut_)
33 {
34 }
35 bool const nativeIn;
36 bool const nativeOut;
40
43
44 void
45 reserve(size_t s)
46 {
47 in.reserve(s);
48 out.reserve(s);
49 liquiditySrcIn.reserve(s);
50 liquiditySrcOut.reserve(s);
52 }
53
54 size_t
55 size() const
56 {
57 return in.size();
58 }
59
60 void
62 EitherAmount const& in_amt,
63 EitherAmount const& out_amt,
64 std::size_t active)
65 {
66 in.push_back(in_amt);
67 out.push_back(out_amt);
68 numActive.push_back(active);
69 }
70
71 void
73 {
74 XRPL_ASSERT(
75 !liquiditySrcIn.empty(),
76 "ripple::path::detail::FlowDebugInfo::pushLiquiditySrc : "
77 "non-empty liquidity source");
78 liquiditySrcIn.back().push_back(eIn);
79 liquiditySrcOut.back().push_back(eOut);
80 }
81
82 void
84 {
85 auto const s = liquiditySrcIn.size();
86 size_t const r = !numActive.empty() ? numActive.back() : 16;
87 liquiditySrcIn.resize(s + 1);
88 liquiditySrcIn.back().reserve(r);
89 liquiditySrcOut.resize(s + 1);
90 liquiditySrcOut.back().reserve(r);
91 }
92 };
93
95
96 FlowDebugInfo() = delete;
97 FlowDebugInfo(bool nativeIn, bool nativeOut) : passInfo(nativeIn, nativeOut)
98 {
100 counts.reserve(16);
101 passInfo.reserve(64);
102 }
103
104 auto
105 duration(std::string const& tag) const
106 {
107 auto i = timePoints.find(tag);
108 if (i == timePoints.end())
109 {
110 // LCOV_EXCL_START
111 UNREACHABLE(
112 "ripple::path::detail::FlowDebugInfo::duration : timepoint not "
113 "found");
115 // LCOV_EXCL_STOP
116 }
117 auto const& t = i->second;
118 return std::chrono::duration_cast<std::chrono::duration<double>>(
119 t.second - t.first);
120 }
121
123 count(std::string const& tag) const
124 {
125 auto i = counts.find(tag);
126 if (i == counts.end())
127 return 0;
128 return i->second;
129 }
130
131 // Time the duration of the existence of the result
132 auto
134 {
135 struct Stopper
136 {
137 std::string tag;
138 FlowDebugInfo* info;
139 Stopper(std::string name, FlowDebugInfo& pi)
140 : tag(std::move(name)), info(&pi)
141 {
142 auto const start = FlowDebugInfo::clock::now();
143 info->timePoints.emplace(tag, std::make_pair(start, start));
144 }
145 ~Stopper()
146 {
147 auto const end = FlowDebugInfo::clock::now();
148 info->timePoints[tag].second = end;
149 }
150 Stopper(Stopper&&) = default;
151 };
152 return Stopper(std::move(name), *this);
153 }
154
155 void
156 inc(std::string const& tag)
157 {
158 auto i = counts.find(tag);
159 if (i == counts.end())
160 {
161 counts[tag] = 1;
162 }
163 ++i->second;
164 }
165
166 void
168 {
169 counts[tag] = c;
170 }
171
173 passCount() const
174 {
175 return passInfo.size();
176 }
177
178 void
180 EitherAmount const& in,
181 EitherAmount const& out,
182 std::size_t activeStrands)
183 {
184 passInfo.push_back(in, out, activeStrands);
185 }
186
187 void
192
193 void
198
200 to_string(bool writePassInfo) const
201 {
203
204 auto const d = duration("main");
205
206 ostr << "duration: " << d.count() << ", pass_count: " << passCount();
207
208 if (writePassInfo)
209 {
210 auto write_list =
211 [&ostr](auto const& vals, auto&& fun, char delim = ';') {
212 ostr << '[';
213 if (!vals.empty())
214 {
215 ostr << fun(vals[0]);
216 for (size_t i = 1, e = vals.size(); i < e; ++i)
217 ostr << delim << fun(vals[i]);
218 }
219 ostr << ']';
220 };
221 auto writeXrpAmtList = [&write_list](
222 std::vector<EitherAmount> const& amts,
223 char delim = ';') {
224 auto get_val = [](EitherAmount const& a) -> std::string {
225 return ripple::to_string(a.xrp);
226 };
227 write_list(amts, get_val, delim);
228 };
229 auto writeIouAmtList = [&write_list](
230 std::vector<EitherAmount> const& amts,
231 char delim = ';') {
232 auto get_val = [](EitherAmount const& a) -> std::string {
233 return ripple::to_string(a.iou);
234 };
235 write_list(amts, get_val, delim);
236 };
237 auto writeIntList = [&write_list](
238 std::vector<size_t> const& vals,
239 char delim = ';') {
240 auto get_val = [](size_t const& v) -> size_t const& {
241 return v;
242 };
243 write_list(vals, get_val);
244 };
245 auto writeNestedIouAmtList =
246 [&ostr, &writeIouAmtList](
248 ostr << '[';
249 if (!amts.empty())
250 {
251 writeIouAmtList(amts[0], '|');
252 for (size_t i = 1, e = amts.size(); i < e; ++i)
253 {
254 ostr << ';';
255 writeIouAmtList(amts[i], '|');
256 }
257 }
258 ostr << ']';
259 };
260 auto writeNestedXrpAmtList =
261 [&ostr, &writeXrpAmtList](
263 ostr << '[';
264 if (!amts.empty())
265 {
266 writeXrpAmtList(amts[0], '|');
267 for (size_t i = 1, e = amts.size(); i < e; ++i)
268 {
269 ostr << ';';
270 writeXrpAmtList(amts[i], '|');
271 }
272 }
273 ostr << ']';
274 };
275
276 ostr << ", in_pass: ";
277 if (passInfo.nativeIn)
278 writeXrpAmtList(passInfo.in);
279 else
280 writeIouAmtList(passInfo.in);
281 ostr << ", out_pass: ";
283 writeXrpAmtList(passInfo.out);
284 else
285 writeIouAmtList(passInfo.out);
286 ostr << ", num_active: ";
287 writeIntList(passInfo.numActive);
288 if (!passInfo.liquiditySrcIn.empty() &&
289 !passInfo.liquiditySrcIn.back().empty())
290 {
291 ostr << ", l_src_in: ";
292 if (passInfo.nativeIn)
293 writeNestedXrpAmtList(passInfo.liquiditySrcIn);
294 else
295 writeNestedIouAmtList(passInfo.liquiditySrcIn);
296 ostr << ", l_src_out: ";
298 writeNestedXrpAmtList(passInfo.liquiditySrcOut);
299 else
300 writeNestedIouAmtList(passInfo.liquiditySrcOut);
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};
319
320template <class Iter>
321void
322writeDiffs(std::ostringstream& ostr, Iter begin, Iter end)
323{
324 ostr << '[';
325 if (begin != end)
326 {
327 writeDiffElement(ostr, *begin);
328 ++begin;
329 }
330 for (; begin != end; ++begin)
331 {
332 ostr << ';';
333 writeDiffElement(ostr, *begin);
334 }
335 ostr << ']';
336};
337
340 XRPAmount>;
341
342inline BalanceDiffs
344{
345 return {sb.balanceChanges(rv), sb.xrpDestroyed()};
346}
347
348inline std::string
350{
351 if (!bd)
352 return std::string{};
353 auto const& diffs = bd->first;
354 auto const& xrpDestroyed = bd->second;
356 ostr << ", xrpDestroyed: " << to_string(xrpDestroyed);
357 ostr << ", balanceDiffs: ";
358 writeDiffs(ostr, diffs.begin(), diffs.end());
359 return ostr.str();
360};
361
362} // namespace detail
363} // namespace path
364} // namespace ripple
365#endif
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:32
T empty(T... args)
T make_pair(T... args)
void writeDiffElement(std::ostringstream &ostr, std::pair< std::tuple< AccountID, AccountID, Currency >, STAmount > const &elem)
std::string balanceDiffsToString(std::optional< BalanceDiffs > const &bd)
BalanceDiffs balanceDiffs(PaymentSandbox const &sb, ReadView const &rv)
void writeDiffs(std::ostringstream &ostr, Iter begin, Iter end)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
STL namespace.
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 > > liquiditySrcIn
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::string to_string(bool writePassInfo) const
void pushPass(EitherAmount const &in, EitherAmount const &out, std::size_t activeStrands)
auto duration(std::string const &tag) const
std::size_t count(std::string const &tag) const
void pushLiquiditySrc(EitherAmount const &in, EitherAmount const &out)
FlowDebugInfo(bool nativeIn, bool nativeOut)
void inc(std::string const &tag)
boost::container::flat_map< std::string, std::size_t > counts
boost::container::flat_map< std::string, std::pair< time_point, time_point > > timePoints
void setCount(std::string const &tag, std::size_t c)