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(txs.begin(), txs.end(), [](auto const& it) { return !it.second.accepted; });
233 }
234
235 // Returns the number of txs which were never validated
238 {
239 return std::count_if(txs.begin(), txs.end(), [](auto const& it) { return !it.second.validated; });
240 }
241
242 template <class T>
243 void
244 report(SimDuration simDuration, T& log, bool printBreakline = false)
245 {
246 using namespace std::chrono;
247 auto perSec = [&simDuration](std::size_t count) {
248 return double(count) / duration_cast<seconds>(simDuration).count();
249 };
250
251 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
252
253 if (printBreakline)
254 {
255 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-"
256 << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-"
257 << std::endl;
258 log << std::setfill(' ');
259 }
260
261 log << std::left << std::setw(11) << "TxStats" << "|" << std::setw(7) << "Count" << "|" << std::setw(7)
262 << "Per Sec" << "|" << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) << "10-ile"
263 << std::setw(7) << "50-ile" << std::setw(7) << "90-ile" << std::left << std::endl;
264
265 log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) << std::setfill('-') << "-" << "|"
266 << std::setw(7) << std::setfill('-') << "-" << "|" << std::setw(36) << std::setfill('-') << "-"
267 << std::endl;
268 log << std::setfill(' ');
269
270 log << std::left << std::setw(11) << "Submit " << "|" << std::right << std::setw(7) << submitted << "|"
271 << std::setw(7) << std::setprecision(2) << perSec(submitted) << "|" << std::setw(36) << "" << std::endl;
272
273 log << std::left << std::setw(11) << "Accept " << "|" << std::right << std::setw(7) << accepted << "|"
274 << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) << std::left
275 << "From Submit" << std::right << std::setw(7) << std::setprecision(2)
276 << fmtS(submitToAccept.percentile(0.1f)) << std::setw(7) << std::setprecision(2)
277 << fmtS(submitToAccept.percentile(0.5f)) << std::setw(7) << std::setprecision(2)
278 << fmtS(submitToAccept.percentile(0.9f)) << std::endl;
279
280 log << std::left << std::setw(11) << "Validate " << "|" << std::right << std::setw(7) << validated << "|"
281 << std::setw(7) << std::setprecision(2) << perSec(validated) << "|" << std::setw(15) << std::left
282 << "From Submit" << std::right << std::setw(7) << std::setprecision(2)
283 << fmtS(submitToValidate.percentile(0.1f)) << std::setw(7) << std::setprecision(2)
284 << fmtS(submitToValidate.percentile(0.5f)) << std::setw(7) << std::setprecision(2)
285 << fmtS(submitToValidate.percentile(0.9f)) << std::endl;
286
287 log << std::left << std::setw(11) << "Orphan" << "|" << std::right << std::setw(7) << orphaned() << "|"
288 << std::setw(7) << "" << "|" << std::setw(36) << std::endl;
289
290 log << std::left << std::setw(11) << "Unvalidated" << "|" << std::right << std::setw(7) << unvalidated() << "|"
291 << std::setw(7) << "" << "|" << std::setw(43) << std::endl;
292
293 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-"
294 << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-"
295 << std::endl;
296 log << std::setfill(' ');
297 }
298
299 template <class T, class Tag>
300 void
301 csv(SimDuration simDuration, T& log, Tag const& tag, bool printHeaders = false)
302 {
303 using namespace std::chrono;
304 auto perSec = [&simDuration](std::size_t count) {
305 return double(count) / duration_cast<seconds>(simDuration).count();
306 };
307
308 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
309
310 if (printHeaders)
311 {
312 log << "tag" << "," << "txNumSubmitted" << "," << "txNumAccepted"
313 << "," << "txNumValidated" << "," << "txNumOrphaned" << ","
314 << "txUnvalidated" << "," << "txRateSumbitted" << ","
315 << "txRateAccepted" << "," << "txRateValidated" << ","
316 << "txLatencySubmitToAccept10Pctl" << ","
317 << "txLatencySubmitToAccept50Pctl" << ","
318 << "txLatencySubmitToAccept90Pctl" << ","
319 << "txLatencySubmitToValidatet10Pctl" << ","
320 << "txLatencySubmitToValidatet50Pctl" << ","
321 << "txLatencySubmitToValidatet90Pctl" << std::endl;
322 }
323
324 log << tag
325 << ","
326 // txNumSubmitted
327 << submitted
328 << ","
329 // txNumAccepted
330 << accepted
331 << ","
332 // txNumValidated
333 << validated
334 << ","
335 // txNumOrphaned
336 << orphaned()
337 << ","
338 // txNumUnvalidated
339 << unvalidated()
340 << ","
341 // txRateSubmitted
342 << std::setprecision(2) << perSec(submitted)
343 << ","
344 // txRateAccepted
345 << std::setprecision(2) << perSec(accepted)
346 << ","
347 // txRateValidated
348 << std::setprecision(2) << perSec(validated)
349 << ","
350 // txLatencySubmitToAccept10Pctl
351 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f))
352 << ","
353 // txLatencySubmitToAccept50Pctl
354 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.5f))
355 << ","
356 // txLatencySubmitToAccept90Pctl
357 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.9f))
358 << ","
359 // txLatencySubmitToValidate10Pctl
361 << ","
362 // txLatencySubmitToValidate50Pctl
364 << ","
365 // txLatencySubmitToValidate90Pctl
366 << std::setprecision(2) << fmtS(submitToValidate.percentile(0.9f)) << "," << std::endl;
367 }
368};
369
377{
380
381 struct Tracker
382 {
385
386 Tracker(SimTime accepted_) : accepted{accepted_}
387 {
388 }
389 };
390
392
397
398 // Ignore most events by default
399 template <class E>
400 void
401 on(PeerID, SimTime, E const& e)
402 {
403 }
404
405 void
406 on(PeerID who, SimTime when, AcceptLedger const& e)
407 {
408 // First time this ledger accepted
409 if (ledgers_.emplace(e.ledger.id(), Tracker{when}).second)
410 {
411 ++accepted;
412 // ignore jumps?
413 if (e.prior.id() == e.ledger.parentID())
414 {
415 auto const it = ledgers_.find(e.ledger.parentID());
416 if (it != ledgers_.end())
417 {
418 acceptToAccept.insert(when - it->second.accepted);
419 }
420 }
421 }
422 }
423
424 void
426 {
427 // ignore jumps
428 if (e.prior.id() == e.ledger.parentID())
429 {
430 auto const it = ledgers_.find(e.ledger.id());
431 assert(it != ledgers_.end());
432 auto& tracker = it->second;
433 // first time fully validated
434 if (!tracker.fullyValidated)
435 {
437 tracker.fullyValidated = when;
438 acceptToFullyValid.insert(when - tracker.accepted);
439
440 auto const parentIt = ledgers_.find(e.ledger.parentID());
441 if (parentIt != ledgers_.end())
442 {
443 auto& parentTracker = parentIt->second;
444 if (parentTracker.fullyValidated)
445 {
446 fullyValidToFullyValid.insert(when - *parentTracker.fullyValidated);
447 }
448 }
449 }
450 }
451 }
452
455 {
456 return std::count_if(
457 ledgers_.begin(), ledgers_.end(), [](auto const& it) { return !it.second.fullyValidated; });
458 }
459
460 template <class T>
461 void
462 report(SimDuration simDuration, T& log, bool printBreakline = false)
463 {
464 using namespace std::chrono;
465 auto perSec = [&simDuration](std::size_t count) {
466 return double(count) / duration_cast<seconds>(simDuration).count();
467 };
468
469 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
470
471 if (printBreakline)
472 {
473 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-"
474 << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-"
475 << std::endl;
476 log << std::setfill(' ');
477 }
478
479 log << std::left << std::setw(11) << "LedgerStats" << "|" << std::setw(7) << "Count" << "|" << std::setw(7)
480 << "Per Sec"
481 << "|" << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) << "10-ile" << std::setw(7)
482 << "50-ile" << std::setw(7) << "90-ile" << std::left << std::endl;
483
484 log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) << std::setfill('-') << "-" << "|"
485 << std::setw(7) << std::setfill('-') << "-" << "|" << std::setw(36) << std::setfill('-') << "-"
486 << std::endl;
487 log << std::setfill(' ');
488
489 log << std::left << std::setw(11) << "Accept " << "|" << std::right << std::setw(7) << accepted << "|"
490 << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) << std::left
491 << "From Accept" << std::right << std::setw(7) << std::setprecision(2)
492 << fmtS(acceptToAccept.percentile(0.1f)) << std::setw(7) << std::setprecision(2)
493 << fmtS(acceptToAccept.percentile(0.5f)) << std::setw(7) << std::setprecision(2)
494 << fmtS(acceptToAccept.percentile(0.9f)) << std::endl;
495
496 log << std::left << std::setw(11) << "Validate " << "|" << std::right << std::setw(7) << fullyValidated << "|"
497 << std::setw(7) << std::setprecision(2) << perSec(fullyValidated) << "|" << std::setw(15) << std::left
498 << "From Validate " << std::right << std::setw(7) << std::setprecision(2)
502
503 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-"
504 << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-"
505 << std::endl;
506 log << std::setfill(' ');
507 }
508
509 template <class T, class Tag>
510 void
511 csv(SimDuration simDuration, T& log, Tag const& tag, bool printHeaders = false)
512 {
513 using namespace std::chrono;
514 auto perSec = [&simDuration](std::size_t count) {
515 return double(count) / duration_cast<seconds>(simDuration).count();
516 };
517
518 auto fmtS = [](SimDuration dur) { return duration_cast<duration<float>>(dur).count(); };
519
520 if (printHeaders)
521 {
522 log << "tag" << "," << "ledgerNumAccepted" << ","
523 << "ledgerNumFullyValidated" << "," << "ledgerRateAccepted"
524 << "," << "ledgerRateFullyValidated" << ","
525 << "ledgerLatencyAcceptToAccept10Pctl" << ","
526 << "ledgerLatencyAcceptToAccept50Pctl" << ","
527 << "ledgerLatencyAcceptToAccept90Pctl" << ","
528 << "ledgerLatencyFullyValidToFullyValid10Pctl" << ","
529 << "ledgerLatencyFullyValidToFullyValid50Pctl" << ","
530 << "ledgerLatencyFullyValidToFullyValid90Pctl" << std::endl;
531 }
532
533 log << tag
534 << ","
535 // ledgerNumAccepted
536 << accepted
537 << ","
538 // ledgerNumFullyValidated
540 << ","
541 // ledgerRateAccepted
542 << std::setprecision(2) << perSec(accepted)
543 << ","
544 // ledgerRateFullyValidated
545 << std::setprecision(2) << perSec(fullyValidated)
546 << ","
547 // ledgerLatencyAcceptToAccept10Pctl
548 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f))
549 << ","
550 // ledgerLatencyAcceptToAccept50Pctl
551 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.5f))
552 << ","
553 // ledgerLatencyAcceptToAccept90Pctl
554 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f))
555 << ","
556 // ledgerLatencyFullyValidToFullyValid10Pctl
558 << ","
559 // ledgerLatencyFullyValidToFullyValid50Pctl
561 << ","
562 // ledgerLatencyFullyValidToFullyValid90Pctl
564 }
565};
566
573{
575
576 // Ignore most events by default
577 template <class E>
578 void
579 on(PeerID, SimTime, E const& e)
580 {
581 }
582
583 void
584 on(PeerID who, SimTime when, AcceptLedger const& e)
585 {
586 out << when.time_since_epoch().count() << ": Node " << who << " accepted " << "L" << e.ledger.id() << " "
587 << e.ledger.txs() << "\n";
588 }
589
590 void
592 {
593 out << when.time_since_epoch().count() << ": Node " << who << " fully-validated " << "L" << e.ledger.id() << " "
594 << e.ledger.txs() << "\n";
595 }
596};
597
604{
612
615
616 // Ignore most events by default
617 template <class E>
618 void
619 on(PeerID, SimTime, E const& e)
620 {
621 }
622
623 void
624 on(PeerID who, SimTime when, AcceptLedger const& e)
625 {
626 // Not a direct child -> parent switch
627 if (e.ledger.parentID() != e.prior.id())
628 closeJumps.emplace_back(Jump{who, when, e.prior, e.ledger});
629 }
630
631 void
633 {
634 // Not a direct child -> parent switch
635 if (e.ledger.parentID() != e.prior.id())
636 fullyValidatedJumps.emplace_back(Jump{who, when, e.prior, e.ledger});
637 }
638};
639
640} // namespace csf
641} // namespace test
642} // 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:44
TxSetType const & txs() const
Definition ledgers.h:187
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:604
std::vector< Jump > fullyValidatedJumps
Definition collectors.h:614
void on(PeerID, SimTime, E const &e)
Definition collectors.h:619
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:632
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:624
std::vector< Jump > closeJumps
Definition collectors.h:613
std::optional< SimTime > fullyValidated
Definition collectors.h:384
Tracks the accepted -> validated evolution of ledgers.
Definition collectors.h:377
hash_map< Ledger::ID, Tracker > ledgers_
Definition collectors.h:391
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:406
void csv(SimDuration simDuration, T &log, Tag const &tag, bool printHeaders=false)
Definition collectors.h:511
void on(PeerID, SimTime, E const &e)
Definition collectors.h:401
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:425
void report(SimDuration simDuration, T &log, bool printBreakline=false)
Definition collectors.h:462
std::size_t unvalidated() const
Definition collectors.h:454
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:573
void on(PeerID, SimTime, E const &e)
Definition collectors.h:579
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition collectors.h:591
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition collectors.h:584
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:244
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:237
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:301