11 #include "../include/hebench_simple_set_intersection.h" 
   12 #include "hebench/modules/general/include/hebench_math_utils.h" 
   15 namespace TestHarness {
 
   35     std::array<std::uint64_t, WorkloadParameterCount> retval;
 
   41            << 
", but " << w_params.size() << 
"received.";
 
   42         throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
 
   50             ss << 
"Invalid type for workload parameter " << i
 
   51                << 
". Expected type ID " << 
WorkloadParameterType[i] << 
", but " << w_params[i].data_type << 
" received.";
 
   52             throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
 
   54         else if (w_params[i].u_param <= 0)
 
   57             ss << 
"Invalid number of elements for vector in workload parameter " << i
 
   58                << 
". Expected positive integer, but " << w_params[i].u_param << 
" received.";
 
   59             throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
 
   62     retval.at(0) = w_params.at(0).u_param; 
 
   63     retval.at(1) = w_params.at(1).u_param; 
 
   64     retval.at(2) = w_params.at(2).u_param; 
 
   87        << 
" |X| -> " << sets_size[0] << 
", " 
   88        << 
"|Y| -> " << sets_size[1] << 
", " 
   89        << 
"k  -> " << sets_size[2];
 
   97                                                            const std::vector<hebench::APIBridge::WorkloadParam> &w_params)
 const 
  133                                             void *result, 
const void *x, 
const void *y,
 
  134                                             std::uint64_t n, std::uint64_t m, std::uint64_t k);
 
  141     static bool isMemberOf(
const T *dataset, 
const T *value, std::uint64_t n, std::uint64_t k)
 
  144         for (
size_t i = 0; !retval && i < n; ++i)
 
  146             std::uint64_t members = 0;
 
  148             for (
size_t j = 0; flag && j < k; ++j)
 
  150                 flag = dataset[(i * k) + j] == value[j];
 
  156             retval = members == k;
 
  162     static void mySetIntersection(T *result, 
const T *dataset_X, 
const T *dataset_Y, std::uint64_t n, std::uint64_t m, std::uint64_t k)
 
  164         size_t idx_result = 0;
 
  167         std::fill(result, result + m * k, 
static_cast<T
>(0));
 
  169         for (
size_t idx_x = 0; idx_x < n; ++idx_x)
 
  171             if (isMemberOf(dataset_Y, dataset_X + (idx_x * k), m, k))
 
  174                 if (!isMemberOf(result, dataset_X + (idx_x * k), m, k))
 
  176                     std::copy(dataset_X + (idx_x * k),
 
  177                               dataset_X + (idx_x * k) + k,
 
  178                               result + (idx_result * k));
 
  189             throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Invalid null `x`"));
 
  191             throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Invalid null `y`"));
 
  193             throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Invalid null `k`"));
 
  197             mySetIntersection(result, x, y, n, m, k);
 
  201             mySetIntersection(result, y, x, m, n, k);
 
  207                                                       void *result, 
