CCF
Loading...
Searching...
No Matches
perf_client.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5// Local
6#include "timing.h"
7
8// CCF
10#include "ccf/crypto/verifier.h"
11#include "ccf/ds/logger.h"
13#include "ds/cli_helper.h"
14#include "ds/files.h"
15
16// STL/3rdparty
17#include <CLI11/CLI11.hpp>
18#include <chrono>
19#include <fstream>
20#include <nlohmann/json.hpp>
21#include <random>
22#include <thread>
23#include <unistd.h>
24
25namespace client
26{
27 constexpr auto perf_summary = "perf_summary.csv";
28
29 bool pin_to_core(int core_id)
30 {
31 int threads = std::thread::hardware_concurrency();
32 if (core_id > threads || core_id < 0)
33 {
34 LOG_FATAL_FMT("Invalid core id: {}", core_id);
35 abort();
36 return false;
37 }
38
39 cpu_set_t set;
40 LOG_INFO_FMT("Pinning to core: {}", core_id);
41 CPU_ZERO(&set);
42 CPU_SET(core_id, &set);
43
44 if (sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0)
45 {
46 LOG_FATAL_FMT("Unable to set affinity");
47 abort();
48 return false;
49 }
50
51 return true;
52 }
53
55 {
58 std::string label; //< Default set in constructor
59 std::string pid_file; //< Default set in constructor
60
63
64 size_t num_transactions = 10000;
65 size_t thread_count = 1;
66 size_t session_count = 1;
67 size_t max_writes_ahead = 0;
68 size_t latency_rounds = 1;
69 size_t generator_seed = 42u;
71
72 bool sign = false;
73 bool no_create = false;
74 bool no_wait = false;
75 bool write_tx_times = false;
76 bool randomise = false;
77 bool check_responses = false;
78 bool relax_commit_target = false;
80
82 const std::string& default_label,
83 const std::string& default_pid_file,
84 CLI::App& app) :
85 label(default_label),
86 pid_file(fmt::format("{}.pid", default_pid_file))
87 {
88 // Enable config from file
89 app.set_config("--config");
90
91 app
92 .add_option(
93 "--label",
94 label,
95 fmt::format(
96 "Identifier for this client, written to {}", perf_summary))
97 ->capture_default_str();
98
99 app
100 .add_option(
101 "--pid-file",
102 pid_file,
103 "Path to which the client PID will be written")
104 ->capture_default_str();
105
106 // Connection details
107 cli::add_address_option(
108 app,
110 "--rpc-address",
111 "Remote node JSON RPC address to which requests should be sent")
112 ->required(true);
113
114 app.add_option("--cert", cert_file)
115 ->required(true)
116 ->check(CLI::ExistingFile);
117 app.add_option("--pk", key_file)
118 ->required(true)
119 ->check(CLI::ExistingFile);
120 app.add_option("--ca", ca_file)->required(true)->check(CLI::ExistingFile);
121 app.add_option("--bearer-token", bearer_token)->required(false);
122
123 app
124 .add_option(
125 "--verify",
127 "Verify results against expectation, specified in file")
128 ->required(false)
129 ->check(CLI::ExistingFile);
130 app.add_option("--generator-seed", generator_seed);
131
132 app.add_option(
133 "--transaction-rate",
135 "The number of transactions per second to send");
136
137 // Transaction counts and batching details
138 app
139 .add_option(
140 "--transactions",
142 "The basic number of transactions to send (will actually send this "
143 "many for each thread, in each session)")
144 ->capture_default_str();
145 app.add_option("-t,--threads", thread_count)->capture_default_str();
146 app.add_option("-s,--sessions", session_count)->capture_default_str();
147 app
148 .add_option(
149 "--max-writes-ahead",
151 "How many transactions the client should send without waiting for "
152 "responses. 0 will send all transactions before blocking for any "
153 "responses, 1 will minimise latency by serially waiting for each "
154 "transaction's response, other values may provide a balance between "
155 "throughput and latency")
156 ->capture_default_str();
157
158 app.add_option("--latency-rounds", latency_rounds)->capture_default_str();
159
160 // Boolean flags
161 app.add_flag("--sign", sign, "Send client-signed transactions")
162 ->capture_default_str();
163 app
164 .add_flag("--no-create", no_create, "Skip creation/setup transactions")
165 ->capture_default_str();
166 app
167 .add_flag(
168 "--no-wait",
169 no_wait,
170 "Don't wait for transactions to be globally committed")
171 ->capture_default_str();
172 app
173 .add_flag(
174 "--write-tx-times",
176 "Write tx sent and received times to csv")
177 ->capture_default_str();
178 app
179 .add_flag(
180 "--randomise",
181 randomise,
182 "Use non-deterministically random transaction contents each run")
183 ->capture_default_str();
184 app
185 .add_flag(
186 "--check-responses",
188 "Check every JSON response for errors. Potentially slow")
189 ->capture_default_str();
190 }
191 };
192
196 template <typename TOptions>
198 {
199 protected:
206
207 private:
208 ccf::crypto::Pem key = {};
209 std::string key_id = "Invalid";
210 std::shared_ptr<::tls::Cert> tls_cert = nullptr;
211
212 // Process reply to an RPC. Records time reply was received. Calls
213 // check_response for derived-overridable validation
214 void process_reply(const RpcTlsClient::Response& reply)
215 {
216 if (options.check_responses)
217 {
218 if (!check_response(reply))
219 {
220 throw std::logic_error("Response failed check");
221 }
222 }
223
224 if (
226 (reply.status == HTTP_STATUS_OK ||
227 reply.status == HTTP_STATUS_NO_CONTENT))
228 {
229 const auto tx_id = timing::extract_transaction_id(reply);
230
231 if (!tx_id.has_value())
232 {
233 throw std::logic_error("No transaction ID found in response headers");
234 }
235
236 // Record time of received responses
237 response_times.record_receive(reply.id, tx_id);
238
239 if (tx_id->view < last_response_tx_id.view)
240 {
241 throw std::logic_error(fmt::format(
242 "View went backwards (expected {}, saw {})!",
244 tx_id->view));
245 }
246 else if (
247 tx_id->view > last_response_tx_id.view &&
248 tx_id->seqno <= last_response_tx_id.seqno)
249 {
250 throw std::logic_error(fmt::format(
251 "There has been an election and transactions have "
252 "been lost! (saw {}.{}, currently at {}.{})",
255 tx_id->view,
256 tx_id->seqno));
257 }
258
259 last_response_tx_id = tx_id.value();
260 }
261 }
262
263 void append_prepared_tx(
264 const PreparedTx& tx, const std::optional<size_t>& index)
265 {
266 if (index.has_value())
267 {
268 assert(index.value() < prepared_txs.size());
269 prepared_txs[index.value()] = tx;
270 }
271 else
272 {
273 prepared_txs.push_back(tx);
274 }
275 }
276
277 protected:
278 TOptions options;
279
280 std::mt19937 rand_generator;
281
282 nlohmann::json verification_target;
283
284 using PreparedTxs = std::vector<PreparedTx>;
285
286 std::shared_ptr<RpcTlsClient> rpc_connection;
288
291
292 std::chrono::high_resolution_clock::time_point last_write_time;
293 std::chrono::nanoseconds write_delay_ns = std::chrono::nanoseconds::zero();
294
295 std::shared_ptr<RpcTlsClient> create_connection(bool force_unsigned = false)
296 {
297 // Create a cert if this is our first rpc_connection
298 const bool is_first_time = tls_cert == nullptr;
299
300 if (is_first_time)
301 {
302 const auto raw_cert = files::slurp(options.cert_file);
303 const auto raw_key = files::slurp(options.key_file);
304 const auto ca = files::slurp_string(options.ca_file);
305
306 key = ccf::crypto::Pem(raw_key);
307
308 const ccf::crypto::Pem cert_pem(raw_cert);
309 auto cert_der = ccf::crypto::cert_pem_to_der(cert_pem);
310 key_id = ccf::crypto::Sha256Hash(cert_der).hex_str();
311
312 tls_cert = std::make_shared<::tls::Cert>(
313 std::make_shared<::tls::CA>(ca), cert_pem, key);
314 }
315
316 const auto [host, port] = ccf::split_net_address(options.server_address);
317 auto conn =
318 std::make_shared<RpcTlsClient>(host, port, nullptr, tls_cert, key_id);
319
320 if (options.sign && !force_unsigned)
321 {
322 LOG_INFO_FMT("Creating key pair");
323 conn->create_key_pair(key);
324 }
325
326 conn->set_prefix("app");
327
328 // Report ciphersuite of first client (assume it is the same for each)
329 if (is_first_time)
330 {
332 "Connected to server via TLS ({})", conn->get_ciphersuite_name());
333 }
334
335 return conn;
336 }
337
339 const std::string& method,
340 const std::span<const uint8_t> params,
341 bool expects_commit,
342 const std::optional<size_t>& index)
343 {
344 const PreparedTx tx{
345 rpc_connection->gen_request(
346 method,
347 params,
348 ccf::http::headervalues::contenttype::JSON,
349 HTTP_POST,
350 options.bearer_token.size() == 0 ? nullptr :
351 options.bearer_token.c_str()),
352 method,
353 expects_commit};
354
355 append_prepared_tx(tx, index);
356 }
357
358 static size_t total_byte_size(const PreparedTxs& txs)
359 {
360 return std::accumulate(
361 txs.begin(), txs.end(), 0, [](size_t n, const PreparedTx& tx) {
362 return n + tx.rpc.encoded.size();
363 });
364 }
365
366 // Everything else has empty stubs and can optionally be overridden. This
367 // must be provided by derived class
368 virtual void prepare_transactions() = 0;
369
370 virtual std::optional<RpcTlsClient::Response> send_creation_transactions()
371 {
372 return std::nullopt;
373 }
374
376 {
377 // Default behaviour is to accept anything that doesn't contain an error
378 return r.status == HTTP_STATUS_OK;
379 }
380
381 virtual void pre_creation_hook(){};
382 virtual void post_creation_hook(){};
383
384 virtual void pre_timing_body_hook(){};
385 virtual void post_timing_body_hook(){};
386
388 std::shared_ptr<RpcTlsClient>& connection, const PreparedTxs& txs)
389 {
390 size_t read;
391 size_t written;
392
393 if (options.transactions_per_s > 0)
394 {
396 std::chrono::nanoseconds{1000000000 / options.transactions_per_s};
397 connection->set_tcp_nodelay(true);
398 }
399
400 last_write_time = std::chrono::high_resolution_clock::now();
402
403 // Repeat for each session
404 for (size_t session = 1; session <= options.session_count; ++session)
405 {
406 read = 0;
407 written = 0;
408
409 // Write everything
410 while (written < txs.size())
411 write(txs[written], read, written, connection);
412
413 blocking_read(read, written, connection);
414
415 // Reconnect for each session (except the last)
416 if (session != options.session_count)
417 {
418 reconnect(connection);
419 }
420 }
421
422 if (!options.no_wait)
423 {
424 // Separate connection for GETs
425 auto c = create_connection(true);
427 }
428 const auto last_commit = last_response_tx_id.seqno;
429 auto timing_results = end_timing(last_commit);
430 LOG_INFO_FMT("Timing ended");
431 return timing_results;
432 }
433
435 {
436 LOG_INFO_FMT("About to begin timing");
437 begin_timing();
438 LOG_INFO_FMT("Began timing");
439 }
440
441 inline void write(
442 const PreparedTx& tx,
443 size_t& read,
444 size_t& written,
445 const std::shared_ptr<RpcTlsClient>& connection)
446 {
447 while (std::chrono::high_resolution_clock::now() - last_write_time <
449 {
450 continue;
451 }
452
453 // Record time of sent requests
455 {
457 }
458
459 connection->write(tx.rpc.encoded);
460 last_write_time = std::chrono::high_resolution_clock::now();
461
462 ++written;
463
464 // Optimistically read (non-blocking) any current responses
465 while (read < written)
466 {
467 const auto r = connection->read_response_non_blocking();
468 if (!r.has_value())
469 {
470 // If we have no responses waiting, move on to the next thing
471 break;
472 }
473
474 process_reply(r.value());
475 ++read;
476 }
477
478 // Do blocking reads if we're beyond our write-ahead limit
479 if (options.max_writes_ahead > 0) // 0 is a special value allowing
480 // unlimited write-ahead
481 {
482 while (written - read >= options.max_writes_ahead)
483 {
484 process_reply(connection->read_response());
485 ++read;
486 }
487 }
488 }
489
491 size_t& read,
492 size_t written,
493 const std::shared_ptr<RpcTlsClient>& connection)
494 {
495 // Read response (blocking) for all pending txs
496 while (read < written)
497 {
498 process_reply(connection->read_response());
499 ++read;
500 }
501 }
502
503 void reconnect(std::shared_ptr<RpcTlsClient>& connection)
504 {
505 connection.reset(new RpcTlsClient(*connection.get()));
506 }
507
509 const std::shared_ptr<RpcTlsClient>& connection,
510 size_t view,
511 size_t seqno)
512 {
513 nlohmann::json p;
514 p["transaction_id"] = fmt::format("{}.{}", view, seqno);
515 return connection->get("tx", p);
516 }
517
518 virtual void verify_params(const nlohmann::json& expected)
519 {
520 // It's only reasonable to compare against expected state if the initial
521 // parameters match, so check a few obvious ones
522
523 {
524 const auto it = expected.find("seed");
525 if (it != expected.end())
526 {
527 const auto expected_seed =
528 it->get<decltype(options.generator_seed)>();
529 if (expected_seed != options.generator_seed)
530 {
531 throw std::runtime_error(fmt::format(
532 "Verification file expects seed {}, but currently using {}",
533 expected_seed,
534 options.generator_seed));
535 }
536 }
537 }
538
539 {
540 const auto it = expected.find("transactions");
541 if (it != expected.end())
542 {
543 const auto expected_txs =
544 it->get<decltype(options.num_transactions)>();
545 if (expected_txs != options.num_transactions)
546 {
547 throw std::runtime_error(fmt::format(
548 "Verification file is only applicable for {} transactions, but "
549 "currently running {}",
550 expected_txs,
551 options.num_transactions));
552 }
553 }
554 }
555
556 {
557 const auto it = expected.find("sessions");
558 if (it != expected.end())
559 {
560 const auto expected_sessions =
561 it->get<decltype(options.session_count)>();
562 if (expected_sessions != options.session_count)
563 {
564 throw std::runtime_error(fmt::format(
565 "Verification file is only applicable for {} sessions, but "
566 "currently running {}",
567 expected_sessions,
568 options.session_count));
569 }
570 }
571 }
572
573 {
574 bool expected_randomise = false;
575 const auto it = expected.find("randomise");
576 if (it != expected.end())
577 {
578 expected_randomise = it->get<bool>();
579 }
580
581 if (expected_randomise != options.randomise)
582 {
583 throw std::runtime_error(fmt::format(
584 "Verification file is only applicable when randomisation is {}, "
585 "but this option is currently {}",
586 expected_randomise ? "ON" : "OFF",
587 options.randomise ? "ON" : "OFF"));
588 }
589 }
590 }
591 virtual void verify_initial_state(const nlohmann::json& expected) {}
592 virtual void verify_final_state(const nlohmann::json& expected) {}
593
594 public:
595 PerfBase(const TOptions& o) :
596 options(o),
598 // timing gets its own new connection for any requests it wants to send -
599 // these are never signed
601 {}
602
604 {
605 // Make sure the connection we're about to use has been initialised
606 if (!rpc_connection)
607 {
609 }
610 }
611
612 std::shared_ptr<RpcTlsClient> get_connection()
613 {
615 return rpc_connection;
616 }
617
619 {
620 if (!options.no_create)
621 {
622 try
623 {
624 const auto last_response = send_creation_transactions();
625
626 if (
627 last_response.has_value() &&
628 http::status_success(last_response->status))
629 {
630 // Ensure creation transactions are globally committed before
631 // proceeding
632 wait_for_global_commit(last_response.value());
633 }
634 }
635 catch (std::exception& e)
636 {
637 LOG_FAIL_FMT("Exception during creation steps: {}", e.what());
638 throw e;
639 }
640 }
641 }
642
644 {
646 try
647 {
649 }
650 catch (std::exception& e)
651 {
652 LOG_FAIL_FMT("Preparation exception: {}", e.what());
653 throw e;
654 }
655 }
656
658 {
660 try
661 {
662 // ...send any transactions which were previously prepared
664 }
665 catch (std::exception& e)
666 {
667 LOG_FAIL_FMT("Transaction exception: {}", e.what());
668 throw e;
669 }
670 }
671
673 {
675 }
676
678 {
679 check_response(response);
680
681 const auto tx_id = timing::extract_transaction_id(response);
682 if (!tx_id.has_value())
683 {
684 throw std::logic_error(
685 "Cannot wait for response to commit - it does not have a TxID");
686 }
687
688 wait_for_global_commit(tx_id.value());
689 }
690
692 {
694 {
695 throw std::logic_error(
696 "timing is already set - has begin_timing been called multiple "
697 "times?");
698 }
699
701 }
702
703 timing::Results end_timing(size_t end_highest_local_commit)
704 {
706 {
707 throw std::logic_error(
708 "timing is not set - has begin_timing not been called?");
709 }
710
711 timing::Results results;
712 try
713 {
715 options.no_wait, end_highest_local_commit, options.latency_rounds);
716 }
717 catch (const std::runtime_error& e)
718 {
720 throw;
721 }
722
723 if (options.write_tx_times)
724 {
726 }
727
729
730 return results;
731 }
732
733 void summarize_results(const timing::Results& timing_results)
734 {
735 using namespace std;
736 using namespace chrono;
737
738 // Write tx/s to std out
739 const auto total_txs = timing_results.total_sends;
740 const auto dur_ms =
741 duration_cast<milliseconds>(timing_results.duration).count();
742 const auto duration = dur_ms / 1000.0;
743 const auto tx_per_sec = total_txs / duration;
744
746 "{} transactions took {}ms.\n"
747 "=> {}tx/s\n", //< This is grepped for by _get_perf in Python
748 total_txs,
749 dur_ms,
750 tx_per_sec);
751
753 " Sends: {}\n"
754 " Receives: {}\n"
755 " All txs (local_commit): {}\n"
756 " Global commit: {}\n",
757 timing_results.total_sends,
758 timing_results.total_receives,
759 timing_results.total_local_commit,
760 timing_results.total_global_commit);
761
762 for (size_t round = 0; round < timing_results.per_round.size(); ++round)
763 {
764 const auto& round_info = timing_results.per_round[round];
765
767 " Round {} (req ids #{} to #{})\n"
768 " Local: {}\n"
769 " Global: {}\n",
770 round,
771 round_info.begin_rpc_id,
772 round_info.end_rpc_id,
773 round_info.local_commit,
774 round_info.global_commit);
775 }
776
777 // Write perf summary to csv
778 std::ofstream perf_summary_csv(
779 perf_summary, std::ofstream::out | std::ofstream::app);
780 if (perf_summary_csv.is_open())
781 {
782 // Total number of bytes sent is:
783 // sessions * sum-per-tx of tx-bytes)
784 const auto total_bytes =
785 options.session_count * total_byte_size(prepared_txs);
786
787 const auto [host, _] = ccf::split_net_address(options.server_address);
788
789 perf_summary_csv << duration_cast<milliseconds>(
790 timing_results.start_time.time_since_epoch())
791 .count(); // timeStamp
792 perf_summary_csv << "," << dur_ms; // elapsed
793 perf_summary_csv << ","
794 << (host.find("127.") == 0 ?
795 options.label :
796 options.label + string("_distributed")); // label
797 perf_summary_csv << "," << total_bytes; // bytes
798 perf_summary_csv << "," << options.thread_count; // allThreads
799 perf_summary_csv << "," << (double)dur_ms / total_txs; // latency
800 perf_summary_csv << "," << total_txs; // SampleCount
801
802 const auto& lc = timing_results.total_local_commit;
803 perf_summary_csv << "," << lc.average; // local_commit_latency
804 perf_summary_csv << "," << lc.sample_count; // local_commit_samples
805
806 const auto& gc = timing_results.total_global_commit;
807 perf_summary_csv << "," << gc.average; // global_commit_latency
808 perf_summary_csv << "," << gc.sample_count; // global_commit_samples
809
810 perf_summary_csv << endl;
811 }
812 }
813
814 virtual void run()
815 {
816 // Write PID to disk
817 files::dump(fmt::format("{}", ::getpid()), options.pid_file);
818
819 if (options.randomise)
820 {
821 options.generator_seed = std::random_device()();
822 }
823
825 "Random choices determined by seed: {}", options.generator_seed);
826 rand_generator.seed(options.generator_seed);
827
828 /*
829 const auto target_core = 0;
830 if (!pin_to_core(target_core))
831 {
832 LOG_FAIL_FMT("Failed to pin to core: {}", target_core);
833 }
834 */
835
836 const bool verifying = !options.verification_file.empty();
837
838 if (verifying)
839 {
840 verification_target = files::slurp_json(options.verification_file);
842 }
843
844 // Pre- and post- hooks allow derived classes to gather/log initial state
848
849 if (verifying)
850 {
852 }
853
855
857
859 "Sending {} transactions from {} clients {} times...",
860 options.num_transactions,
861 options.thread_count,
862 options.session_count);
863
864 auto timing_results = send_all_prepared_transactions();
865
866 LOG_INFO_FMT("Done");
867
869
870 if (verifying)
871 {
873 }
874
875 summarize_results(timing_results);
876 }
877
878 template <typename T>
880 {
881 std::uniform_int_distribution<T> dist;
882 return dist(rand_generator);
883 }
884
885 template <typename T>
886 T rand_range(T exclusive_upper_bound)
887 {
888 std::uniform_int_distribution<T> dist(0, exclusive_upper_bound - 1);
889 return dist(rand_generator);
890 }
891
892 template <typename T>
893 T rand_range(T inclusive_lower_bound, T exclusive_upper_bound)
894 {
895 std::uniform_int_distribution<T> dist(
896 inclusive_lower_bound, exclusive_upper_bound - 1);
897 return dist(rand_generator);
898 }
899 };
900}
Definition pem.h:18
Definition sha256_hash.h:16
std::string hex_str() const
Definition sha256_hash.cpp:61
Definition perf_client.h:198
void prepare_all_transactions()
Definition perf_client.h:643
timing::Results end_timing(size_t end_highest_local_commit)
Definition perf_client.h:703
virtual void prepare_transactions()=0
virtual void post_timing_body_hook()
Definition perf_client.h:385
virtual void post_creation_hook()
Definition perf_client.h:382
void write(const PreparedTx &tx, size_t &read, size_t &written, const std::shared_ptr< RpcTlsClient > &connection)
Definition perf_client.h:441
timing::ResponseTimes response_times
Definition perf_client.h:289
void kick_off_timing()
Definition perf_client.h:434
static size_t total_byte_size(const PreparedTxs &txs)
Definition perf_client.h:358
TOptions options
Definition perf_client.h:278
std::shared_ptr< RpcTlsClient > get_connection()
Definition perf_client.h:612
void add_prepared_ser_tx(const std::string &method, const std::span< const uint8_t > params, bool expects_commit, const std::optional< size_t > &index)
Definition perf_client.h:338
void wait_for_global_commit(const RpcTlsClient::Response &response)
Definition perf_client.h:677
virtual std::optional< RpcTlsClient::Response > send_creation_transactions()
Definition perf_client.h:370
virtual void run()
Definition perf_client.h:814
T rand_range(T exclusive_upper_bound)
Definition perf_client.h:886
timing::Results send_all_prepared_transactions()
Definition perf_client.h:657
virtual void pre_timing_body_hook()
Definition perf_client.h:384
std::vector< PreparedTx > PreparedTxs
Definition perf_client.h:284
void wait_for_global_commit(const ccf::TxID &target)
Definition perf_client.h:672
std::chrono::nanoseconds write_delay_ns
Definition perf_client.h:293
std::shared_ptr< RpcTlsClient > create_connection(bool force_unsigned=false)
Definition perf_client.h:295
virtual timing::Results call_raw_batch(std::shared_ptr< RpcTlsClient > &connection, const PreparedTxs &txs)
Definition perf_client.h:387
ccf::TxID last_response_tx_id
Definition perf_client.h:290
void summarize_results(const timing::Results &timing_results)
Definition perf_client.h:733
PreparedTxs prepared_txs
Definition perf_client.h:287
T rand_range()
Definition perf_client.h:879
std::shared_ptr< RpcTlsClient > rpc_connection
Definition perf_client.h:286
void begin_timing()
Definition perf_client.h:691
void reconnect(std::shared_ptr< RpcTlsClient > &connection)
Definition perf_client.h:503
virtual void verify_params(const nlohmann::json &expected)
Definition perf_client.h:518
virtual bool check_response(const RpcTlsClient::Response &r)
Definition perf_client.h:375
RpcTlsClient::Response get_tx_status(const std::shared_ptr< RpcTlsClient > &connection, size_t view, size_t seqno)
Definition perf_client.h:508
virtual void verify_final_state(const nlohmann::json &expected)
Definition perf_client.h:592
void blocking_read(size_t &read, size_t written, const std::shared_ptr< RpcTlsClient > &connection)
Definition perf_client.h:490
PerfBase(const TOptions &o)
Definition perf_client.h:595
std::chrono::high_resolution_clock::time_point last_write_time
Definition perf_client.h:292
virtual void pre_creation_hook()
Definition perf_client.h:381
T rand_range(T inclusive_lower_bound, T exclusive_upper_bound)
Definition perf_client.h:893
std::mt19937 rand_generator
Definition perf_client.h:280
virtual void verify_initial_state(const nlohmann::json &expected)
Definition perf_client.h:591
void send_all_creation_transactions()
Definition perf_client.h:618
void init_connection()
Definition perf_client.h:603
nlohmann::json verification_target
Definition perf_client.h:282
Definition timing.h:167
void stop_timing()
Definition timing.h:195
void write_to_file(const string &filename)
Definition timing.h:540
void start_timing()
Definition timing.h:184
void record_receive(size_t rpc_id, const optional< ccf::TxID > &tx_id, size_t global_seqno=0)
Definition timing.h:212
bool is_timing_active()
Definition timing.h:190
Results produce_results(bool allow_pending, size_t highest_local_commit, size_t desired_rounds=1)
Definition timing.h:308
void record_send(const std::string &method, size_t rpc_id, bool expects_commit)
Definition timing.h:205
void wait_for_global_commit(const ccf::TxID &target, bool record=true)
Definition timing.h:223
#define LOG_INFO_FMT
Definition logger.h:395
#define LOG_TRACE_FMT
Definition logger.h:378
#define LOG_DEBUG_FMT
Definition logger.h:380
#define LOG_FATAL_FMT
Definition logger.h:397
#define LOG_FAIL_FMT
Definition logger.h:396
std::vector< uint8_t > cert_pem_to_der(const Pem &pem)
Definition verifier.cpp:38
ccf::NodeInfoNetwork::NetAddress ParsedAddress
Definition cli_helper.h:18
Definition perf_client.h:26
bool pin_to_core(int core_id)
Definition perf_client.h:29
HttpRpcTlsClient RpcTlsClient
Definition rpc_tls_client.h:248
constexpr auto perf_summary
Definition perf_client.h:27
std::vector< uint8_t > slurp(const std::string &file, bool optional=false)
Tries to read a file as byte vector.
Definition files.h:43
void dump(const std::vector< uint8_t > &data, const std::string &file)
Writes the content of a vector to a file.
Definition files.h:121
std::string slurp_string(const std::string &file, bool optional=false)
Tries to read a file as string.
Definition files.h:82
nlohmann::json slurp_json(const std::string &file, bool optional=false)
Tries to read a file as JSON.
Definition files.h:106
Definition configuration.h:13
bool status_success(http_status status)
Definition http_parser.h:71
STL namespace.
Definition tx_id.h:44
SeqNo seqno
Definition tx_id.h:46
View view
Definition tx_id.h:45
Definition rpc_tls_client.h:23
size_t id
Definition rpc_tls_client.h:25
std::vector< uint8_t > encoded
Definition rpc_tls_client.h:24
Definition rpc_tls_client.h:29
size_t id
Definition rpc_tls_client.h:30
http_status status
Definition rpc_tls_client.h:31
Definition perf_client.h:201
std::string method
Definition perf_client.h:203
bool expects_commit
Definition perf_client.h:204
RpcTlsClient::PreparedRpc rpc
Definition perf_client.h:202
Definition perf_client.h:55
bool sign
Definition perf_client.h:72
size_t latency_rounds
Definition perf_client.h:68
size_t generator_seed
Definition perf_client.h:69
std::string label
Definition perf_client.h:58
cli::ParsedAddress server_address
Definition perf_client.h:61
std::string pid_file
Definition perf_client.h:59
PerfOptions(const std::string &default_label, const std::string &default_pid_file, CLI::App &app)
Definition perf_client.h:81
size_t max_writes_ahead
Definition perf_client.h:67
std::string key_file
Definition perf_client.h:62
bool relax_commit_target
Definition perf_client.h:78
size_t thread_count
Definition perf_client.h:65
size_t num_transactions
Definition perf_client.h:64
bool check_responses
Definition perf_client.h:77
size_t transactions_per_s
Definition perf_client.h:70
bool no_create
Definition perf_client.h:73
size_t session_count
Definition perf_client.h:66
std::string cert_file
Definition perf_client.h:62
std::string ca_file
Definition perf_client.h:62
bool write_tx_times
Definition perf_client.h:75
std::string verification_file
Definition perf_client.h:62
std::string bearer_token
Definition perf_client.h:62
bool randomise
Definition perf_client.h:76
bool no_wait
Definition perf_client.h:74
double average
Definition timing.h:24
Definition timing.h:132
size_t total_sends
Definition timing.h:133
Measure total_global_commit
Definition timing.h:139
Clock::time_point start_time
Definition timing.h:135
Measure total_local_commit
Definition timing.h:138
TimeDelta duration
Definition timing.h:136
size_t total_receives
Definition timing.h:134
vector< PerRound > per_round
Definition timing.h:150