13 #include "hebench/modules/timer/include/timer.h"
16 #include "hebench/modules/general/include/hebench_math_utils.h"
19 #include "../include/hebench_benchmark_latency.h"
22 namespace TestHarness {
44 std::cout << std::endl
45 <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Starting test...") << std::endl;
48 hebench::Common::EventTimer<true> timer;
50 std::string event_name;
51 hebench::Common::TimingReportEvent::Ptr p_timing_event;
56 constexpr std::uint64_t LatencySampleSize = 1;
71 std::vector<hebench::APIBridge::DataPack> param_packs(p_dataset->getParameterCount());
72 for (std::size_t param_i = 0; param_i < param_packs.size(); ++param_i)
74 assert(p_dataset->getParameterData(param_i).param_position == param_i);
75 param_packs[param_i].p_buffers = p_dataset->getParameterData(param_i).p_buffers;
76 param_packs[param_i].buffer_count = LatencySampleSize;
77 param_packs[param_i].param_position = param_i;
80 if (param_packs[param_i].buffer_count > 0
81 && !param_packs[param_i].p_buffers)
82 throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Invalid empty DataPack in IDataLoader `p_dataset` for parameter " +
std::to_string(param_i) +
"."));
86 for (std::uint64_t result_i = 0; result_i < p_dataset->getResultCount(); ++result_i)
89 if (p_dataset->getResultData(result_i).buffer_count < LatencySampleSize)
92 ss <<
"Invalid number of result samples for result component " << result_i <<
". "
93 <<
"Expected " << LatencySampleSize <<
", but " << p_dataset->getResultData(result_i).buffer_count <<
" received.";
94 throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
97 if (!p_dataset->getResultData(result_i).p_buffers)
100 ss <<
"Invalid null DataPack buffer in IDataLoader `p_dataset` for result component " << result_i <<
".";
101 throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
112 std::vector<hebench::APIBridge::DataPackCollection> packed_parameters(2);
113 std::vector<std::vector<hebench::APIBridge::DataPack>> packed_parameters_data_packs(packed_parameters.size());
115 for (std::size_t i = 0; i < param_packs.size(); ++i)
118 if (cipher_param_mask.test(i))
119 packed_parameters_data_packs.front().push_back(param_packs[i]);
121 packed_parameters_data_packs.back().push_back(param_packs[i]);
126 for (std::size_t i = 0; i < packed_parameters.size(); ++i)
128 if (!packed_parameters_data_packs[i].empty())
130 packed_parameters[i].p_data_packs = packed_parameters_data_packs[i].data();
131 packed_parameters[i].pack_count = packed_parameters_data_packs[i].size();
140 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Encoding.") << std::endl;
142 std::vector<RAIIHandle> h_inputs(packed_parameters.size());
143 for (std::size_t i = 0; i < packed_parameters.size(); ++i)
146 if (packed_parameters[i].pack_count > 0)
149 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(event_name +
"...") << std::endl;
156 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Pack " +
std::to_string(i) +
" is empty (skipping).") << std::endl;
164 event_name =
"Encryption";
169 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Encryption.") << std::endl;
171 if (packed_parameters[0].pack_count > 0)
173 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Encrypting...") << std::endl;
183 h_inputs.front() = encrypted_input;
188 std::cout <<
IOS_MSG_WARNING << hebench::Logging::GlobalLogger::log(
"No encrypted parameters requested (skipping).") << std::endl;
193 event_name =
"Loading";
201 std::vector<hebench::APIBridge::Handle> h_inputs_local;
202 for (std::size_t i = 0; i < packed_parameters.size(); ++i)
204 if (packed_parameters[i].pack_count > 0)
205 h_inputs_local.push_back(h_inputs[i].
handle);
210 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Loading data to remote backend...") << std::endl;
212 RAIIHandle h_inputs_remote;
215 h_inputs_local.data(), h_inputs_local.
size(),
216 &h_inputs_remote.handle));
227 h_inputs_local.clear();
229 packed_parameters.clear();
230 packed_parameters_data_packs.clear();
242 std::vector<hebench::APIBridge::ParameterIndexer> params(p_dataset->getParameterCount());
243 for (std::size_t i = 0; i < params.size(); ++i)
245 params[i].batch_size = LatencySampleSize;
246 params[i].value_index = 0;
252 event_name =
"Warmup";
260 if (warmup_terations_count > 0)
263 << hebench::Logging::GlobalLogger::log(
"Starting warm-up iterations: requested "
268 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Warming up...") << std::endl;
271 for (std::uint64_t rep_i = 0; rep_i < warmup_terations_count; ++rep_i)
273 RAIIHandle h_result_remote;
276 h_inputs_remote.handle,
277 params.data(), params.
size(),
278 &h_result_remote.handle));
288 << hebench::Logging::GlobalLogger::log(
"No warm-up requested (skipping).")
292 std::uint64_t min_test_time_ms =
297 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Starting latency test.") << std::endl
299 << std::string(
sizeof(
IOS_MSG_INFO) + 1,
' ') << hebench::Logging::GlobalLogger::log(
"Actual time: " +
std::to_string(min_test_time_ms) +
" ms") << std::endl;
301 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Testing...") << std::endl;
304 event_name =
"Operation";
309 std::vector<RAIIHandle> h_remote_results;
310 h_remote_results.reserve(20);
312 std::uint64_t op_count = 0;
313 double elapsed_ms = 0.0;
314 while (op_count < 2 || elapsed_ms < min_test_time_ms)
319 h_inputs_remote.handle,
320 params.data(), params.
size(),
323 elapsed_ms += p_timing_event->elapsedWallTime<std::milli>();
325 if (h_remote_results.capacity() == h_remote_results.size()
330 std::size_t tmp_multiplier =
static_cast<std::size_t
>(min_test_time_ms / elapsed_ms);
331 std::size_t max_capacity = h_remote_results.capacity()
332 * (tmp_multiplier + (tmp_multiplier > 0 ? 1 : 2));
334 + (max_capacity - h_remote_results.capacity()));
335 h_remote_results.reserve(max_capacity);
338 h_remote_results.emplace_back(h_result_remote);
349 h_inputs_remote.destroy();
358 event_name =
"Store";
360 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Retrieving data from remote backend...") << std::endl;
362 std::vector<RAIIHandle> h_cipher_results(h_remote_results.size());
363 for (std::size_t i = 0; i < h_remote_results.size(); ++i)
371 h_remote_results[i].
handle,
372 &h_cipher_results[i].
handle,
382 h_remote_results[i].destroy();
384 h_remote_results.clear();
391 event_name =
"Decryption";
393 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Decrypting results...") << std::endl;
395 std::vector<RAIIHandle> h_plain_results(h_cipher_results.size());
396 for (std::size_t i = 0; i < h_cipher_results.size(); ++i)
411 h_cipher_results[i].destroy();
413 h_cipher_results.clear();
429 std::vector<std::uint8_t> raw_result_buffer;
430 std::uint64_t max_raw_result_size = 0;
431 for (std::uint64_t result_pos = 0; result_pos < p_dataset->getResultCount(); ++result_pos)
433 if (p_dataset->getResultData(result_pos).buffer_count <= 0
434 || !p_dataset->getResultData(result_pos).p_buffers)
435 throw std::logic_error(IL_LOG_MSG_CLASS(
"Invalid empty NativeDataBuffer in IDataLoader `p_dataset` at result " +
std::to_string(result_pos) +
"."));
436 max_raw_result_size += p_dataset->getResultData(result_pos).p_buffers[0].size;
438 raw_result_buffer.resize(max_raw_result_size);
442 std::vector<hebench::APIBridge::NativeDataBuffer> raw_results(p_dataset->getResultCount(),
444 std::uint64_t offset_p = 0;
445 for (std::uint64_t result_pos = 0; result_pos < p_dataset->getResultCount(); ++result_pos)
447 if (p_dataset->getResultData(result_pos).buffer_count > 0)
449 raw_results[result_pos].p = raw_result_buffer.data() + offset_p;
450 raw_results[result_pos].size = p_dataset->getResultData(result_pos).p_buffers[0].size;
451 raw_results[result_pos].tag = 0;
453 offset_p += raw_results[result_pos].size;
462 std::vector<hebench::APIBridge::DataPack> results_pack(p_dataset->getResultCount());
463 for (std::size_t result_pos = 0; result_pos < results_pack.size(); ++result_pos)
465 results_pack[result_pos].p_buffers = &raw_results[result_pos];
466 results_pack[result_pos].buffer_count = 1;
467 results_pack[result_pos].param_position = result_pos;
476 packed_results.
pack_count = results_pack.size();
481 event_name =
"Decoding";
484 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Decoding and Validation.") << std::endl;
486 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Decoding...") << std::endl;
488 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Result",
false);
490 std::size_t mini_reports_cnt = 3;
491 std::size_t report_every_n_elements = h_plain_results.size() / 7 + 1;
492 if (report_every_n_elements <= 0)
493 report_every_n_elements = 1;
494 std::size_t report_every_n_by_3_elements = report_every_n_elements / 4;
495 if (report_every_n_by_3_elements <= 0)
496 report_every_n_by_3_elements = 1;
497 std::size_t progress_report_batch = 0;
500 for (std::size_t i = 0; i < h_plain_results.size(); ++i)
502 const auto &h_plain = h_plain_results[i].handle;
505 if (i == 0 || (i + 1) % report_every_n_elements == 0)
508 while (mini_reports_cnt++ < 3)
509 std::cout << hebench::Logging::GlobalLogger::log(
".",
false) << std::flush;
510 mini_reports_cnt = 0;
511 progress_report_batch = 0;
512 std::cout << hebench::Logging::GlobalLogger::log(
" " +
std::to_string(i + 1),
false) << std::flush;
524 if (mini_reports_cnt < 3
525 && progress_report_batch > 0
526 && progress_report_batch % report_every_n_by_3_elements == 0)
530 std::cout << hebench::Logging::GlobalLogger::log(
".",
false) << std::flush;
536 std::string s_error_msg;
537 std::vector<std::uint64_t> data_pack_indices;
538 std::vector<hebench::APIBridge::NativeDataBuffer *> outputs;
541 outputs.resize(p_dataset->getResultCount());
542 for (std::uint64_t i = 0; i < packed_results.
pack_count; ++i)
545 throw std::runtime_error(
"Invalid result position received from decoding.");
547 throw std::runtime_error(
"Invalid empty result buffers received from decoding.");
552 data_pack_indices.resize(p_dataset->getParameterCount(), 0);
555 this->getBackendDescription().descriptor.data_type);
557 catch (std::exception &ex)
560 s_error_msg = ex.what();
569 std::cout << hebench::Logging::GlobalLogger::log(
"",
true) << std::endl;
570 ss = std::stringstream();
571 ss <<
"Validation failed" << std::endl
572 <<
"Result, " << i + 1 << std::endl;
573 if (!s_error_msg.empty())
574 ss << s_error_msg << std::endl;
575 std::cout <<
IOS_MSG_FAILED << hebench::Logging::GlobalLogger::log(ss.str()) << std::endl;
579 logResult(ss, p_dataset, data_pack_indices.data(),
581 this->getBackendDescription().descriptor.data_type);
586 ++progress_report_batch;
593 h_plain_results[i].destroy();
595 h_plain_results.clear();
600 if ((op_count) % report_every_n_elements != 0)
603 while (mini_reports_cnt++ < 3)
604 std::cout << hebench::Logging::GlobalLogger::log(
".",
false) << std::flush;
605 std::cout << hebench::Logging::GlobalLogger::log(
" " +
std::to_string(op_count)) << std::endl;
608 std::cout << hebench::Logging::GlobalLogger::log(
"") << std::endl;
615 std::cout <<
IOS_MSG_WARNING << hebench::Logging::GlobalLogger::log(
"Validation skipped.") << std::endl;
618 std::cout <<
IOS_MSG_DONE << hebench::Logging::GlobalLogger::log(
"Test Completed.") << std::endl;
void prependFooter(const std::string &new_header, bool new_line=true)
void setEventCapacity(uint64_t new_capacity)
uint64_t getEventCapacity() const
void addEventType(uint32_t event_type_id, const std::string &event_type_header, bool is_main_event=false)
Adds a new event type to the types of events.
void appendFooter(const std::string &new_header, bool new_line=true)
const hebench::APIBridge::BenchmarkDescriptor & descriptor
Benchmark backend descriptor, as retrieved by backend, corresponding to the registration handle h_des...
std::uint64_t default_min_test_time_ms
Default minimum test time in milliseconds.
~BenchmarkLatency() override
BenchmarkLatency(std::shared_ptr< Engine > p_engine, const IBenchmarkDescriptor::DescriptionToken &description_token)
bool run(hebench::Utilities::TimingReportEx &out_report, IBenchmark::RunConfig &config) override
Executes the benchmark latency test.
Token returned by a successful call to IBenchmarkDescriptor::matchBenchmarkDescriptor().
bool b_validate_results
Specifies whether the benchmark will validate backend results (true) or it will simply benchmark with...
Provides configuration to and retrieves data from a benchmark run.
std::shared_ptr< IDataLoader > Ptr
virtual IDataLoader::Ptr getDataset() const =0
Dataset to be used for operations previously initialized during creation of this object.
virtual bool validateResult(IDataLoader::Ptr dataset, const std::uint64_t *param_data_pack_indices, const std::vector< hebench::APIBridge::NativeDataBuffer * > &outputs, hebench::APIBridge::DataType data_type) const
Validates the result of an operation against the ground truth.
virtual void logResult(std::ostream &os, IDataLoader::Ptr dataset, const std::uint64_t *param_data_pack_indices, const std::vector< hebench::APIBridge::NativeDataBuffer * > &outputs, hebench::APIBridge::DataType data_type) const
Outputs the arguments, expected ground truth, and received result to an output stream.
const BenchmarkDescription::Backend & getBackendDescription() const
Allows read-only access to this benchmark backend description.
const BenchmarkDescription::Configuration & getBenchmarkConfiguration() const
Allows read-only access to this benchmark configuration.
const hebench::APIBridge::Handle & handle() const override
std::uint32_t getEventIDNext()
Returns the next available event ID.
void validateRetCode(hebench::APIBridge::ErrorCode err_code, bool last_error=true) const
Validates whether the specified HEBench API return code represents a success or error.
void addEvent(hebench::Common::TimingReportEvent::Ptr p_event)
ErrorCode encrypt(Handle h_benchmark, Handle h_plaintext, Handle *h_ciphertext)
Encrypts a plain text into a cipher text.
ErrorCode operate(Handle h_benchmark, Handle h_remote_packed_params, const ParameterIndexer *p_param_indexers, uint64_t indexers_count, Handle *h_remote_output)
Performs the workload operation of the benchmark.
DataPack * p_data_packs
Collection of data packs.
ErrorCode encode(Handle h_benchmark, const DataPackCollection *p_parameters, Handle *h_plaintext)
Given a pack of parameters in raw, native data format, encodes them into plain text suitable for back...
std::uint64_t min_test_time_ms
Specifies the minimum time, in milliseconds, to run the test.
ErrorCode decrypt(Handle h_benchmark, Handle h_ciphertext, Handle *h_plaintext)
Decrypts a cipher text into corresponding plain text.
std::uint32_t cipher_param_mask
Input mask to define which operation parameters for the computation are plain text or cipher text.
ErrorCode store(Handle h_benchmark, Handle h_remote, Handle *h_local_packed_params, std::uint64_t local_count)
Retrieves the specified data from the backend.
CategoryParams cat_params
Parameters for the category.
std::uint64_t pack_count
Number of data packs in the collection.
std::uint64_t size
Size of underlying data.
std::uint64_t param_position
The 0-based position of this parameter in the corresponding function call.
ErrorCode load(Handle h_benchmark, const Handle *h_local_packed_params, std::uint64_t local_count, Handle *h_remote)
Loads the specified data from the local host into the remote backend to use as parameter during a cal...
std::uint64_t buffer_count
Number of data buffers in p_buffers.
ErrorCode decode(Handle h_benchmark, Handle h_plaintext, DataPackCollection *p_native)
Decodes plaintext data into the appropriate raw, native format.
NativeDataBuffer * p_buffers
Array of data buffers for parameter.
Defines a collection of data packs.
Structure to contain flexible data.
std::string to_string(const std::string_view &s)
std::micro DefaultTimeInterval