const void *x, 
const void *y,
 
  208                                                       std::uint64_t n, std::uint64_t m, std::uint64_t k)
 
  212         throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Invalid null 'p_result'."));
 
  218         vectorSimpleSetIntersection<std::int32_t>(
reinterpret_cast<std::int32_t *
>(result),
 
  219                                                   reinterpret_cast<const std::int32_t *
>(x), 
reinterpret_cast<const std::int32_t *
>(y),
 
  224         vectorSimpleSetIntersection<std::int64_t>(
reinterpret_cast<std::int64_t *
>(result),
 
  225                                                   reinterpret_cast<const std::int64_t *
>(x), 
reinterpret_cast<const std::int64_t *
>(y),
 
  230         vectorSimpleSetIntersection<float>(
reinterpret_cast<float *
>(result),
 
  231                                            reinterpret_cast<const float *
>(x), 
reinterpret_cast<const float *
>(y),
 
  236         vectorSimpleSetIntersection<double>(
reinterpret_cast<double *
>(result),
 
  237                                             reinterpret_cast<const double *
>(x), 
reinterpret_cast<const double *
>(y),
 
  242         throw std::invalid_argument(IL_LOG_MSG_CLASS(
"Unknown data type."));
 
  252                                    std::uint64_t set_size_y,
 
  253                                    std::uint64_t batch_size_x,
 
  254                                    std::uint64_t batch_size_y,
 
  255                                    std::uint64_t element_size_k,
 
  259     retval->init(set_size_x, set_size_y, batch_size_x, batch_size_y, element_size_k, data_type);
 
  264                                    std::uint64_t set_size_y,
 
  265                                    std::uint64_t batch_size_x,
 
  266                                    std::uint64_t batch_size_y,
 
  267                                    std::uint64_t element_size_k,
 
  269                                    const std::string &dataset_filename)
 
  272     retval->init(set_size_x, set_size_y, batch_size_x, batch_size_y, element_size_k, data_type, dataset_filename);
 
  276 DataLoader::DataLoader() :
 
  277     m_set_size_x(0), m_set_size_y(0), m_element_size_k(1)
 
  281 void DataLoader::init(std::uint64_t set_size_x,
 
  282                       std::uint64_t set_size_y,
 
  283                       std::uint64_t batch_size_x,
 
  284                       std::uint64_t batch_size_y,
 
  285                       std::uint64_t element_size_k,
 
  292     std::size_t batch_sizes[InputDim0 + OutputDim0] = {
 
  295         (batch_size_x * batch_size_y)
 
  298     m_set_size_x     = set_size_x;
 
  299     m_set_size_y     = set_size_y;
 
  300     m_element_size_k = element_size_k;
 
  303     std::uint64_t sample_set_sizes[InputDim0 + OutputDim0] = {
 
  304         set_size_x * element_size_k,
 
  305         set_size_y * element_size_k,
 
  306         std::min(set_size_x, set_size_y) * element_size_k 
 
  311                             InputDim0, batch_sizes, sample_set_sizes,
 
  312                             OutputDim0, sample_set_sizes + InputDim0,
 
  319     constexpr std::size_t Param_SetX = 0;
 
  320     constexpr std::size_t Param_SetY = 1;
 
  323     for (std::uint64_t sample_i = 0; sample_i < batch_sizes[Param_SetX]; ++sample_i)
 
  327                                                    sample_set_sizes[Param_SetX],
 
  333     for (std::uint64_t sample_i = 0; sample_i < batch_sizes[Param_SetY]; ++sample_i)
 
  336         std::vector<std::uint64_t> indices_x;
 
  337         std::vector<std::uint64_t>::iterator it_indices_y;
 
  338         if (!indices_y.empty())
 
  341             std::sort(indices_y.begin(), indices_y.end());
 
  344             it_indices_y = indices_y.begin();
 
  350         for (std::uint64_t item_y = 0; item_y < set_size_y; ++item_y)
 
  352             std::uint8_t *p_setY_item = p_setY + item_y * element_size_k * 
sizeOf(data_type);
 
  353             if (!indices_x.empty() && item_y == *it_indices_y)
 
  356                 std::uint8_t *p_setX_item = p_setX + indices_x.back() * element_size_k * 
sizeOf(data_type);
 
  357                 std::copy(p_setX_item, p_setX_item + element_size_k * 
sizeOf(data_type),
 
  359                 indices_x.pop_back();
 
  373     for (std::uint64_t sampleX_i = 0; sampleX_i < batch_sizes[Param_SetX]; ++sampleX_i)
 
  374         for (std::uint64_t sampleY_i = 0; sampleY_i < batch_sizes[Param_SetY]; ++sampleY_i)
 
  377             std::uint64_t ppi[] = { sampleX_i, sampleY_i };
 
  385                                                              set_size_x, set_size_y, element_size_k);
 
  391 void DataLoader::init(std::uint64_t set_size_x,
 
  392                       std::uint64_t set_size_y,
 
  393                       std::uint64_t batch_size_x,
 
  394                       std::uint64_t batch_size_y,
 
  395                       std::uint64_t element_size_k,
 
  397                       const std::string &dataset_filename)
 
  403     std::size_t batch_sizes[InputDim0 + OutputDim0] = {
 
  406         (batch_size_x * batch_size_y)
 
  409     m_set_size_x     = set_size_x;
 
  410     m_set_size_y     = set_size_y;
 
  411     m_element_size_k = element_size_k;
 
  414     std::uint64_t sample_set_sizes[InputDim0 + OutputDim0] = {
 
  415         set_size_x * element_size_k,
 
  416         set_size_y * element_size_k,
 
  417         std::min(set_size_x, set_size_y) * element_size_k 
 
  422                             InputDim0, batch_sizes, sample_set_sizes,
 
  423                             OutputDim0, sample_set_sizes + InputDim0);
 
  430                                const std::uint64_t *param_data_pack_indices,
 
  440                                                      m_set_size_x, m_set_size_y, m_element_size_k);
 
  444                     const std::uint64_t *param_data_pack_indices,
 
  445                     const std::vector<hebench::APIBridge::NativeDataBuffer *> &outputs,
 
  446                     std::uint64_t k_count,
 
  449     static constexpr 
const std::size_t MaxErrorPrint = 10;
 
  454     std::vector<std::pair<bool, std::uint64_t>> is_valid;
 
  458     if (outputs.size() != dataset->getResultCount())
 
  460         throw std::invalid_argument(IL_LOG_MSG(
"Invalid number of outputs: 'outputs'."));
 
  464     const std::vector<const hebench::APIBridge::NativeDataBuffer *> &truths =
 
  468     if (!truths.empty() && !outputs.empty() && truths.front())
 
  470         std::size_t index = 0;
 
  471         for (index = 0; retval && index < truths.size(); ++index)
 
  476                 if (!outputs.at(index))
 
  478                     throw std::invalid_argument(IL_LOG_MSG(
"Unexpected null output component in: 'outputs[" + 
std::to_string(index) + 
"]'."));
 
  481             catch (
const std::out_of_range &out_of_range)
 
  483                 throw std::invalid_argument(IL_LOG_MSG(
"Unexpected out of range index output component in: 'outputs[" + 
std::to_string(index) + 
"]'."));
 
  486             if (outputs.at(index)->size < truths.at(index)->size)
 
  488                 throw std::invalid_argument(IL_LOG_MSG(
"Buffer in outputs is not large enough to contain the expected output: 'outputs[" + 
std::to_string(index) + 
"]'."));
 
  491             void *p_truth  = truths.at(index)->p;
 
  492             void *p_output = outputs.at(index)->p; 
 
  501                 is_valid = 
almostEqualSet(
reinterpret_cast<const std::int32_t *
>(p_truth),
 
  502                                           reinterpret_cast<const std::int32_t *
>(p_output),
 
  508                 is_valid = 
almostEqualSet(
reinterpret_cast<const std::int64_t *
>(p_truth),
 
  509                                           reinterpret_cast<const std::int64_t *
>(p_output),
 
  515                 is_valid = 
almostEqualSet(
reinterpret_cast<const float *
>(p_truth),
 
  516                                           reinterpret_cast<const float *
>(p_output),
 
  522                 is_valid = 
almostEqualSet(
reinterpret_cast<const double *
>(p_truth),
 
  523                                           reinterpret_cast<const double *
>(p_output),
 
  534             retval = retval && is_valid.empty();
 
  539             std::stringstream ss;
 
  540             ss << 
"Result component, " << (index - 1) << std::endl
 
  541                << 
"Elements mismatched, " << is_valid.size() << std::endl
 
  542                << 
"Failed indices, ";
 
  543             for (std::size_t i = 0; i < is_valid.size() && i < MaxErrorPrint; ++i)
 
  545                 ss << 
"(" << (is_valid[i].first ? 
"ground truth" : 
"output") << 
"; " << is_valid[i].second * k_count << 
".." << is_valid[i].second * k_count + k_count - 1 << 
")";
 
  546                 if (i + 1 < is_valid.size() && i + 1 < MaxErrorPrint)
 
  551             if (is_valid.size() > MaxErrorPrint)
 
  555             throw std::runtime_error(ss.str());
 
const hebench::APIBridge::BenchmarkDescriptor & descriptor
Benchmark backend descriptor, as retrieved by backend, corresponding to the registration handle h_des...
Specifies a benchmark configuration.
std::vector< hebench::APIBridge::WorkloadParam > w_params
Set of arguments for workload parameters.
Static helper class to generate vector data for all supported data types.
static std::vector< std::uint64_t > generateRandomIntersectionIndicesU(std::uint64_t elem_count, std::uint64_t indices_count=0)
Generates uniform random amount of indices.
static std::uint64_t generateRandomIntU(std::uint64_t min_val, std::uint64_t max_val)
static void generateRandomVectorU(hebench::APIBridge::DataType data_type, void *result, std::uint64_t elem_count, double min_val, double max_val)
Generates uniform random data of the specified type.
static std::size_t sizeOf(hebench::APIBridge::DataType data_type)
std::shared_ptr< ResultData > ResultDataPtr
std::shared_ptr< IDataLoader > Ptr
static void completeCategoryParams(hebench::APIBridge::BenchmarkDescriptor &out_descriptor, const hebench::APIBridge::BenchmarkDescriptor &in_descriptor, const BenchmarkDescription::Configuration &config, bool force_config)
Completes common elements of category parameters in a descriptor using the specified configuration.
static bool getForceConfigValues()
Specifies whether frontend will override backend descriptors using configuration data or not.
std::size_t operation_params_count
Number of parameters for the represented workload operation.
std::string workload_name
Human-readable friendly name for the represented workload to be used for its description on the repor...
hebench::APIBridge::BenchmarkDescriptor concrete_descriptor
Benchmark descriptor completed with concrete values assigned to configurable fields.
std::string workload_base_name
Human-readable friendly name for the represented workload to be used for its description on the repor...
Bundles values that need to be filled by a workload during completeWorkloadDescription().
const hebench::APIBridge::DataPack & getResultData(std::uint64_t param_position) const override
Data pack corresponding to the specified component of the result.
const hebench::APIBridge::DataPack & getParameterData(std::uint64_t param_position) const override
Data pack for specified operation parameter (operand).
void init(hebench::APIBridge::DataType data_type, std::size_t input_dim, const std::size_t *input_sample_count_per_dim, const std::uint64_t *input_count_per_dim, std::size_t output_dim, const std::uint64_t *output_count_per_dim, bool allocate_output)
Initializes dimensions of inputs and outputs. No allocation is performed.
std::uint64_t getResultIndex(const std::uint64_t *param_data_pack_indices) const override
Computes the index of the result NativeDataBuffer given the indices of the input data.
void completeWorkloadDescription(WorkloadDescriptionOutput &output, const Engine &engine, const BenchmarkDescription::Backend &backend_desc, const BenchmarkDescription::Configuration &config) const override
Completes the description for the matched benchmark.
static std::array< std::uint64_t, BenchmarkDescriptorCategory::WorkloadParameterCount > fetchSetSize(const std::vector< hebench::APIBridge::WorkloadParam > &w_params)
static constexpr std::uint64_t OpResultCount
static hebench::APIBridge::WorkloadParamType::WorkloadParamType WorkloadParameterType[WorkloadParameterCount]
static constexpr std::uint64_t WorkloadParameterCount
bool matchBenchmarkDescriptor(const hebench::APIBridge::BenchmarkDescriptor &bench_desc, const std::vector< hebench::APIBridge::WorkloadParam > &w_params) const override
Determines if the represented benchmark can perform the workload described by a specified HEBench ben...
static constexpr const char * BaseWorkloadName
static constexpr std::uint64_t OpParameterCount
Static helper class to generate vector data for all supported data types.
static void vectorSimpleSetIntersection(hebench::APIBridge::DataType data_type, void *result, const void *x, const void *y, std::uint64_t n, std::uint64_t m, std::uint64_t k)
void computeResult(std::vector< hebench::APIBridge::NativeDataBuffer * > &result, const std::uint64_t *param_data_pack_indices, hebench::APIBridge::DataType data_type) override
Computes result of the operation on the input data given the of the input sample.
static DataLoader::Ptr create(std::uint64_t set_size_x, std::uint64_t set_size_y, std::uint64_t batch_size_x, std::uint64_t batch_size_y, std::uint64_t element_size_k, hebench::APIBridge::DataType data_type)
std::shared_ptr< DataLoader > Ptr
WorkloadParamType
Defines the possible data types for a workload flexible parameter.
@ Float64
64 bits IEEE 754 standard floating point real numbers.
@ Int64
64 bits signed integers.
@ UInt64
64 bits unsigned integers.
DataType
Defines data types for a workload.
@ Float32
32 bits IEEE 754 standard floating point real numbers.
@ Int32
32 bits signed integers.
void * p
Pointer to underlying data.
Workload workload
Workload for the benchmark.
NativeDataBuffer * p_buffers
Array of data buffers for parameter.
Defines a benchmark test.
std::string to_string(const std::string_view &s)
bool validateResult(IDataLoader::Ptr dataset, const std::uint64_t *param_data_pack_indices, const std::vector< hebench::APIBridge::NativeDataBuffer * > &p_outputs, std::uint64_t k_count, hebench::APIBridge::DataType data_type)
std::enable_if< std::is_integral< T >::value||std::is_floating_point< T >::value, std::vector< std::pair< bool, std::uint64_t > > >::type almostEqualSet(const T *X, const T *Y, std::uint64_t n, std::uint64_t m, std::uint64_t k, double pct=0.05)
Finds whether values in two arrays are within a certain percentage of each other.