HEBench
hebench_eltwiseadd.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 <cassert>
6 #include <sstream>
7 
8 #include "../include/hebench_eltwiseadd.h"
9 
10 namespace hebench {
11 namespace TestHarness {
12 namespace EltwiseAdd {
13 
14 //------------------------------------
15 // class BenchmarkDescriptionCategory
16 //------------------------------------
17 
21  };
22 
23 std::uint64_t BenchmarkDescriptorCategory::fetchVectorSize(const std::vector<hebench::APIBridge::WorkloadParam> &w_params)
24 {
25  assert(WorkloadParameterCount == 1);
26  assert(OpParameterCount == 2);
27  assert(OpResultCount == 1);
28 
29  std::uint64_t retval;
30 
31  if (w_params.size() < WorkloadParameterCount)
32  {
33  std::stringstream ss;
34  ss << "Insufficient workload parameters in 'w_params'. Expected " << WorkloadParameterCount
35  << ", but " << w_params.size() << "received.";
36  throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
37  } // end if
38 
39  for (std::size_t i = 0; i < WorkloadParameterCount; ++i)
40  if (w_params[i].data_type != WorkloadParameterType[i])
41  {
42  std::stringstream ss;
43  ss << "Invalid type for workload parameter " << i
44  << ". Expected type ID " << WorkloadParameterType[i] << ", but " << w_params[i].data_type << " received.";
45  throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
46  } // end if
47  else if (w_params[i].u_param <= 0)
48  {
49  std::stringstream ss;
50  ss << "Invalid number of elements for vector in workload parameter " << i
51  << ". Expected positive integer, but " << w_params[i].u_param << " received.";
52  throw std::invalid_argument(IL_LOG_MSG_CLASS(ss.str()));
53  } // end if
54 
55  retval = w_params.at(0).u_param;
56 
57  return retval;
58 }
59 
61  const std::vector<hebench::APIBridge::WorkloadParam> &w_params) const
62 {
63  bool retval = false;
64 
65  // return true if benchmark is supported
67  {
68  try
69  {
70  fetchVectorSize(w_params);
71  retval = true;
72  }
73  catch (...)
74  {
75  // workload not supported
76  retval = false;
77  }
78  } // end if
79 
80  return retval;
81 }
82 
84  const Engine &engine,
85  const BenchmarkDescription::Backend &backend_desc,
86  const BenchmarkDescription::Configuration &config) const
87 {
88  (void)engine;
89  std::stringstream ss;
90 
91  output.concrete_descriptor = backend_desc.descriptor;
93  backend_desc.descriptor,
94  config,
96 
97  // workload name
98 
99  std::uint64_t vector_size = fetchVectorSize(config.w_params);
100  ss << BaseWorkloadName << " " << vector_size;
101 
102  output.workload_name = ss.str();
105 }
106 
107 //---------------------------
108 // class DataGeneratorHelper
109 //---------------------------
110 
115 {
116 private:
117  IL_DECLARE_CLASS_NAME(EltwiseAdd::DataGeneratorHelper)
118 
119 public:
120  static void vectorEltwiseAdd(hebench::APIBridge::DataType data_type,
121  void *result, const void *a, const void *b,
122  std::uint64_t elem_count);
123 
124 protected:
126 
127 private:
128  template <class T>
129  static void vectorEltwiseAdd(T *result, const T *a, const T *b, std::uint64_t elem_count)
130  {
131  if (!result)
132  throw std::invalid_argument(IL_LOG_MSG_CLASS("Invalid null `result`"));
133  if (!a)
134  throw std::invalid_argument(IL_LOG_MSG_CLASS("Invalid null `a`"));
135  if (!b)
136  throw std::invalid_argument(IL_LOG_MSG_CLASS("Invalid null `b`"));
137  std::transform(a, a + elem_count, // a[0..elem_count]
138  b, // b[0..elem_count]
139  result, // result[0..elem_count]
140  std::plus<T>()); // eltwise add
141  }
142 };
143 
145  void *result, const void *a, const void *b,
146  std::uint64_t elem_count)
147 {
148  switch (data_type)
149  {
151  vectorEltwiseAdd<std::int32_t>(reinterpret_cast<std::int32_t *>(result),
152  reinterpret_cast<const std::int32_t *>(a), reinterpret_cast<const std::int32_t *>(b),
153  elem_count);
154  break;
155 
157  vectorEltwiseAdd<std::int64_t>(reinterpret_cast<std::int64_t *>(result),
158  reinterpret_cast<const std::int64_t *>(a), reinterpret_cast<const std::int64_t *>(b),
159  elem_count);
160  break;
161 
163  vectorEltwiseAdd<float>(reinterpret_cast<float *>(result),
164  reinterpret_cast<const float *>(a), reinterpret_cast<const float *>(b),
165  elem_count);
166  break;
167 
169  vectorEltwiseAdd<double>(reinterpret_cast<double *>(result),
170  reinterpret_cast<const double *>(a), reinterpret_cast<const double *>(b),
171  elem_count);
172  break;
173 
174  default:
175  throw std::invalid_argument(IL_LOG_MSG_CLASS("Unknown data type."));
176  break;
177  } // end switch
178 }
179 
180 //---------------------
181 // class DataGenerator
182 //---------------------
183 
184 DataLoader::Ptr DataLoader::create(std::uint64_t vector_size,
185  std::uint64_t batch_size_a,
186  std::uint64_t batch_size_b,
188 {
190  retval->init(vector_size, batch_size_a, batch_size_b, data_type);
191  return retval;
192 }
193 
194 DataLoader::Ptr DataLoader::create(std::uint64_t expected_vector_size,
195  std::uint64_t max_batch_size_a,
196  std::uint64_t max_batch_size_b,
198  const std::string &dataset_filename)
199 {
201  retval->init(expected_vector_size, max_batch_size_a, max_batch_size_b, data_type, dataset_filename);
202  return retval;
203 }
204 
205 DataLoader::DataLoader() :
206  m_vector_size(0)
207 {
208 }
209 
210 void DataLoader::init(std::uint64_t vector_size,
211  std::uint64_t batch_size_a,
212  std::uint64_t batch_size_b,
214 {
215  // Load/generate and initialize the data for vector element-wise addition:
216  // C = A + B
217 
218  // number of samples in each input parameter and output
219  std::size_t batch_sizes[InputDim0 + OutputDim0] = {
220  batch_size_a,
221  batch_size_b,
222  batch_size_a * batch_size_b
223  };
224 
225  // compute buffer size in bytes for each vector
226  std::vector<std::uint64_t> sample_vector_sizes(InputDim0 + OutputDim0, vector_size);
227  m_vector_size = vector_size;
228 
229  PartialDataLoader::init(data_type,
230  InputDim0, // number of input parameters
231  batch_sizes, // samples per parameter
232  sample_vector_sizes.data(), // vector size for each parameter
233  OutputDim0, // number of result components
234  sample_vector_sizes.data() + InputDim0, // number of result samples
235  true); // allocate memory for ground truth?
236 
237  // at this point all NativeDataBuffers have been allocated and pointed to the correct locations
238 
239  // fill up each vector data
240 
241  // input
242  for (std::size_t vector_i = 0; vector_i < InputDim0; ++vector_i)
243  {
244  for (std::uint64_t i = 0; i < batch_sizes[vector_i]; ++i)
245  {
246  // generate the data
248  getParameterData(vector_i).p_buffers[i].p,
249  vector_size, -10.0, 10.0);
250  } // end for
251  } // end for
252 
253  // output
254  //#pragma omp parallel for collapse(2)
255  for (std::uint64_t a_i = 0; a_i < batch_sizes[0]; ++a_i)
256  {
257  for (std::uint64_t b_i = 0; b_i < batch_sizes[1]; ++b_i)
258  {
259  // find the index for the result buffer based on the input indices
260  std::uint64_t ppi[] = { a_i, b_i };
261  std::uint64_t r_i = getResultIndex(ppi);
262 
263  // generate the data
265  getResultData(0).p_buffers[r_i].p, // C
266  getParameterData(0).p_buffers[a_i].p, // A
267  getParameterData(1).p_buffers[b_i].p, // B
268  vector_size);
269  } // end for
270  } // end for
271 
272  // all data has been generated at this point
273 }
274 
275 void DataLoader::init(std::uint64_t expected_vector_size,
276  std::uint64_t max_batch_size_a,
277  std::uint64_t max_batch_size_b,
279  const std::string &dataset_filename)
280 {
281  // Load and initialize the data for vector element-wise addition:
282  // C = A + B
283 
284  // number of samples in each input parameter and output
285  std::size_t batch_sizes[InputDim0 + OutputDim0] = {
286  max_batch_size_a,
287  max_batch_size_b,
288  max_batch_size_a * max_batch_size_b
289  };
290 
291  // compute buffer size in bytes for each vector
292  std::vector<std::uint64_t> sample_vector_sizes(InputDim0 + OutputDim0, expected_vector_size);
293  m_vector_size = expected_vector_size;
294 
295  PartialDataLoader::init(dataset_filename, data_type,
296  InputDim0,
297  batch_sizes,
298  sample_vector_sizes.data(),
299  OutputDim0,
300  sample_vector_sizes.data() + InputDim0);
301 
302  // at this point all NativeDataBuffers have been allocated, pointed to the correct locations
303  // and filled with data from the specified dataset file
304 }
305 
306 void DataLoader::computeResult(std::vector<hebench::APIBridge::NativeDataBuffer *> &result,
307  const std::uint64_t *param_data_pack_indices,
309 {
310  // as protected method, parameters should be valid when called
311 
312  // generate the output
314  result.front()->p, // C
315  this->getParameterData(0).p_buffers[param_data_pack_indices[0]].p, // A
316  this->getParameterData(1).p_buffers[param_data_pack_indices[1]].p, // B
317  m_vector_size);
318 }
319 
320 } // namespace EltwiseAdd
321 } // namespace TestHarness
322 } // namespace hebench
const hebench::APIBridge::BenchmarkDescriptor & descriptor
Benchmark backend descriptor, as retrieved by backend, corresponding to the registration handle h_des...
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 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.
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::uint64_t fetchVectorSize(const std::vector< hebench::APIBridge::WorkloadParam > &w_params)
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 hebench::APIBridge::WorkloadParamType::WorkloadParamType WorkloadParameterType[WorkloadParameterCount]
Static helper class to generate vector data for all supported data types.
static void vectorEltwiseAdd(hebench::APIBridge::DataType data_type, void *result, const void *a, const void *b, std::uint64_t elem_count)
static DataLoader::Ptr create(std::uint64_t vector_size, std::uint64_t batch_size_a, std::uint64_t batch_size_b, hebench::APIBridge::DataType data_type)
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 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.
WorkloadParamType
Defines the possible data types for a workload flexible parameter.
Definition: types.h:303
@ Float64
64 bits IEEE 754 standard floating point real numbers.
Definition: types.h:306
@ Int64
64 bits signed integers.
Definition: types.h:304
@ UInt64
64 bits unsigned integers.
Definition: types.h:305
DataType
Defines data types for a workload.
Definition: types.h:379
@ Float32
32 bits IEEE 754 standard floating point real numbers.
Definition: types.h:382
@ Int32
32 bits signed integers.
Definition: types.h:380
Workload workload
Workload for the benchmark.
Definition: types.h:529
Defines a benchmark test.
Definition: types.h:527