rippled
Loading...
Searching...
No Matches
collectors.h
1#pragma once
2
3#include <test/csf/Histogram.h>
4#include <test/csf/SimTime.h>
5#include <test/csf/events.h>
6
7#include <xrpl/basics/UnorderedContainers.h>
8
9#include <chrono>
10#include <optional>
11#include <ostream>
12#include <tuple>
13
14namespace xrpl {
15namespace test {
16namespace csf {
17
18// A collector is any class that implements
19//
20// on(NodeID, SimTime, Event)
21//
22// for all events emitted by a Peer.
23//
24// This file contains helper functions for composing different collectors
25// and also defines several standard collectors available for simulations.
26
34template <class... Cs>
36{
37 std::tuple<Cs&...> cs;
38
39 template <class C, class E>
40 static void
41 apply(C& c, PeerID who, SimTime when, E e)
42 {
43 c.on(who, when, e);
44 }
45
46 template <std::size_t... Is, class E>
47 static void
49 {
50 (..., apply(std::get<Is>(cs), who, when, e));
51 }
52
53public:
58 Collectors(Cs&... cs_) : cs(std::tie(cs_...))
59 {
60 }
61
62 template <class E>
63 void
64 on(PeerID who, SimTime when, E e)
65 {
66 apply(cs, who, when, e, std::index_sequence_for<Cs...>{});
67 }
68};
69
71template <class... Cs>
72Collectors<Cs...>
74{
75 return Collectors<Cs...>(cs...);
76}
77
86template <class CollectorType>
88{
90
91 CollectorType&
93 {
94 return byNode[who];
95 }
96
97 CollectorType const&
98 operator[](PeerID who) const
99 {
100 return byNode[who];
101 }
102 template <class E>
103 void
104 on(PeerID who, SimTime when, E const& e)
105 {
106 byNode[who].on(who, when, e);
107 }
108};
109
112{
113 template <class E>
114 void
115 on(PeerID, SimTime, E const& e)
116 {
117 }
118};
119
122{
123 bool init = false;
126
127 template <class E>
128 void
129 on(PeerID, SimTime when, E const& e)
130 {
131 if (!init)
132 {
133 start = when;
134 init = true;
135 }
136 else
137 stop = when;
138 }
139};
140
151{
152 // Counts
156
168
170
174
175 // Ignore most events by default
176 template <class E>
177 void
178 on(PeerID, SimTime when, E const& e)
179 {
180 }
181
182 void
183 on(PeerID who, SimTime when, SubmitTx const& e)
184 {
185 // save first time it was seen
186 if (txs.emplace(e.tx.id(), Tracker{e.tx, when}).second)
187 {
188 submitted++;
189 }
190 }
191
192 void
193 on(PeerID who, SimTime when, AcceptLedger const& e)
194 {
195 for (auto const& tx : e.ledger.txs())
196 {
197 auto it = txs.find(tx.id());
198 if (it != txs.end() && !it->second.accepted)
199 {
200 Tracker& tracker = it->second;
201 tracker.accepted = when;
202 accepted++;
203
204 submitToAccept.insert(*tracker.accepted - tracker.submitted);
205 }
206 }
207 }
208
209 void
211 {
212 for (auto const& tx : e.ledger.txs())
213 {
214 auto it = txs.find(tx.id());
215 if (it != txs.end() && !it->second.validated)
216 {
217 Tracker& tracker = it->second;
218 // Should only validated a previously accepted Tx
219 assert(tracker.accepted);
220
221 tracker.validated = when;
222 validated++;
223 submitToValidate.insert(*tracker.validated - tracker.submitted);
224 }
225 }
226 }
227
228 // Returns the number of txs which were never accepted
230 orphaned() const
231 {
232 return std::count_if(
233 txs.begin(), txs.end(), [](auto const& it) { return !it.second.accepted; });
234 }
235
236 // Returns the number of txs which were never validated
239 {
240 return std::count_if(
241 txs.begin(), txs.end(), [](auto const& it) { return !it.second.validated; });
242 }
243
244 template <class T>
245 void
246 report(SimDuration simDuration, T& log, bool printBreakline = false)
247 {
248 using namespace std::chrono;
249 auto perSec = [&simDuration](std::size_t count) {
250 return double(count) / duration_cast<seconds>(simDuration).count();
251 };
252
253 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
254
255 if (printBreakline)
256 {
257 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7)
258 << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-"
259 << "-" << std::setw(36) << std::setfill('-') << "-" << std::endl;
260 log << std::setfill(' ');
261 }
262
263 log << std::left << std::setw(11) << "TxStats" << "|" << std::setw(7) << "Count" << "|"
264 << std::setw(7) << "Per Sec" << "|" << std::setw(15) << "Latency (sec)" << std::right
265 << std::setw(7) << "10-ile" << std::setw(7) << "50-ile" << std::setw(7) << "90-ile"
266 << std::left << std::endl;
267
268 log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) << std::setfill('-')
269 << "-" << "|" << std::setw(7) << std::setfill('-') << "-" << "|" << std::setw(36)
270 << std::setfill('-') << "-" << std::endl;
271 log << std::setfill(' ');
272
273 log << std::left << std::setw(11) << "Submit " << "|" << std::right << std::setw(7)
274 << submitted << "|" << std::setw(7) << std::setprecision(2) << perSec(submitted) << "|"
275 << std::setw(36) << "" << std::endl;
276
277 log << std::left << std::setw(11) << "Accept " << "|" << std::right << std::setw(7)
278 << accepted << "|" << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|"
279 << std::setw(15) << std::left << "From Submit" << std::right << std::setw(7)
280 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f)) << std::setw(7)
281 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.5f)) << std::setw(7)
283
284 log << std::left << std::setw(11) << "Validate " << "|" << std::right << std::setw(7)
285 << validated << "|" << std::setw(7) << std::setprecision(2) << perSec(validated) << "|"
286 << std::setw(15) << std::left << "From Submit" << std::right << std::setw(7)
287 << std::setprecision(2) << fmtS(submitToValidate.percentile(0.1f)) << std::setw(7)
288 << std::setprecision(2) << fmtS(submitToValidate.percentile(0.5f)) << std::setw(7)
290
291 log << std::left << std::setw(11) << "Orphan" << "|" << std::right << std::setw(7)
292 << orphaned() << "|" << std::setw(7) << "" << "|" << std::setw(36) << std::endl;
293
294 log << std::left << std::setw(11) << "Unvalidated" << "|" << std::right << std::setw(7)
295 << unvalidated() << "|" << std::setw(7) << "" << "|" << std::setw(43) << std::endl;
296
297 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-')
298 << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36)
299 << std::setfill('-') << "-" << std::endl;
300 log << std::setfill(' ');
301 }
302
303 template <class T, class Tag>
304 void
305 csv(SimDuration simDuration, T& log, Tag const& tag, bool printHeaders = false)
306 {
307 using namespace std::chrono;
308 auto perSec = [&simDuration](std::size_t count) {
309 return double(count) / duration_cast<seconds>(simDuration).count();
310 };
311
312 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
313
314 if (printHeaders)
315 {
316 log << "tag" << "," << "txNumSubmitted" << "," << "txNumAccepted"
317 << "," << "txNumValidated" << "," << "txNumOrphaned" << ","
318 << "txUnvalidated" << "," << "txRateSumbitted" << ","
319 << "txRateAccepted" << "," << "txRateValidated" << ","
320 << "txLatencySubmitToAccept10Pctl" << ","
321 << "txLatencySubmitToAccept50Pctl" << ","
322 << "txLatencySubmitToAccept90Pctl" << ","
323 << "txLatencySubmitToValidatet10Pctl" << ","
324 << "txLatencySubmitToValidatet50Pctl" << ","
325 << "txLatencySubmitToValidatet90Pctl" << std::endl;
326 }
327
328 log << tag
329 << ","
330 // txNumSubmitted
331 << submitted
332 << ","
333 // txNumAccepted
334 << accepted
335 << ","
336 // txNumValidated
337 << validated
338 << ","
339 // txNumOrphaned
340 << orphaned()
341 << ","
342 // txNumUnvalidated
343 << unvalidated()
344 << ","
345 // txRateSubmitted
346 << std::setprecision(2) << perSec(submitted)
347 << ","
348 // txRateAccepted
349 << std::setprecision(2) << perSec(accepted)
350 << ","
351 // txRateValidated
352 << std::setprecision(2) << perSec(validated)
353 << ","
354 // txLatencySubmitToAccept10Pctl
355 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f))
356 << ","
357 // txLatencySubmitToAccept50Pctl
358 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.5f))
359 << ","
360 // txLatencySubmitToAccept90Pctl
361 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.9f))
362 << ","
363 // txLatencySubmitToValidate10Pctl
365 << ","
366 // txLatencySubmitToValidate50Pctl
368 << ","
369 // txLatencySubmitToValidate90Pctl
370 << std::setprecision(2) << fmtS(submitToValidate.percentile(0.9f)) << "," << std::endl;
371 }
372};
373
381{
384
385 struct Tracker
386 {
389
390 Tracker(SimTime accepted_) : accepted{accepted_}
391 {
392 }
393 };
394
396
401
402 // Ignore most events by default
403 template <class E>
404 void
405 on(PeerID, SimTime, E const& e)
406 {
407 }
408
409 void
410 on(PeerID who, SimTime when, AcceptLedger const& e)
411 {
412 // First time this ledger accepted
413 if (ledgers_.emplace(e.ledger.id(), Tracker{when}).second)
414 {
415 ++accepted;
416 // ignore jumps?
417 if (e.prior.id() == e.ledger.parentID())
418 {
419 auto const it = ledgers_.find(e.ledger.parentID());
420 if (it != ledgers_.end())
421 {
422 acceptToAccept.insert(when - it->second.accepted);
423 }
424 }
425 }
426 }
427
428 void
430 {
431 // ignore jumps
432 if (e.prior.id() == e.ledger.parentID())
433 {
434 auto const it = ledgers_.find(e.ledger.id());
435 assert(it != ledgers_.end());
436 auto& tracker = it->second;
437 // first time fully validated
438 if (!tracker.fullyValidated)
439 {
441 tracker.fullyValidated = when;
442 acceptToFullyValid.insert(when - tracker.accepted);
443
444 auto const parentIt = ledgers_.find(e.ledger.parentID());
445 if (parentIt != ledgers_.end())
446 {
447 auto& parentTracker = parentIt->second;
448 if (parentTracker.fullyValidated)
449 {
450 fullyValidToFullyValid.insert(when - *parentTracker.fullyValidated);
451 }
452 }
453 }
454 }
455 }
456
459 {
460 return std::count_if(ledgers_.begin(), ledgers_.end(), [](auto const& it) {
461 return !it.second.fullyValidated;
462 });
463 }
464
465 template <class T>
466 void
467 report(SimDuration simDuration, T& log, bool printBreakline = false)
468 {
469 using namespace std::chrono;
470 auto perSec = [&simDuration](std::size_t count) {
471 return double(count) / duration_cast<seconds>(simDuration).count();
472 };
473
474 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
475
476 if (printBreakline)
477 {
478 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7)
479 << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-"
480 << "-" << std::setw(36) << std::setfill('-') << "-" << std::endl;
481 log << std::setfill(' ');
482 }
483
484 log << std::left << std::setw(11) << "LedgerStats" << "|" << std::setw(7) << "Count" << "|"
485 << std::setw(7) << "Per Sec"
486 << "|" << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) << "10-ile"
487 << std::setw(7) << "50-ile" << std::setw(7) << "90-ile" << std::left << std::endl;
488
489 log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) << std::setfill('-')
490 << "-" << "|" << std::setw(7) << std::setfill('-') << "-" << "|" << std::setw(36)
491 << std::setfill('-') << "-" << std::endl;
492 log << std::setfill(' ');
493
494 log << std::left << std::setw(11) << "Accept " << "|" << std::right << std::setw(7)
495 << accepted << "|" << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|"
496 << std::setw(15) << std::left << "From Accept" << std::right << std::setw(7)
497 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f)) << std::setw(7)
498 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.5f)) << std::setw(7)
500
501 log << std::left << std::setw(11) << "Validate " << "|" << std::right << std::setw(7)
502 << fullyValidated << "|" << std::setw(7) << std::setprecision(2)
503 << perSec(fullyValidated) << "|" << std::setw(15) << std::left << "From Validate "
508
509 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-')
510 << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36)
511 << std::setfill('-') << "-" << std::endl;
512 log << std::setfill(' ');
513 }
514
515 template <class T, class Tag>
516 void
517 csv(SimDuration simDuration, T& log, Tag const& tag, bool printHeaders = false)
518 {
519 using namespace std::chrono;
520 auto perSec = [&simDuration](std::size_t count) {
521 return double(count) / duration_cast<seconds>(simDuration).count();
522 };
523
524 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
525
526 if (printHeaders)
527 {
528 log << "tag" << "," << "ledgerNumAccepted" << ","
529 << "ledgerNumFullyValidated" << "," << "ledgerRateAccepted"
530 << "," << "ledgerRateFullyValidated" << ","
531 << "ledgerLatencyAcceptToAccept10Pctl" << ","
532 << "ledgerLatencyAcceptToAccept50Pctl" << ","
533 << "ledgerLatencyAcceptToAccept90Pctl" << ","
534 << "ledgerLatencyFullyValidToFullyValid10Pctl" << ","
535 << "ledgerLatencyFullyValidToFullyValid50Pctl" << ","
536 << "ledgerLatencyFullyValidToFullyValid90Pctl" << std::endl;
537 }
538
539 log << tag
540 << ","
541 // ledgerNumAccepted
542 << accepted
543 << ","
544 // ledgerNumFullyValidated
546 << ","
547 // ledgerRateAccepted
548 << std::setprecision(2) << perSec(accepted)
549 << ","
550 // ledgerRateFullyValidated
551 << std::setprecision(2) << perSec(fullyValidated)
552 << ","
553 // ledgerLatencyAcceptToAccept10Pctl
554 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f))
555 << ","
556 // ledgerLatencyAcceptToAccept50Pctl
557 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.5f))
558 << ","
559 // ledgerLatencyAcceptToAccept90Pctl
560 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f))
561 << ","
562 // ledgerLatencyFullyValidToFullyValid10Pctl
564 << ","
565 // ledgerLatencyFullyValidToFullyValid50Pctl
567 << ","
568 // ledgerLatencyFullyValidToFullyValid90Pctl
570 }
571};
572
579{
581
582 // Ignore most events by default
583 template <class E>
584 void
585 on(PeerID, SimTime, E const& e)
586 {
587 }
588
589 void
590 on(PeerID who, SimTime when, AcceptLedger const& e)
591 {
592 out << when.time_since_epoch().count() << ": Node " << who << " accepted " << "L"
593 << e.ledger.id() << " " << e.ledger.txs() << "\n";
594 }
595
596 void
598 {
599 out << when.time_since_epoch().count() << ": Node " << who << " fully-validated " << "L"
600 << e.ledger.id() << " " << e.ledger.txs() << "\n";
601 }
602};
603
610{
618
621
622 // Ignore most events by default
623 template <class E>
624 void
625 on(PeerID, SimTime, E const& e)
626 {
627 }
628
629 void
630 on(PeerID who, SimTime when, AcceptLedger const& e)
631 {
632 // Not a direct child -> parent switch
633 if (e.ledger.parentID() != e.prior.id())
634 closeJumps.emplace_back(Jump{who, when, e.prior, e.ledger});
635 }
636
637 void
639 {
640 // Not a direct child -> parent switch
641 if (e.ledger.parentID() != e.prior.id())
642 fullyValidatedJumps.emplace_back(Jump{who, when, e.prior, e.ledger});
643 }
644};
645
646} // namespace csf
647} // namespace test
648} // namespace xrpl
Group of collectors.
Definition collectors.h:36
std::tuple< Cs &... > cs
Definition collectors.h:37
static void apply(std::tuple< Cs &... > &cs, PeerID who, SimTime when, E e, std::index_sequence< Is... >)
Definition collectors.h:48
void on(PeerID who, SimTime when, E e)
Definition collectors.h:64
Collectors(Cs &... cs_)
Constructor.
Definition collectors.h:58
static void apply(C &c, PeerID who, SimTime when, E e)
Definition collectors.h:41
T percentile(float p) const
Calculate the given percentile of the distribution.
Definition Histogram.h:92
void insert(T const &s)
Insert an sample.
Definition Histogram.h:35
A ledger is a set of observed transactions and a sequence number identifying the ledger.
Definition ledgers.h:43
TxSetType const & txs() const
Definition ledgers.h:193
A single transaction.
Definition Tx.h:22
ID const & id() const
Definition Tx.h:36
T count_if(T... args)
T endl(T... args)
T is_same_v
T left(T... args)
STL namespace.
typename SimClock::duration SimDuration
Definition SimTime.h:16
typename SimClock::time_point SimTime
Definition SimTime.h:17
Collectors< Cs... > makeCollectors(Cs &... cs)
Create an instance of Collectors<Cs...>
Definition collectors.h:73
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
T setfill(T... args)
T setprecision(T... args)
T setw(T... args)
Peer accepted consensus results.
Definition events.h:101
Maintain an instance of a Collector per peer.
Definition collectors.h:88
CollectorType const & operator[](PeerID who) const
Definition collectors.h:98
void on(PeerID who, SimTime when, E const &e)
Definition collectors.h:104
std::map< PeerID, CollectorType > byNode
Definition collectors.h:89
CollectorType & operator[](PeerID who)
Definition collectors.h:92
Peer fully validated a new ledger.
Definition events.h:120
Ledger prior
The prior fully validated ledger This is a jump if prior.id() != ledger.parentID()
Definition events.h:126
Ledger ledger
The new fully validated ledger.
Definition events.h:122
Saves information about Jumps for closed and fully validated ledgers.
Definition collectors.h:610
std::vector< Jump > fullyValidatedJumps
Definition collectors.h:620
void on(PeerID, SimTime, E const &e)
Definition collectors.h:625
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:638
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:630
std::vector< Jump > closeJumps
Definition collectors.h:619
std::optional< SimTime > fullyValidated
Definition collectors.h:388
Tracks the accepted -> validated evolution of ledgers.
Definition collectors.h:381
hash_map< Ledger::ID, Tracker > ledgers_
Definition collectors.h:395
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:410
void csv(SimDuration simDuration, T &log, Tag const &tag, bool printHeaders=false)
Definition collectors.h:517
void on(PeerID, SimTime, E const &e)
Definition collectors.h:405
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:429
void report(SimDuration simDuration, T &log, bool printBreakline=false)
Definition collectors.h:467
std::size_t unvalidated() const
Definition collectors.h:458
Collector which ignores all events.
Definition collectors.h:112
void on(PeerID, SimTime, E const &e)
Definition collectors.h:115
Tracks the overall duration of a simulation.
Definition collectors.h:122
void on(PeerID, SimTime when, E const &e)
Definition collectors.h:129
Write out stream of ledger activity.
Definition collectors.h:579
void on(PeerID, SimTime, E const &e)
Definition collectors.h:585
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:597
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:590
A transaction submitted to a peer.
Definition events.h:72
Tx tx
The submitted transaction.
Definition events.h:74
std::optional< SimTime > accepted
Definition collectors.h:161
std::optional< SimTime > validated
Definition collectors.h:162
Tracker(Tx tx_, SimTime submitted_)
Definition collectors.h:164
Tracks the submission -> accepted -> validated evolution of transactions.
Definition collectors.h:151
void report(SimDuration simDuration, T &log, bool printBreakline=false)
Definition collectors.h:246
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:193
std::size_t orphaned() const
Definition collectors.h:230
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:210
std::size_t unvalidated() const
Definition collectors.h:238
void on(PeerID, SimTime when, E const &e)
Definition collectors.h:178
hash_map< Tx::ID, Tracker > txs
Definition collectors.h:169
void on(PeerID who, SimTime when, SubmitTx const &e)
Definition collectors.h:183
void csv(SimDuration simDuration, T &log, Tag const &tag, bool printHeaders=false)
Definition collectors.h:305