HEBench
hebench_benchmark_offline.cpp
Go to the documentation of this file.
1 
2 // Copyright (C) 2021 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include <algorithm>
6 #include <bitset>
7 #include <cassert>
8 #include <cstring>
9 #include <filesystem>
10 #include <iostream>
11 #include <stdexcept>
12 
13 #include "hebench/modules/timer/include/timer.h"
14 
15 #include "hebench/api_bridge/api.h"
16 #include "hebench/modules/general/include/hebench_math_utils.h"
17 #include "include/hebench_engine.h"
18 
19 #include "../include/hebench_benchmark_offline.h"
20 
21 namespace hebench {
22 namespace TestHarness {
23 
24 BenchmarkOffline::BenchmarkOffline(std::shared_ptr<Engine> p_engine,
25  const IBenchmarkDescriptor::DescriptionToken &description_token) :
26  PartialBenchmarkCategory(p_engine, description_token)
27 {
28 }
29 
31 {
32 }
33 
35 {
36  return run(out_report, getDataset(), config);
37 }
38 
40  IDataLoader::Ptr p_dataset,
41  IBenchmark::RunConfig &run_config)
42 {
43  std::cout << std::endl
44  << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Starting test...") << std::endl;
45 
46  std::stringstream ss;
47  hebench::Common::EventTimer<true> timer; // high precision
48  std::uint32_t event_id = getEventIDNext();
49  std::string event_name;
50  hebench::Common::TimingReportEvent::Ptr p_timing_event;
51 
52  // prepare the parameters for encoding
53 
54  // constexpr int op_params_count = 2; // operation has 2 parameters
55 
56  // DataPack param_packs[op_params_count];
57  // param_packs[0].p_buffers = p_raw_inputs_A;
58  // param_packs[0].buffer_count = A_count;
59  // param_packs[0].param_position = 0; // A is the first parameter, so, position 0
60  // param_packs[1].p_buffers = p_raw_inputs_B;
61  // param_packs[1].buffer_count = B_count;
62  // param_packs[1].param_position = 1; // B is the second parameter, so, position 1
63 
64  // create the data packs
65  std::vector<hebench::APIBridge::DataPack> param_packs(p_dataset->getParameterCount());
66  std::uint64_t num_results_samples = 1; // used to count the number of expected results
67  for (std::size_t param_i = 0; param_i < param_packs.size(); ++param_i)
68  {
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;
73 
74  // validate param pack
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) + "."));
78 
79  num_results_samples *= param_packs[param_i].buffer_count; // count the number of results
80  } // end for
81 
82  // validate ground truths
83  for (std::uint64_t result_i = 0; result_i < p_dataset->getResultCount(); ++result_i)
84  {
85  // make sure we have enough results in the dataset
86  if (p_dataset->getResultData(result_i).buffer_count < num_results_samples)
87  {
88  std::stringstream ss;
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()));
92  } // end if
93  // make sure the results are not null
94  if (!p_dataset->getResultData(result_i).p_buffers)
95  {
96  std::stringstream ss;
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()));
99  } // end if
100  } // end if
101 
102  // pack the parameters based on encrypted/plain
103 
104  // DataPackCollection packed_parameters;
105  // packed_parameters.p_data_packs = param_packs;
106  // packed_parameters.pack_count = op_params_count;
107 
108  // separate param packs in encrypted/plain
109  std::vector<hebench::APIBridge::DataPackCollection> packed_parameters(2);
110  std::vector<std::vector<hebench::APIBridge::DataPack>> packed_parameters_data_packs(packed_parameters.size());
111  std::bitset<sizeof(std::uint32_t)> cipher_param_mask(this->getBackendDescription().descriptor.cipher_param_mask);
112  for (std::size_t i = 0; i < param_packs.size(); ++i)
113  {
114  // determine if this parameter is encrypted
115  if (cipher_param_mask.test(i)) // m_descriptor.cipher_param_mask & (1 << i)
116  packed_parameters_data_packs.front().push_back(param_packs[i]);
117  else
118  packed_parameters_data_packs.back().push_back(param_packs[i]);
119  } // end for
120 
121  // pack the data in API bridge format
122  std::memset(packed_parameters.data(), 0, sizeof(hebench::APIBridge::DataPackCollection) * packed_parameters.size());
123  for (std::size_t i = 0; i < packed_parameters.size(); ++i)
124  {
125  if (!packed_parameters_data_packs[i].empty())
126  {
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();
129  } // end for
130  } // end for
131 
132  // encode the raw parameters data
133 
134  // Handle h_encoded_inputs;
135  // encode(h_benchmark, &packed_parameters, &h_encoded_inputs);
136 
137  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Encoding.") << std::endl;
138 
139  std::vector<RAIIHandle> h_inputs(packed_parameters.size());
140  for (std::size_t i = 0; i < packed_parameters.size(); ++i)
141  {
142  event_id = getEventIDNext();
143  if (packed_parameters[i].pack_count > 0)
144  {
145  event_name = "Encoding pack " + std::to_string(i);
146  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log(event_name + "...") << std::endl;
147  timer.start();
148  validateRetCode(hebench::APIBridge::encode(handle(), &packed_parameters[i], &h_inputs[i].handle));
149  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, 1, nullptr);
150  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
151  } // end if
152  else
153  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Pack " + std::to_string(i) + " is empty (skipping).") << std::endl;
154  } // end for
155 
156  std::cout << IOS_MSG_OK << std::endl;
157 
158  // encrypt the encoded data
159 
160  event_id = getEventIDNext();
161  event_name = "Encryption";
162 
163  // Handle h_cipher_inputs;
164  // encrypt(h_benchmark, h_encoded_inputs, &h_cipher_inputs);
165 
166  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Encryption.") << std::endl;
167 
168  if (packed_parameters[0].pack_count > 0)
169  {
170  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Encrypting...") << std::endl;
171 
172  hebench::APIBridge::Handle encrypted_input;
173  // we have data to encrypt
174  timer.start();
175  validateRetCode(hebench::APIBridge::encrypt(handle(), h_inputs.front().handle, &encrypted_input));
176  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, 1, nullptr);
177  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
178 
179  // overwrite the first input handle by its encrypted version
180  h_inputs.front() = encrypted_input; // old handle automatically destroyed by RAII
181 
182  std::cout << IOS_MSG_OK << std::endl;
183  } // end if
184  else
185  std::cout << IOS_MSG_WARNING << hebench::Logging::GlobalLogger::log("No encrypted parameters requested (skipping).") << std::endl;
186 
187  // load encrypted data into backend's remote to use as input to the operation
188 
189  event_id = getEventIDNext();
190  event_name = "Loading";
191 
192  // Handle h_remote_inputs;
193  // load(h_benchmark,
194  // &h_cipher_inputs, 1, // only 1 DataPackCollection
195  // &h_remote_inputs);
196 
197  // prepare handles for loading
198  std::vector<hebench::APIBridge::Handle> h_inputs_local;
199  for (std::size_t i = 0; i < packed_parameters.size(); ++i)
200  {
201  if (packed_parameters[i].pack_count > 0)
202  h_inputs_local.push_back(h_inputs[i].handle);
203  } // end for
204 
205  // load handles
206 
207  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Loading data to remote backend...") << std::endl;
208 
209  RAIIHandle h_inputs_remote;
210  timer.start();
212  h_inputs_local.data(), h_inputs_local.size(),
213  &h_inputs_remote.handle));
214  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, 1, nullptr);
215  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
216 
217  std::cout << IOS_MSG_OK << std::endl;
218 
219  // clean up data we no longer need (in reverse order of creation)
220 
221  // destroyHandle(h_cipher_inputs);
222  // destroyHandle(h_encoded_inputs);
223 
224  h_inputs_local.clear();
225  h_inputs.clear(); // input handles cleaned up automatically here
226  packed_parameters.clear();
227  packed_parameters_data_packs.clear();
228  param_packs.clear();
229 
230  // prepare parameter indexers for operation
231 
232  // ParameterIndexer params[op_params_count]; // one indexer per parameter
233  // params[0].batch_size = 1; // for parameter A we will be using one value
234  // params[0].value_index = 0; // starting with the first value
235 
236  // params[1].batch_size = 10; // for parameter B we will be using 10 values
237  // params[1].value_index = 0; // starting with the first.
238 
239  std::vector<hebench::APIBridge::ParameterIndexer> params(p_dataset->getParameterCount());
240 
241  for (std::size_t i = 0; i < params.size(); ++i)
242  {
243  params[i].batch_size = p_dataset->getParameterData(i).buffer_count;
244  params[i].value_index = 0;
245  } // end if
246 
247  // operate
248 
249  std::uint64_t min_test_time_ms =
253 
254  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Starting offline test.") << std::endl
255  << std::string(sizeof(IOS_MSG_INFO) + 1, ' ') << hebench::Logging::GlobalLogger::log("Requested time: " + std::to_string(this->getBackendDescription().descriptor.cat_params.min_test_time_ms) + " ms") << 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;
257 
258  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Testing...") << std::endl;
259 
260  event_id = getEventIDNext();
261  event_name = "Operation";
262 
263  out_report.addEventType(event_id, event_name, true);
264 
265  // TODO: (nice to have) maybe have a way to report progress or check if backend is stuck
266  // since this operation can be time consuming.
267 
268  RAIIHandle h_remote_results;
269  std::size_t iteration_count = 0;
270  std::size_t iteration_capacity = 20; // initial capacity for 20 iterations
271  double elapsed_ms = 0.0;
272  out_report.setEventCapacity(out_report.getEventCapacity() + iteration_capacity);
273  while (iteration_count <= 0 || elapsed_ms < min_test_time_ms)
274  {
275  if (iteration_count > 0)
276  // destroy previous result
277  h_remote_results.destroy();
278  timer.start();
280  h_inputs_remote.handle,
281  params.data(), params.size(),
282  &h_remote_results.handle));
283  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, num_results_samples, nullptr);
284  elapsed_ms += p_timing_event->elapsedWallTime<std::milli>();
285 
286  // check if we have enough capacity
287  if (iteration_capacity == iteration_count
288  && elapsed_ms > 0.0)
289  {
290  // capacity exceeded: over estimate capacity needed for the whole operation
291  // so that it is less likely that we need to reallocate again
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));
295  out_report.setEventCapacity(out_report.getEventCapacity()
296  + (max_capacity - iteration_capacity));
297  iteration_capacity = max_capacity;
298  } // end if
299  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
300 
301  ++iteration_count;
302  } // end while
303 
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;
307 
308  // clean up data we no longer need
309 
310  // destroyHandle(h_remote_inputs);
311 
312  h_inputs_remote.destroy();
313 
314  // postprocess output
315 
316  // Handle h_cipher_output;
317 
318  // retrieve data from backend's remote and store in host
319 
320  event_id = getEventIDNext();
321  event_name = "Store";
322 
323  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Retrieving data from remote backend...") << std::endl;
324 
325  RAIIHandle h_cipher_results;
326  // store(h_benchmark, h_remote_result,
327  // &h_cipher_output, 1 // Only 1 local DataPackCollection for result expected for this operation.
328  // );
329 
330  timer.start();
332  h_remote_results.handle,
333  &h_cipher_results.handle,
334  1));
335  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, 1, nullptr);
336  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
337 
338  // clean up data we no longer need
339  // destroyHandle(h_remote_result);
340 
341  // even though it is RAII, it is better to free up space on remote manually here,
342  // just in case it is a device with low memory capacity
343  h_remote_results.destroy();
344 
345  std::cout << IOS_MSG_OK << std::endl;
346 
347  // decrypt results
348 
349  event_id = getEventIDNext();
350  event_name = "Decryption";
351 
352  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Decrypting results...") << std::endl;
353 
354  RAIIHandle h_plain_results;
355  // Handle h_plain_result;
356  // decrypt(h_benchmark, h_cipher_output, &h_plain_result);
357 
358  timer.start();
359  validateRetCode(hebench::APIBridge::decrypt(handle(), h_cipher_results.handle, &h_plain_results.handle));
360  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, 1, nullptr);
361  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
362 
363  // // clean up data we no longer need
364  // destroyHandle(h_cipher_output);
365 
366  // even though it is RAII, it is better to free up space here,
367  // just in case these local handles are large
368  h_cipher_results.destroy();
369 
370  std::cout << IOS_MSG_OK << std::endl;
371 
372  // allocate space for decoded results
373 
374  // NativeDataBuffer p_raw_results[?]; // allocate space for all outputs
375 
376  // std::vector<std::uint8_t> raw_result_buffer(p_dataset->getResultData(0).p_buffers[0].size);
377  // hebench::APIBridge::NativeDataBuffer raw_results;
378  // raw_results.p = raw_result_buffer.data();
379  // raw_results.size = raw_result_buffer.size();
380  // raw_results.tag = 0;
381 
382  // allocate space for all outputs
383 
384  std::vector<std::uint8_t> raw_result_buffer;
385  std::uint64_t max_raw_result_size = 0;
386  //std::uint64_t num_buffers = 0;
387  for (std::uint64_t result_component_i = 0; result_component_i < p_dataset->getResultCount(); ++result_component_i)
388  {
389  const hebench::APIBridge::DataPack &result_component = p_dataset->getResultData(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;
392  } // end for
393  raw_result_buffer.resize(max_raw_result_size);
394 
395  // point to the allocated buffers
396 
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)
400  {
401  const hebench::APIBridge::DataPack &result_component = p_dataset->getResultData(result_component_i);
402  if (result_component.buffer_count > 0)
403  {
404  raw_results[result_component_i].resize(result_component.buffer_count, hebench::APIBridge::NativeDataBuffer({ 0, 0, 0 }));
405  for (std::uint64_t result_sample = 0; result_sample < result_component.buffer_count; ++result_sample)
406  {
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;
411 
412  offset_p += raw_results[result_component_i][result_sample].size;
413  } // end for
414  } // end if
415  } // end for
416 
417  // DataPack results_pack;
418  // results_pack.p_buffers = p_raw_results;
419  // results_pack.buffer_count = A_count// B_count;
420  // results_pack.param_position = 0; // we are retrieving results in the first position into this data pack
421 
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)
424  {
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;
428  } // end for
429 
430  // DataPackCollection packed_results;
431  // packed_results.p_data_packs = &results_pack;
432  // packed_results.pack_count = 1; // result shape is [1, 10]
433 
435  packed_results.p_data_packs = results_packs.data();
436  packed_results.pack_count = results_packs.size();
437 
438  // decode the results
439 
440  event_id = getEventIDNext();
441  event_name = "Decoding";
442 
443  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Decoding...") << std::endl;
444 
445  // decode(Handle h_benchmark, h_plain_result, &packed_results);
446 
447  timer.start();
448  validateRetCode(hebench::APIBridge::decode(handle(), h_plain_results.handle, &packed_results));
449  p_timing_event = timer.stop<DefaultTimeInterval>(event_id, 1, nullptr);
450  out_report.addEvent<DefaultTimeInterval>(p_timing_event, event_name);
451 
452  // clean up data we no longer need
453 
454  // even though it is RAII, it is better to free up space here,
455  // just in case these local handles are large
456  h_plain_results.destroy();
457 
458  std::cout << IOS_MSG_OK << std::endl;
459 
460  bool b_valid = true;
461 
462  if (run_config.b_validate_results)
463  {
464  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Validation.") << std::endl;
465 
466  std::cout << IOS_MSG_INFO << hebench::Logging::GlobalLogger::log("Result", false);
467 
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;
476 
477  // initialize loop limits
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)
480  {
481  // ComponentCounter increments starting from component 0,
482  // but we want to increment starting from most significant component,
483  // so, reverse the sizes:
484  params_count[params_count.size() - param_i - 1] = p_dataset->getParameterData(param_i).buffer_count;
485  } // end for
486  // looping variables
487  hebench::Utilities::Math::ComponentCounter param_counter(params_count);
488  std::size_t result_i = 0;
489  // validate the result of the operation evaluated on all sample combinations per parameter
490  do
491  {
492  assert(result_i < num_results_samples);
493 
494  if (result_i == 0 || (result_i + 1) % report_every_n_elements == 0)
495  {
496  // report operation to show sign of life
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;
502  } // end if
503 
504  if (mini_reports_cnt < 3
505  && progress_report_batch > 0
506  && progress_report_batch % report_every_n_by_3_elements == 0)
507  {
508  // report operation to show sign of life
509  ++mini_reports_cnt;
510  std::cout << hebench::Logging::GlobalLogger::log(".", false) << std::flush;
511  } // end if
512 
513  // validate output
514  std::string s_error_msg;
515  std::vector<hebench::APIBridge::NativeDataBuffer *> outputs;
516  std::vector<std::uint64_t> data_pack_indices;
517  try
518  {
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)
522  {
523  // make sure the right parameter and result index are being used
524  assert(packed_results.p_data_packs[result_component_i].param_position == result_component_i
525  && packed_results.p_data_packs[result_component_i].buffer_count > result_i);
526 
527  outputs[result_component_i] =
528  &packed_results.p_data_packs[result_component_i].p_buffers[result_i];
529  } // end for
530 
531  // ComponentCounter increments starting from component 0,
532  // but we want to increment starting from most significant component,
533  // so, reverse the counter:
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());
537 
538  b_valid = validateResult(p_dataset, data_pack_indices.data(),
539  outputs,
540  this->getBackendDescription().descriptor.data_type);
541  }
542  catch (std::exception &ex)
543  {
544  b_valid = false;
545  s_error_msg = ex.what();
546  }
547  catch (...)
548  {
549  b_valid = false;
550  }
551 
552  if (!b_valid)
553  {
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;
561 
562  // log the parameters, expected result and received result.
563  ss << std::endl;
564  logResult(ss, p_dataset, data_pack_indices.data(),
565  outputs,
566  this->getBackendDescription().descriptor.data_type);
567  out_report.appendFooter(ss.str());
568  } // end else
569 
570  ++progress_report_batch;
571  ++result_i; // next result
572  } while (b_valid && !param_counter.inc());
573 
574  if (b_valid)
575  {
576  // report valid op
577  if ((num_results_samples) % report_every_n_elements != 0)
578  {
579  // pretty-print end of result report
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;
583  } // end if
584  else
585  std::cout << hebench::Logging::GlobalLogger::log("") << std::endl;
586  std::cout << IOS_MSG_OK << std::endl;
587  } // end if
588  } // end if
589  else
590  {
591  out_report.prependFooter("Validation skipped");
592  std::cout << IOS_MSG_WARNING << hebench::Logging::GlobalLogger::log("Validation skipped.") << std::endl;
593  } // end else
594 
595  std::cout << IOS_MSG_DONE << hebench::Logging::GlobalLogger::log("Test Completed.") << std::endl;
596 
597  return b_valid;
598 }
599 
600 } // namespace TestHarness
601 } // namespace hebench
void prependFooter(const std::string &new_header, bool new_line=true)
void setEventCapacity(uint64_t new_capacity)
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(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)
#define IOS_MSG_FAILED
#define IOS_MSG_DONE
#define IOS_MSG_WARNING
#define IOS_MSG_INFO
#define IOS_MSG_OK
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.
Definition: types.h:625
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.
Definition: types.h:447
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.
Definition: types.h:533
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.
Definition: types.h:532
std::uint64_t pack_count
Number of data packs in the collection.
Definition: types.h:626
std::uint64_t size
Size of underlying data.
Definition: types.h:564
std::uint64_t param_position
The 0-based position of this parameter in the corresponding function call.
Definition: types.h:614
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.
Definition: types.h:613
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.
Definition: types.h:612
Defines a data package for an operation.
Definition: types.h:611
Defines a collection of data packs.
Definition: types.h:624
Structure to contain flexible data.
Definition: types.h:552
std::string to_string(const std::string_view &s)