13 #include "hebench/modules/timer/include/timer.h"
16 #include "hebench/modules/general/include/hebench_math_utils.h"
19 #include "../include/hebench_benchmark_offline.h"
22 namespace TestHarness {
43 std::cout << std::endl
44 <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Starting test...") << std::endl;
47 hebench::Common::EventTimer<true> timer;
49 std::string event_name;
50 hebench::Common::TimingReportEvent::Ptr p_timing_event;
65 std::vector<hebench::APIBridge::DataPack> param_packs(p_dataset->getParameterCount());
66 std::uint64_t num_results_samples = 1;
67 for (std::size_t param_i = 0; param_i < param_packs.size(); ++param_i)
69 assert(p_dataset->getParameterData(param_i).param_position == param_i);
70 param_packs[param_i].p_buffers = p_dataset->getParameterData(param_i).p_buffers;
71 param_packs[param_i].buffer_count = p_dataset->getParameterData(param_i).buffer_count;
72 param_packs[param_i].param_position = param_i;
75 if (param_packs[param_i].buffer_count > 0
76 && !param_packs[param_i].p_buffers)
77 throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Invalid empty DataPack in IDataLoader `p_dataset` for parameter " +
std::to_string(param_i) +
"."));
79 num_results_samples *= param_packs[param_i].buffer_count;
83 for (std::uint64_t result_i = 0; result_i < p_dataset->getResultCount(); ++result_i)
86 if (p_dataset->getResultData(result_i).buffer_count < num_results_samples)
89 ss <<
"Invalid number of result samples for result component " << result_i <<
". "
90 <<
"Expected " << num_results_samples <<
", but " << p_dataset->getResultData(result_i).buffer_count <<
" received.";
91 throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
94 if (!p_dataset->getResultData(result_i).p_buffers)
97 ss <<
"Invalid null DataPack buffer in IDataLoader `p_dataset` for result component " << result_i <<
".";
98 throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
109 std::vector<hebench::APIBridge::DataPackCollection> packed_parameters(2);
110 std::vector<std::vector<hebench::APIBridge::DataPack>> packed_parameters_data_packs(packed_parameters.size());
112 for (std::size_t i = 0; i < param_packs.size(); ++i)
115 if (cipher_param_mask.test(i))
116 packed_parameters_data_packs.front().push_back(param_packs[i]);
118 packed_parameters_data_packs.back().push_back(param_packs[i]);
123 for (std::size_t i = 0; i < packed_parameters.size(); ++i)
125 if (!packed_parameters_data_packs[i].empty())
127 packed_parameters[i].p_data_packs = packed_parameters_data_packs[i].data();
128 packed_parameters[i].pack_count = packed_parameters_data_packs[i].size();
137 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Encoding.") << std::endl;
139 std::vector<RAIIHandle> h_inputs(packed_parameters.size());
140 for (std::size_t i = 0; i < packed_parameters.size(); ++i)
143 if (packed_parameters[i].pack_count > 0)
146 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(event_name +
"...") << std::endl;
153 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Pack " +
std::to_string(i) +
" is empty (skipping).") << std::endl;
161 event_name =
"Encryption";
166 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Encryption.") << std::endl;
168 if (packed_parameters[0].pack_count > 0)
170 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Encrypting...") << std::endl;
180 h_inputs.front() = encrypted_input;
185 std::cout <<
IOS_MSG_WARNING << hebench::Logging::GlobalLogger::log(
"No encrypted parameters requested (skipping).") << std::endl;
190 event_name =
"Loading";
198 std::vector<hebench::APIBridge::Handle> h_inputs_local;
199 for (std::size_t i = 0; i < packed_parameters.size(); ++i)
201 if (packed_parameters[i].pack_count > 0)
202 h_inputs_local.push_back(h_inputs[i].
handle);
207 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Loading data to remote backend...") << std::endl;
209 RAIIHandle h_inputs_remote;
212 h_inputs_local.data(), h_inputs_local.
size(),
213 &h_inputs_remote.handle));
224 h_inputs_local.clear();
226 packed_parameters.clear();
227 packed_parameters_data_packs.clear();
239 std::vector<hebench::APIBridge::ParameterIndexer> params(p_dataset->getParameterCount());
241 for (std::size_t i = 0; i < params.size(); ++i)
243 params[i].batch_size = p_dataset->getParameterData(i).buffer_count;
244 params[i].value_index = 0;
249 std::uint64_t min_test_time_ms =
254 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Starting offline test.") << std::endl
256 << std::string(
sizeof(
IOS_MSG_INFO) + 1,
' ') << hebench::Logging::GlobalLogger::log(
"Actual time: " +
std::to_string(min_test_time_ms) +
" ms") << std::endl;
258 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Testing...") << std::endl;
261 event_name =
"Operation";
268 RAIIHandle h_remote_results;
269 std::size_t iteration_count = 0;
270 std::size_t iteration_capacity = 20;
271 double elapsed_ms = 0.0;
273 while (iteration_count <= 0 || elapsed_ms < min_test_time_ms)
275 if (iteration_count > 0)
277 h_remote_results.destroy();
280 h_inputs_remote.handle,
281 params.data(), params.
size(),
282 &h_remote_results.handle));
284 elapsed_ms += p_timing_event->elapsedWallTime<std::milli>();
287 if (iteration_capacity == iteration_count
292 std::size_t tmp_multiplier =
static_cast<std::size_t
>(min_test_time_ms / elapsed_ms);
293 std::size_t max_capacity = iteration_capacity
294 * (tmp_multiplier + (tmp_multiplier > 0 ? 1 : 2));
296 + (max_capacity - iteration_capacity));
297 iteration_capacity = max_capacity;
304 ss = std::stringstream();
305 ss <<
"Elapsed time: " << p_timing_event->elapsedWallTime<std::milli>() <<
"ms";
306 std::cout <<
IOS_MSG_DONE << hebench::Logging::GlobalLogger::log(ss.str()) << std::endl;
312 h_inputs_remote.destroy();
321 event_name =
"Store";
323 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Retrieving data from remote backend...") << std::endl;
325 RAIIHandle h_cipher_results;
332 h_remote_results.handle,
333 &h_cipher_results.handle,
343 h_remote_results.destroy();
350 event_name =
"Decryption";
352 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Decrypting results...") << std::endl;
354 RAIIHandle h_plain_results;
368 h_cipher_results.destroy();
384 std::vector<std::uint8_t> raw_result_buffer;
385 std::uint64_t max_raw_result_size = 0;
387 for (std::uint64_t result_component_i = 0; result_component_i < p_dataset->getResultCount(); ++result_component_i)
390 for (std::uint64_t result_sample = 0; result_sample < result_component.
buffer_count; ++result_sample)
391 max_raw_result_size += result_component.
p_buffers[result_sample].
size;
393 raw_result_buffer.resize(max_raw_result_size);
397 std::vector<std::vector<hebench::APIBridge::NativeDataBuffer>> raw_results(p_dataset->getResultCount());
398 std::uint64_t offset_p = 0;
399 for (std::uint64_t result_component_i = 0; result_component_i < raw_results.size(); ++result_component_i)
405 for (std::uint64_t result_sample = 0; result_sample < result_component.
buffer_count; ++result_sample)
407 assert(offset_p < raw_result_buffer.size());
408 raw_results[result_component_i][result_sample].p = raw_result_buffer.data() + offset_p;
409 raw_results[result_component_i][result_sample].size = result_component.
p_buffers[result_sample].
size;
410 raw_results[result_component_i][result_sample].tag = 0;
412 offset_p += raw_results[result_component_i][result_sample].size;
422 std::vector<hebench::APIBridge::DataPack> results_packs(raw_results.size());
423 for (std::uint64_t result_component_i = 0; result_component_i < results_packs.size(); ++result_component_i)
425 results_packs[result_component_i].p_buffers = raw_results[result_component_i].data();
426 results_packs[result_component_i].buffer_count = raw_results[result_component_i].size();
427 results_packs[result_component_i].param_position = result_component_i;
436 packed_results.
pack_count = results_packs.size();
441 event_name =
"Decoding";
443 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Decoding...") << std::endl;
456 h_plain_results.destroy();
464 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Validation.") << std::endl;
466 std::cout <<
IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(
"Result",
false);
468 std::size_t mini_reports_cnt = 3;
469 std::size_t report_every_n_elements = num_results_samples / 7 + 1;
470 if (report_every_n_elements <= 0)
471 report_every_n_elements = 1;
472 std::size_t report_every_n_by_3_elements = report_every_n_elements / 4;
473 if (report_every_n_by_3_elements <= 0)
474 report_every_n_by_3_elements = 1;
475 std::size_t progress_report_batch = 0;
478 std::vector<std::size_t> params_count(p_dataset->getParameterCount());
479 for (std::uint64_t param_i = 0; param_i < p_dataset->getParameterCount(); ++param_i)
484 params_count[params_count.size() - param_i - 1] = p_dataset->getParameterData(param_i).buffer_count;
487 hebench::Utilities::Math::ComponentCounter param_counter(params_count);
488 std::size_t result_i = 0;
492 assert(result_i < num_results_samples);
494 if (result_i == 0 || (result_i + 1) % report_every_n_elements == 0)
497 while (mini_reports_cnt++ < 3)
498 std::cout << hebench::Logging::GlobalLogger::log(
".",
false) << std::flush;
499 mini_reports_cnt = 0;
500 progress_report_batch = 0;
501 std::cout << hebench::Logging::GlobalLogger::log(
" " +
std::to_string(result_i + 1),
false) << std::flush;
504 if (mini_reports_cnt < 3
505 && progress_report_batch > 0
506 && progress_report_batch % report_every_n_by_3_elements == 0)
510 std::cout << hebench::Logging::GlobalLogger::log(
".",
false) << std::flush;
514 std::string s_error_msg;
515 std::vector<hebench::APIBridge::NativeDataBuffer *> outputs;
516 std::vector<std::uint64_t> data_pack_indices;
519 outputs.resize(p_dataset->getResultCount());
520 assert(packed_results.
pack_count >= outputs.size());
521 for (std::uint64_t result_component_i = 0; result_component_i < outputs.size(); ++result_component_i)
527 outputs[result_component_i] =
534 const auto &tmp = param_counter.getCount();
535 data_pack_indices.assign(tmp.rbegin(), tmp.rend());
536 assert(data_pack_indices.size() == p_dataset->getParameterCount());
540 this->getBackendDescription().descriptor.data_type);
542 catch (std::exception &ex)
545 s_error_msg = ex.what();
554 std::cout << hebench::Logging::GlobalLogger::log(
"",
true) << std::endl;
555 ss = std::stringstream();
556 ss <<
"Validation failed" << std::endl
557 <<
"Result, " << result_i + 1 << std::endl;
558 if (!s_error_msg.empty())
559 ss << s_error_msg << std::endl;
560 std::cout <<
IOS_MSG_FAILED << hebench::Logging::GlobalLogger::log(ss.str()) << std::endl;
564 logResult(ss, p_dataset, data_pack_indices.data(),
566 this->getBackendDescription().descriptor.data_type);
570 ++progress_report_batch;
572 }
while (b_valid && !param_counter.inc());
577 if ((num_results_samples) % report_every_n_elements != 0)
580 while (mini_reports_cnt++ < 3)
581 std::cout << hebench::Logging::GlobalLogger::log(
".",
false) << std::flush;
582 std::cout << hebench::Logging::GlobalLogger::log(
" " +
std::to_string(num_results_samples)) << std::endl;
585 std::cout << hebench::Logging::GlobalLogger::log(
"") << std::endl;
592 std::cout <<
IOS_MSG_WARNING << hebench::Logging::GlobalLogger::log(
"Validation skipped.") << std::endl;
595 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.
bool run(hebench::Utilities::TimingReportEx &out_report, IBenchmark::RunConfig &config) override
Executes the benchmark offline test.
~BenchmarkOffline() override
BenchmarkOffline(std::shared_ptr< Engine > p_engine, const IBenchmarkDescriptor::DescriptionToken &description_token)
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 data package for an operation.
Defines a collection of data packs.
Structure to contain flexible data.
std::string to_string(const std::string_view &s)
std::micro DefaultTimeInterval