rippled
Loading...
Searching...
No Matches
FlowDebugInfo.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef RIPPLE_PATH_IMPL_FLOWDEBUGINFO_H_INCLUDED
21#define RIPPLE_PATH_IMPL_FLOWDEBUGINFO_H_INCLUDED
22
23#include <xrpld/app/paths/detail/AmountSpec.h>
24
25#include <xrpl/ledger/PaymentSandbox.h>
26#include <xrpl/protocol/IOUAmount.h>
27#include <xrpl/protocol/XRPAmount.h>
28
29#include <boost/container/flat_map.hpp>
30
31#include <chrono>
32#include <optional>
33#include <sstream>
34
35namespace ripple {
36namespace path {
37namespace detail {
38// Track performance information of a single payment
40{
42 using time_point = clock::time_point;
43 boost::container::flat_map<std::string, std::pair<time_point, time_point>>
45 boost::container::flat_map<std::string, std::size_t> counts;
46
47 struct PassInfo
48 {
49 PassInfo() = delete;
50 PassInfo(bool nativeIn_, bool nativeOut_)
51 : nativeIn(nativeIn_), nativeOut(nativeOut_)
52 {
53 }
54 bool const nativeIn;
55 bool const nativeOut;
59
62
63 void
64 reserve(size_t s)
65 {
66 in.reserve(s);
67 out.reserve(s);
68 liquiditySrcIn.reserve(s);
69 liquiditySrcOut.reserve(s);
71 }
72
73 size_t
74 size() const
75 {
76 return in.size();
77 }
78
79 void
81 EitherAmount const& in_amt,
82 EitherAmount const& out_amt,
83 std::size_t active)
84 {
85 in.push_back(in_amt);
86 out.push_back(out_amt);
87 numActive.push_back(active);
88 }
89
90 void
92 {
93 XRPL_ASSERT(
94 !liquiditySrcIn.empty(),
95 "ripple::path::detail::FlowDebugInfo::pushLiquiditySrc : "
96 "non-empty liquidity source");
97 liquiditySrcIn.back().push_back(eIn);
98 liquiditySrcOut.back().push_back(eOut);
99 }
100
101 void
103 {
104 auto const s = liquiditySrcIn.size();
105 size_t const r = !numActive.empty() ? numActive.back() : 16;
106 liquiditySrcIn.resize(s + 1);
107 liquiditySrcIn.back().reserve(r);
108 liquiditySrcOut.resize(s + 1);
109 liquiditySrcOut.back().reserve(r);
110 }
111 };
112
114
115 FlowDebugInfo() = delete;
116 FlowDebugInfo(bool nativeIn, bool nativeOut) : passInfo(nativeIn, nativeOut)
117 {
119 counts.reserve(16);
120 passInfo.reserve(64);
121 }
122
123 auto
124 duration(std::string const& tag) const
125 {
126 auto i = timePoints.find(tag);
127 if (i == timePoints.end())
128 {
129 // LCOV_EXCL_START
130 UNREACHABLE(
131 "ripple::path::detail::FlowDebugInfo::duration : timepoint not "
132 "found");
134 // LCOV_EXCL_STOP
135 }
136 auto const& t = i->second;
137 return std::chrono::duration_cast<std::chrono::duration<double>>(
138 t.second - t.first);
139 }
140
142 count(std::string const& tag) const
143 {
144 auto i = counts.find(tag);
145 if (i == counts.end())
146 return 0;
147 return i->second;
148 }
149
150 // Time the duration of the existence of the result
151 auto
153 {
154 struct Stopper
155 {
156 std::string tag;
157 FlowDebugInfo* info;
158 Stopper(std::string name, FlowDebugInfo& pi)
159 : tag(std::move(name)), info(&pi)
160 {
161 auto const start = FlowDebugInfo::clock::now();
162 info->timePoints.emplace(tag, std::make_pair(start, start));
163 }
164 ~Stopper()
165 {
166 auto const end = FlowDebugInfo::clock::now();
167 info->timePoints[tag].second = end;
168 }
169 Stopper(Stopper&&) = default;
170 };
171 return Stopper(std::move(name), *this);
172 }
173
174 void
175 inc(std::string const& tag)
176 {
177 auto i = counts.find(tag);
178 if (i == counts.end())
179 {
180 counts[tag] = 1;
181 }
182 ++i->second;
183 }
184
185 void
187 {
188 counts[tag] = c;
189 }
190
192 passCount() const
193 {
194 return passInfo.size();
195 }
196
197 void
199 EitherAmount const& in,
200 EitherAmount const& out,
201 std::size_t activeStrands)
202 {
203 passInfo.push_back(in, out, activeStrands);
204 }
205
206 void
211
212 void
217
219 to_string(bool writePassInfo) const
220 {
222
223 auto const d = duration("main");
224
225 ostr << "duration: " << d.count() << ", pass_count: " << passCount();
226
227 if (writePassInfo)
228 {
229 auto write_list =
230 [&ostr](auto const& vals, auto&& fun, char delim = ';') {
231 ostr << '[';
232 if (!vals.empty())
233 {
234 ostr << fun(vals[0]);
235 for (size_t i = 1, e = vals.size(); i < e; ++i)
236 ostr << delim << fun(vals[i]);
237 }
238 ostr << ']';
239 };
240 auto writeXrpAmtList = [&write_list](
241 std::vector<EitherAmount> const& amts,
242 char delim = ';') {
243 auto get_val = [](EitherAmount const& a) -> std::string {
244 return ripple::to_string(a.xrp);
245 };
246 write_list(amts, get_val, delim);
247 };
248 auto writeIouAmtList = [&write_list](
249 std::vector<EitherAmount> const& amts,
250 char delim = ';') {
251 auto get_val = [](EitherAmount const& a) -> std::string {
252 return ripple::to_string(a.iou);
253 };
254 write_list(amts, get_val, delim);
255 };
256 auto writeIntList = [&write_list](
257 std::vector<size_t> const& vals,
258 char delim = ';') {
259 auto get_val = [](size_t const& v) -> size_t const& {
260 return v;
261 };
262 write_list(vals, get_val);
263 };
264 auto writeNestedIouAmtList =
265 [&ostr, &writeIouAmtList](
267 ostr << '[';
268 if (!amts.empty())
269 {
270 writeIouAmtList(amts[0], '|');
271 for (size_t i = 1, e = amts.size(); i < e; ++i)
272 {
273 ostr << ';';
274 writeIouAmtList(amts[i], '|');
275 }
276 }
277 ostr << ']';
278 };
279 auto writeNestedXrpAmtList =
280 [&ostr, &writeXrpAmtList](
282 ostr << '[';
283 if (!amts.empty())
284 {
285 writeXrpAmtList(amts[0], '|');
286 for (size_t i = 1, e = amts.size(); i < e; ++i)
287 {
288 ostr << ';';
289 writeXrpAmtList(amts[i], '|');
290 }
291 }
292 ostr << ']';
293 };
294
295 ostr << ", in_pass: ";
296 if (passInfo.nativeIn)
297 writeXrpAmtList(passInfo.in);
298 else
299 writeIouAmtList(passInfo.in);
300 ostr << ", out_pass: ";
302 writeXrpAmtList(passInfo.out);
303 else
304 writeIouAmtList(passInfo.out);
305 ostr << ", num_active: ";
306 writeIntList(passInfo.numActive);
307 if (!passInfo.liquiditySrcIn.empty() &&
308 !passInfo.liquiditySrcIn.back().empty())
309 {
310 ostr << ", l_src_in: ";
311 if (passInfo.nativeIn)
312 writeNestedXrpAmtList(passInfo.liquiditySrcIn);
313 else
314 writeNestedIouAmtList(passInfo.liquiditySrcIn);
315 ostr << ", l_src_out: ";
317 writeNestedXrpAmtList(passInfo.liquiditySrcOut);
318 else
319 writeNestedIouAmtList(passInfo.liquiditySrcOut);
320 }
321 }
322
323 return ostr.str();
324 }
325};
326
327inline void
329 std::ostringstream& ostr,
331{
332 using namespace std;
333 auto const k = elem.first;
334 auto const v = elem.second;
335 ostr << '[' << get<0>(k) << '|' << get<1>(k) << '|' << get<2>(k) << '|' << v
336 << ']';
337};
338
339template <class Iter>
340void
341writeDiffs(std::ostringstream& ostr, Iter begin, Iter end)
342{
343 ostr << '[';
344 if (begin != end)
345 {
346 writeDiffElement(ostr, *begin);
347 ++begin;
348 }
349 for (; begin != end; ++begin)
350 {
351 ostr << ';';
352 writeDiffElement(ostr, *begin);
353 }
354 ostr << ']';
355};
356
359 XRPAmount>;
360
361inline BalanceDiffs
363{
364 return {sb.balanceChanges(rv), sb.xrpDestroyed()};
365}
366
367inline std::string
369{
370 if (!bd)
371 return std::string{};
372 auto const& diffs = bd->first;
373 auto const& xrpDestroyed = bd->second;
375 ostr << ", xrpDestroyed: " << to_string(xrpDestroyed);
376 ostr << ", balanceDiffs: ";
377 writeDiffs(ostr, diffs.begin(), diffs.end());
378 return ostr.str();
379};
380
381} // namespace detail
382} // namespace path
383} // namespace ripple
384#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:51
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:25
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
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)