NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
gga_offload_sbc_generator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024-2025 NVIDIA CORPORATION AND AFFILIATES. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are permitted
5  * provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice, this list of
7  * conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
12  * to endorse or promote products derived from this software without specific prior written
13  * permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21  * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  */
25 #include <algorithm>
26 #include <array>
27 #include <chrono>
28 #include <cstdint>
29 #include <cstdio>
30 #include <memory>
31 #include <stdexcept>
32 #include <thread>
33 #include <vector>
34 
35 #include <lz4frame.h>
36 
37 #include <doca_argp.h>
38 #include <doca_buf_inventory.h>
39 #include <doca_ctx.h>
40 #include <doca_dev.h>
41 #include <doca_erasure_coding.h>
42 #include <doca_error.h>
43 #include <doca_log.h>
44 #include <doca_mmap.h>
45 #include <doca_pe.h>
46 #include <doca_version.h>
47 
54 
56 
57 using namespace std::string_literals;
58 
59 namespace {
60 auto constexpr app_name = "doca_storage_gga_offload_sbc_generator";
61 auto constexpr padding_byte = uint8_t{0};
62 auto constexpr num_ec_tasks = uint32_t{1};
63 auto constexpr num_ec_buffers = uint32_t{2} * num_ec_tasks;
64 
65 struct gga_offload_sbc_gen_configuration {
66  std::string device_id;
67  std::string original_data_file_name;
68  std::string data_1_file_name;
69  std::string data_2_file_name;
70  std::string data_p_file_name;
71  std::string ec_matrix_type;
72  uint32_t block_size;
73 };
74 
75 struct gga_offload_sbc_gen_result {
76  uint32_t block_count;
77  std::vector<uint8_t> data_1_content;
78  std::vector<uint8_t> data_2_content;
79  std::vector<uint8_t> data_p_content;
80 };
81 
82 struct lz4_context {
83  LZ4F_preferences_t const cfg;
84  LZ4F_cctx *ctx;
85 
86  ~lz4_context();
87 
88  lz4_context();
89 
90  lz4_context(lz4_context const &) = delete;
91 
92  lz4_context(lz4_context &&) noexcept = delete;
93 
94  lz4_context &operator=(lz4_context const &) = delete;
95 
96  lz4_context &operator=(lz4_context &&) noexcept = delete;
97 
98  uint32_t compress(uint8_t const *in_bytes, uint32_t in_byte_count, uint8_t *out_bytes, uint32_t out_bytes_size);
99 };
100 
101 class gga_offload_sbc_gen_app {
102 public:
103  ~gga_offload_sbc_gen_app();
104 
105  gga_offload_sbc_gen_app() = delete;
106 
107  gga_offload_sbc_gen_app(std::string const &device_id, std::string const &ec_matrix_type, uint32_t block_size);
108 
109  gga_offload_sbc_gen_app(gga_offload_sbc_gen_app const &) = delete;
110 
111  gga_offload_sbc_gen_app(gga_offload_sbc_gen_app &&) noexcept = delete;
112 
113  gga_offload_sbc_gen_app &operator=(gga_offload_sbc_gen_app const &) = delete;
114 
115  gga_offload_sbc_gen_app &operator=(gga_offload_sbc_gen_app &&) noexcept = delete;
116 
117  gga_offload_sbc_gen_result generate_binary_content(std::vector<uint8_t> input_data);
118 
119 private:
120  lz4_context m_lz4_ctx;
121  doca_dev *m_dev;
122  std::vector<uint8_t> m_compressed_bytes_buffer;
123  std::vector<uint8_t> m_gga_output_buffer_bytes;
124  doca_mmap *m_input_mmap;
125  doca_mmap *m_output_mmap;
126  doca_buf_inventory *m_buf_inv;
127  doca_buf *m_input_buf;
128  doca_buf *m_output_buf;
129  doca_pe *m_pe;
130  doca_ec *m_ec;
131  doca_ec_matrix *m_ec_matrix;
132  doca_ec_task_create *m_ec_task;
133  uint32_t m_block_size;
134  bool m_error_flag;
135 };
136 
137 /*
138  * Print the parsed configuration
139  *
140  * @cfg [in]: Configuration to display
141  */
142 void print_config(gga_offload_sbc_gen_configuration const &cfg) noexcept;
143 
144 /*
145  * Parse command line arguments
146  *
147  * @argc [in]: Number of arguments
148  * @argv [in]: Array of argument values
149  * @return: Parsed configuration
150  *
151  * @throws: std::runtime_error If the configuration cannot pe parsed or contains invalid values
152  */
153 gga_offload_sbc_gen_configuration parse_cli_args(int argc, char **argv);
154 
155 /*
156  * Pad the content of input to be a multiple of block_size length
157  *
158  * @input [in]: Vector to pad
159  * @block_size [in]: Block size
160  */
161 void pad_input_to_multiple_of_block_size(std::vector<uint8_t> &input, uint32_t block_size);
162 } /* namespace */
163 
164 /*
165  * Main
166  *
167  * @argc [in]: Number of arguments
168  * @argv [in]: Array of argument values
169  * @return: EXIT_SUCCESS on success and EXIT_FAILURE otherwise
170  */
171 int main(int argc, char **argv)
172 {
173  int rc = EXIT_SUCCESS;
175  printf("%s: v%s\n", app_name, doca_version());
176 
177  try {
178  auto const cfg = parse_cli_args(argc, argv);
179  print_config(cfg);
180 
181  gga_offload_sbc_gen_app app{cfg.device_id, cfg.ec_matrix_type, cfg.block_size};
182 
183  auto input_data = storage::load_file_bytes(cfg.original_data_file_name);
184  pad_input_to_multiple_of_block_size(input_data, cfg.block_size);
185 
186  printf("Processing data...");
187  auto const results = app.generate_binary_content(input_data);
188 
189  printf("Output info:\n");
190  printf("\tBlock size: %u\n", cfg.block_size);
191  printf("\tOut block count: %u\n", results.block_count);
192 
194  storage::binary_content{cfg.block_size,
195  results.block_count,
196  std::move(results.data_1_content)});
197  printf("\tData 1(%s) created successfully\n", cfg.data_1_file_name.c_str());
199  storage::binary_content{cfg.block_size,
200  results.block_count,
201  std::move(results.data_2_content)});
202  printf("\tData 2(%s) created successfully\n", cfg.data_2_file_name.c_str());
204  storage::binary_content{cfg.block_size,
205  results.block_count,
206  std::move(results.data_p_content)});
207  printf("\tData p(%s) created successfully\n", cfg.data_p_file_name.c_str());
208  } catch (std::exception const &ex) {
209  DOCA_LOG_ERR("EXCEPTION: %s\n", ex.what());
210 
211  rc = EXIT_FAILURE;
212  }
213 
214  return rc;
215 }
216 
217 namespace {
218 void print_config(gga_offload_sbc_gen_configuration const &cfg) noexcept
219 {
220  printf("configuration: {\n");
221  printf("\tdevice : \"%s\",\n", cfg.device_id.c_str());
222  printf("\toriginal_data_file : \"%s\",\n", cfg.original_data_file_name.c_str());
223  printf("\tblock_size : %u,\n", cfg.block_size);
224  printf("\tec_matrix_type : \"%s\",\n", cfg.ec_matrix_type.c_str());
225  printf("\tdata_1_file : \"%s\",\n", cfg.data_1_file_name.c_str());
226  printf("\tdata_2_file : \"%s\",\n", cfg.data_2_file_name.c_str());
227  printf("\tdata_p_file : \"%s\",\n", cfg.data_p_file_name.c_str());
228  printf("}\n");
229 }
230 
231 gga_offload_sbc_gen_configuration parse_cli_args(int argc, char **argv)
232 {
233  doca_error_t ret;
234  gga_offload_sbc_gen_configuration config{};
235  config.block_size = 4096;
236  config.ec_matrix_type = "vandermonde";
237 
238  ret = doca_argp_init(app_name, &config);
239  if (ret != DOCA_SUCCESS) {
240  throw storage::runtime_error{ret, "Failed to parse CLI args: "s + doca_error_get_name(ret)};
241  }
242 
244  "d",
245  "device",
246  "Device identifier",
249  [](void *value, void *cfg) noexcept {
250  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->device_id =
251  static_cast<char const *>(value);
252  return DOCA_SUCCESS;
253  });
256  nullptr,
257  "original-input-data",
258  "File containing the original data that is represented by the storage",
261  [](void *value, void *cfg) noexcept {
262  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->original_data_file_name =
263  static_cast<char const *>(value);
264  return DOCA_SUCCESS;
265  });
267  nullptr,
268  "block-size",
269  "Size of each block. Default: 4096",
272  [](void *value, void *cfg) noexcept {
273  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->block_size =
274  *static_cast<int *>(value);
275  return DOCA_SUCCESS;
276  });
278  nullptr,
279  "matrix-type",
280  "Type of matrix to use. One of: cauchy, vandermonde Default: vandermonde",
283  [](void *value, void *cfg) noexcept {
284  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->ec_matrix_type =
285  static_cast<char const *>(value);
286  return DOCA_SUCCESS;
287  });
289  nullptr,
290  "data-1",
291  "First half of the data in storage",
294  [](void *value, void *cfg) noexcept {
295  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->data_1_file_name =
296  static_cast<char const *>(value);
297  return DOCA_SUCCESS;
298  });
300  nullptr,
301  "data-2",
302  "Second half of the data in storage",
305  [](void *value, void *cfg) noexcept {
306  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->data_2_file_name =
307  static_cast<char const *>(value);
308  return DOCA_SUCCESS;
309  });
311  nullptr,
312  "data-p",
313  "Parity data (used to perform recovery flow)",
316  [](void *value, void *cfg) noexcept {
317  static_cast<gga_offload_sbc_gen_configuration *>(cfg)->data_p_file_name =
318  static_cast<char const *>(value);
319  return DOCA_SUCCESS;
320  });
321 
322  ret = doca_argp_start(argc, argv);
323  if (ret != DOCA_SUCCESS) {
324  throw storage::runtime_error{ret, "Failed to parse CLI args: "s + doca_error_get_name(ret)};
325  }
326 
327  static_cast<void>(doca_argp_destroy());
328 
329  if (config.block_size % 64 != 0) {
330  // doca_ec requires buffers to be a multiple of 64 bytes of data
331  throw storage::runtime_error{DOCA_ERROR_INVALID_VALUE, "Block size must be a multiple of 64"};
332  }
333  return config;
334 }
335 
336 void pad_input_to_multiple_of_block_size(std::vector<uint8_t> &input, uint32_t block_size)
337 {
338  auto const padding_size = input.size() % block_size;
339  if (padding_size != 0) {
340  auto const block_count = 1 + (input.size() / block_size);
341  input.resize(block_count * block_size, padding_byte);
342  }
343 }
344 
345 LZ4F_preferences_t make_lz4_cfg()
346 {
347  LZ4F_preferences_t cfg{};
348  ::memset(&cfg, 0, sizeof(cfg));
349  cfg.frameInfo.blockSizeID = LZ4F_max64KB;
350  cfg.frameInfo.blockMode = LZ4F_blockIndependent;
351  cfg.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
352  cfg.frameInfo.frameType = LZ4F_frame;
353  cfg.frameInfo.blockChecksumFlag = LZ4F_noBlockChecksum;
354  cfg.compressionLevel = 1;
355  cfg.autoFlush = 1;
356 
357  return cfg;
358 }
359 
360 lz4_context::~lz4_context()
361 {
362  auto const ret = LZ4F_freeCompressionContext(ctx);
363  if (LZ4F_isError(ret)) {
364  DOCA_LOG_ERR("Failed to release LZ4 compression context: %s\n", LZ4F_getErrorName(ret));
365  }
366 }
367 
368 lz4_context::lz4_context() : cfg{make_lz4_cfg()}, ctx{nullptr}
369 {
370  auto const ret = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
371  if (LZ4F_isError(ret)) {
373  "Failed to create LZ4 compression context: "s + LZ4F_getErrorName(ret)};
374  }
375 }
376 
377 uint32_t lz4_context::compress(uint8_t const *in_bytes,
378  uint32_t in_byte_count,
379  uint8_t *out_bytes,
380  uint32_t out_bytes_size)
381 {
382  uint32_t constexpr trailer_byte_count = 4; // doca_compress does not want the 4 byte trailer at the end of the
383  // data
384 
385  // Create header
386  auto const header_len = LZ4F_compressBegin(ctx, out_bytes, out_bytes_size, &cfg);
387  if (LZ4F_isError(header_len)) {
389  "Failed to start compression: "s +
390  LZ4F_getErrorName(static_cast<LZ4F_errorCode_t>(header_len))};
391  }
392 
393  // Skip writing header bytes to any output as doca_compress does not want them
394 
395  // do the compression
396  auto const compressed_byte_count =
397  LZ4F_compressUpdate(ctx, out_bytes, out_bytes_size, in_bytes, in_byte_count, nullptr);
398  if (LZ4F_isError(compressed_byte_count)) {
400  "Failed to compress: "s + LZ4F_getErrorName(static_cast<LZ4F_errorCode_t>(
401  compressed_byte_count))};
402  }
403 
404  // Finalise (may flush any remaining out bytes)
405  auto const final_byte_count = LZ4F_compressEnd(ctx,
406  out_bytes + compressed_byte_count,
407  out_bytes_size - compressed_byte_count,
408  nullptr);
409  if (LZ4F_isError(final_byte_count)) {
412  "Failed to complete compression. Error: "s +
413  LZ4F_getErrorName(static_cast<LZ4F_errorCode_t>(final_byte_count))};
414  }
415 
416  return (compressed_byte_count + final_byte_count) - trailer_byte_count;
417 }
418 
419 gga_offload_sbc_gen_app::~gga_offload_sbc_gen_app()
420 {
421  doca_error_t ret;
422 
423  if (m_ec_task) {
425  m_ec_task = nullptr;
426  }
427 
428  if (m_ec_matrix) {
429  ret = doca_ec_matrix_destroy(m_ec_matrix);
430  if (ret != DOCA_SUCCESS) {
431  DOCA_LOG_ERR("Failed to destroy ec matrix: %s\n", doca_error_get_name(ret));
432  }
433  m_ec_matrix = nullptr;
434  }
435 
436  if (m_ec) {
437  ret = doca_ctx_stop(doca_ec_as_ctx(m_ec));
438  if (ret != DOCA_SUCCESS) {
439  DOCA_LOG_ERR("Failed to stop ec context: %s\n", doca_error_get_name(ret));
440  }
441 
442  ret = doca_ec_destroy(m_ec);
443  if (ret != DOCA_SUCCESS) {
444  DOCA_LOG_ERR("Failed to destroy ec context: %s\n", doca_error_get_name(ret));
445  }
446 
447  m_ec = nullptr;
448  }
449 
450  if (m_pe) {
451  ret = doca_pe_destroy(m_pe);
452  if (ret != DOCA_SUCCESS) {
453  DOCA_LOG_ERR("Failed to destroy progress engine: %s\n", doca_error_get_name(ret));
454  }
455 
456  m_pe = nullptr;
457  }
458 
459  if (m_input_buf) {
460  ret = doca_buf_dec_refcount(m_input_buf, nullptr);
461  if (ret != DOCA_SUCCESS) {
462  DOCA_LOG_ERR("Failed to release doca buf: %s\n", doca_error_get_name(ret));
463  }
464  m_input_buf = nullptr;
465  }
466 
467  if (m_output_buf) {
468  ret = doca_buf_dec_refcount(m_output_buf, nullptr);
469  if (ret != DOCA_SUCCESS) {
470  DOCA_LOG_ERR("Failed to release doca buf: %s\n", doca_error_get_name(ret));
471  }
472  m_output_buf = nullptr;
473  }
474 
475  if (m_buf_inv) {
476  ret = doca_buf_inventory_destroy(m_buf_inv);
477  if (ret != DOCA_SUCCESS) {
478  DOCA_LOG_ERR("Failed to destroy buf inventory: %s\n", doca_error_get_name(ret));
479  }
480 
481  m_buf_inv = nullptr;
482  }
483 
484  if (m_input_mmap) {
485  ret = doca_mmap_stop(m_input_mmap);
486  if (ret != DOCA_SUCCESS) {
487  DOCA_LOG_ERR("Failed to stop input mmap: %s\n", doca_error_get_name(ret));
488  }
489 
490  ret = doca_mmap_destroy(m_input_mmap);
491  if (ret != DOCA_SUCCESS) {
492  DOCA_LOG_ERR("Failed to destroy input mmap: %s\n", doca_error_get_name(ret));
493  }
494 
495  m_input_mmap = nullptr;
496  }
497 
498  if (m_output_mmap) {
499  ret = doca_mmap_stop(m_output_mmap);
500  if (ret != DOCA_SUCCESS) {
501  DOCA_LOG_ERR("Failed to stop output mmap: %s", doca_error_get_name(ret));
502  }
503 
504  ret = doca_mmap_destroy(m_output_mmap);
505  if (ret != DOCA_SUCCESS) {
506  DOCA_LOG_ERR("Failed to destroy output mmap: %s\n", doca_error_get_name(ret));
507  }
508 
509  m_output_mmap = nullptr;
510  }
511 
512  if (m_dev) {
513  ret = doca_dev_close(m_dev);
514  if (ret != DOCA_SUCCESS) {
515  DOCA_LOG_ERR("Failed to close device: %s\n", doca_error_get_name(ret));
516  }
517 
518  m_dev = nullptr;
519  }
520 }
521 
522 gga_offload_sbc_gen_app::gga_offload_sbc_gen_app(std::string const &device_id,
523  std::string const &ec_matrix_type,
524  uint32_t block_size)
525  : m_lz4_ctx{},
526  m_dev{nullptr},
527  m_compressed_bytes_buffer{},
528  m_gga_output_buffer_bytes{},
529  m_input_mmap{nullptr},
530  m_output_mmap{nullptr},
531  m_buf_inv{nullptr},
532  m_input_buf{nullptr},
533  m_output_buf{nullptr},
534  m_pe{nullptr},
535  m_ec{nullptr},
536  m_ec_matrix{nullptr},
537  m_ec_task{nullptr},
538  m_block_size{block_size},
539  m_error_flag{false}
540 {
541  doca_error_t ret;
542 
543  DOCA_LOG_INFO("Open doca_dev: %s", device_id.c_str());
544  m_dev = storage::open_device(device_id);
545 
546  ret = doca_pe_create(&m_pe);
547  if (ret != DOCA_SUCCESS) {
548  throw storage::runtime_error{ret, "Failed to create doca_pe"};
549  }
550 
552  if (ret != DOCA_SUCCESS) {
553  throw storage::runtime_error{ret, "Selected device does not support doca_ec"};
554  }
555 
556  ret = doca_ec_create(m_dev, &m_ec);
557  if (ret != DOCA_SUCCESS) {
558  throw storage::runtime_error{ret, "Failed to create doca_ec"};
559  }
560 
562  m_ec,
563  [](doca_ec_task_create *task, doca_data task_user_data, doca_data ctx_user_data) {},
564  [](doca_ec_task_create *task, doca_data task_user_data, doca_data ctx_user_data) {
565  reinterpret_cast<gga_offload_sbc_gen_app *>(ctx_user_data.ptr)->m_error_flag = true;
566  },
567  num_ec_tasks);
568  if (ret != DOCA_SUCCESS) {
569  throw storage::runtime_error{ret, "Failed to configure doca_ec create task pool"};
570  }
571 
572  static_cast<void>(doca_ctx_set_user_data(doca_ec_as_ctx(m_ec), doca_data{.ptr = this}));
573 
575  if (ret != DOCA_SUCCESS) {
576  throw storage::runtime_error{ret, "Failed to register doca_ec context with progress engine"};
577  }
578 
579  ret = doca_ctx_start(doca_ec_as_ctx(m_ec));
580  if (ret != DOCA_SUCCESS) {
581  throw storage::runtime_error{ret, "Failed to start doca_ec context"};
582  }
583 
584  // Create a matrix that creates one redundancy block per 2 data blocks
585  ret = doca_ec_matrix_create(m_ec, storage::matrix_type_from_string(ec_matrix_type), 2, 1, &m_ec_matrix);
586  if (ret != DOCA_SUCCESS) {
587  throw storage::runtime_error{ret, "Failed to create doca_ec matrix"};
588  }
589 
590  /* LZ4 compression can result in the output being larger than the input in cases of non-compressible data.
591  * To keep things simple this buffer is over allocated so that the LZ4 compress will not fail and the higher
592  * level application logic can check for that and handle the error itself
593  */
594  m_compressed_bytes_buffer.resize(m_block_size * 2, padding_byte);
595  m_gga_output_buffer_bytes.resize(m_block_size, padding_byte);
596 
597  m_input_mmap = storage::make_mmap(m_dev,
598  reinterpret_cast<char *>(m_compressed_bytes_buffer.data()),
599  m_compressed_bytes_buffer.size(),
601 
602  m_output_mmap = storage::make_mmap(m_dev,
603  reinterpret_cast<char *>(m_gga_output_buffer_bytes.data()),
604  m_gga_output_buffer_bytes.size(),
606 
607  m_buf_inv = storage::make_buf_inventory(num_ec_buffers);
608 
609  // Make a buffer that can access any area of the input data
610  ret = doca_buf_inventory_buf_get_by_addr(m_buf_inv,
611  m_input_mmap,
612  m_compressed_bytes_buffer.data(),
613  m_compressed_bytes_buffer.size(),
614  &m_input_buf);
615  if (ret != DOCA_SUCCESS) {
616  throw std::runtime_error{"Unable to init input buffer: "s + doca_error_get_name(ret)};
617  }
618 
619  ret = doca_buf_inventory_buf_get_by_addr(m_buf_inv,
620  m_output_mmap,
621  m_gga_output_buffer_bytes.data(),
622  m_gga_output_buffer_bytes.size(),
623  &m_output_buf);
624  if (ret != DOCA_SUCCESS) {
625  throw std::runtime_error{"Unable to init output buffer: "s + doca_error_get_name(ret)};
626  }
627 
628  ret = doca_ec_task_create_allocate_init(m_ec, m_ec_matrix, m_input_buf, m_output_buf, doca_data{}, &m_ec_task);
629  if (ret != DOCA_SUCCESS) {
630  throw storage::runtime_error{ret, "Failed to get doca_ec task"};
631  }
632 }
633 
634 uint32_t get_out_byte_count(doca_ec_task_create *task)
635 {
636  size_t buf_len = 0;
637  static_cast<void>(doca_buf_get_data_len(doca_ec_task_create_get_rdnc_blocks(task), &buf_len));
638  return buf_len;
639 }
640 
641 gga_offload_sbc_gen_result gga_offload_sbc_gen_app::generate_binary_content(std::vector<uint8_t> input_data)
642 {
643  doca_error_t ret;
644  auto const metadata_header_size = sizeof(storage::compressed_block_header);
645  auto const metadata_trailer_size = sizeof(storage::compressed_block_trailer);
646  auto const metadata_overhead_size = metadata_header_size + metadata_trailer_size;
647 
648  auto const total_block_count = input_data.size() / m_block_size;
649 
650  gga_offload_sbc_gen_result out_data;
651  out_data.block_count = total_block_count;
652  out_data.data_1_content.reserve(input_data.size() / 2);
653  out_data.data_2_content.reserve(input_data.size() / 2);
654  out_data.data_p_content.reserve(input_data.size() / 2);
655 
656  for (uint32_t ii = 0; ii != total_block_count; ++ii) {
657  // Compress the data
658  auto const compresed_size =
659  m_lz4_ctx.compress(input_data.data() + (ii * m_block_size),
660  m_block_size,
661  m_compressed_bytes_buffer.data() + metadata_header_size,
662  m_compressed_bytes_buffer.size() - metadata_overhead_size);
663 
664  if (compresed_size + metadata_overhead_size > m_block_size) {
667  "Data was not compressible enough to be held in internal storage format. Max compressed size of a block is : " +
668  std::to_string(m_block_size - metadata_overhead_size) +
669  ". Block compressed to a size of: " + std::to_string(compresed_size)};
670  }
671 
673  htobe32(m_block_size),
674  htobe32(compresed_size),
675  };
676  std::copy(reinterpret_cast<char const *>(&hdr),
677  reinterpret_cast<char const *>(&hdr) + sizeof(hdr),
678  m_compressed_bytes_buffer.data());
679 
680  // apply padding
681  {
682  ::memset(m_compressed_bytes_buffer.data() + metadata_header_size + compresed_size,
683  0,
684  m_compressed_bytes_buffer.size() -
685  (metadata_header_size + compresed_size + metadata_trailer_size));
686  }
687 
688  // auto half_way_iter = std::begin(m_gga_input_buffer_bytes) + (m_gga_input_buffer_bytes.size() / 2);
689 
690  // TMP: write the full compressed data to both data files, and duplicate data in the party file to
691  // simplify address translation in the DPU
692 
693  // write first compressed half
694  std::copy(m_compressed_bytes_buffer.data(),
695  m_compressed_bytes_buffer.data() + m_block_size,
696  std::back_inserter(out_data.data_1_content));
697  // write second compressed half
698  std::copy(m_compressed_bytes_buffer.data(),
699  m_compressed_bytes_buffer.data() + m_block_size,
700  std::back_inserter(out_data.data_2_content));
701 
702  // generate EC blocks
703  static_cast<void>(doca_buf_set_data(m_input_buf, m_compressed_bytes_buffer.data(), m_block_size));
704  static_cast<void>(doca_buf_reset_data_len(m_output_buf));
705 
707  if (ret != DOCA_SUCCESS) {
708  throw std::runtime_error{"Failed to submit doca_ec task: "s + doca_error_get_name(ret)};
709  }
710 
711  for (;;) {
712  size_t in_flight_count = 0;
713  static_cast<void>(doca_ctx_get_num_inflight_tasks(doca_ec_as_ctx(m_ec), &in_flight_count));
714  if (in_flight_count) {
715  static_cast<void>(doca_pe_progress(m_pe));
716  } else {
717  if (m_error_flag)
718  throw std::runtime_error{"Failed to execute doca_ec task"};
719  else
720  break;
721  }
722  }
723 
724  if (get_out_byte_count(m_ec_task) != (m_block_size / 2)) {
725  throw std::runtime_error{"doca_ec task return invalid result"};
726  }
727 
728  std::copy(std::begin(m_gga_output_buffer_bytes),
729  std::begin(m_gga_output_buffer_bytes) + (m_block_size / 2),
730  std::back_inserter(out_data.data_p_content));
731  std::copy(std::begin(m_gga_output_buffer_bytes),
732  std::begin(m_gga_output_buffer_bytes) + (m_block_size / 2),
733  std::back_inserter(out_data.data_p_content));
734  }
735 
736  DOCA_LOG_TRC("Out data: { block_count: %u, d1_size: %zu, d2_size: %zu, p_size: %zu}",
737  out_data.block_count,
738  out_data.data_1_content.size(),
739  out_data.data_2_content.size(),
740  out_data.data_p_content.size());
741 
742  return out_data;
743 }
744 
745 } // namespace
doca_pe * m_pe
int main(int argc, char **argv)
DOCA_LOG_REGISTER(SBC_GEN)
DOCA_EXPERIMENTAL doca_error_t doca_argp_start(int argc, char **argv)
Parse incoming arguments (cmd line/json).
DOCA_EXPERIMENTAL doca_error_t doca_argp_init(const char *program_name, void *program_config)
Initialize the parser interface.
DOCA_EXPERIMENTAL doca_error_t doca_argp_destroy(void)
ARG Parser destroy.
@ DOCA_ARGP_TYPE_STRING
Definition: doca_argp.h:56
@ DOCA_ARGP_TYPE_INT
Definition: doca_argp.h:57
DOCA_STABLE doca_error_t doca_buf_inventory_destroy(struct doca_buf_inventory *inventory)
Destroy buffer inventory structure.
static doca_error_t doca_buf_inventory_buf_get_by_addr(struct doca_buf_inventory *inventory, struct doca_mmap *mmap, void *addr, size_t len, struct doca_buf **buf)
Allocate single element from buffer inventory and point it to the buffer defined by addr & len argume...
DOCA_STABLE doca_error_t doca_buf_dec_refcount(struct doca_buf *buf, uint16_t *refcount)
Decrease the object reference count by 1, if 0 reached, return the element back to the inventory.
DOCA_STABLE doca_error_t doca_buf_get_data_len(const struct doca_buf *buf, size_t *data_len)
Get buffer's data length.
DOCA_STABLE doca_error_t doca_buf_reset_data_len(struct doca_buf *buf)
DOCA_STABLE doca_error_t doca_buf_set_data(struct doca_buf *buf, void *data, size_t data_len)
DOCA_STABLE doca_error_t doca_ctx_start(struct doca_ctx *ctx)
Finalizes all configurations, and starts the DOCA CTX.
DOCA_STABLE doca_error_t doca_ctx_set_user_data(struct doca_ctx *ctx, union doca_data user_data)
set user data to context
DOCA_STABLE doca_error_t doca_ctx_get_num_inflight_tasks(const struct doca_ctx *ctx, size_t *num_inflight_tasks)
Get number of in flight tasks in a doca context.
DOCA_STABLE doca_error_t doca_ctx_stop(struct doca_ctx *ctx)
Stops the context allowing reconfiguration.
DOCA_STABLE struct doca_devinfo * doca_dev_as_devinfo(const struct doca_dev *dev)
Get local device info from device. This should be useful when wanting to query information about devi...
DOCA_STABLE doca_error_t doca_dev_close(struct doca_dev *dev)
Destroy allocated local device instance.
DOCA_EXPERIMENTAL doca_error_t doca_ec_cap_task_create_is_supported(const struct doca_devinfo *devinfo)
DOCA_EXPERIMENTAL doca_error_t doca_ec_task_create_set_conf(struct doca_ec *ec, doca_ec_task_create_completion_cb_t successful_task_completion_cb, doca_ec_task_create_completion_cb_t error_task_completion_cb, uint32_t num_tasks)
This method sets the create tasks configuration.
DOCA_EXPERIMENTAL doca_error_t doca_ec_destroy(struct doca_ec *ec)
Destroy a DOCA EC instance.
DOCA_EXPERIMENTAL doca_error_t doca_ec_task_create_allocate_init(struct doca_ec *ec, const struct doca_ec_matrix *coding_matrix, const struct doca_buf *original_data_blocks, struct doca_buf *rdnc_blocks, union doca_data user_data, struct doca_ec_task_create **task)
This method allocates and initializes a create task.
DOCA_EXPERIMENTAL doca_error_t doca_ec_create(struct doca_dev *dev, struct doca_ec **ec)
Create a DOCA EC instance.
DOCA_EXPERIMENTAL doca_error_t doca_ec_matrix_destroy(struct doca_ec_matrix *matrix)
Destroy coding matrix.
DOCA_EXPERIMENTAL struct doca_buf * doca_ec_task_create_get_rdnc_blocks(const struct doca_ec_task_create *task)
This method gets the rdnc_blocks buffer of a create task. The rdnc_blocks buffer is a destination buf...
DOCA_EXPERIMENTAL struct doca_task * doca_ec_task_create_as_task(struct doca_ec_task_create *task)
This method converts an EC create task to a doca_task.
DOCA_EXPERIMENTAL doca_error_t doca_ec_matrix_create(struct doca_ec *ec, enum doca_ec_matrix_type type, size_t data_block_count, size_t rdnc_block_count, struct doca_ec_matrix **matrix)
Generate coding matrix for Erasure Code encode i.e. most basic encode matrix. This is necessary for e...
DOCA_EXPERIMENTAL struct doca_ctx * doca_ec_as_ctx(struct doca_ec *ec)
Convert EC instance into context.
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_name(doca_error_t error)
Returns the string representation of an error code name.
@ DOCA_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_ERROR_UNKNOWN
Definition: doca_error.h:39
@ DOCA_SUCCESS
Definition: doca_error.h:38
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
#define DOCA_LOG_TRC(format,...)
Generates a TRACE application log message.
Definition: doca_log.h:513
DOCA_STABLE doca_error_t doca_mmap_destroy(struct doca_mmap *mmap)
Destroy DOCA Memory Map structure.
DOCA_STABLE doca_error_t doca_mmap_stop(struct doca_mmap *mmap)
Stop DOCA Memory Map.
DOCA_STABLE doca_error_t doca_pe_destroy(struct doca_pe *pe)
Destroy doca progress engine.
DOCA_STABLE doca_error_t doca_pe_connect_ctx(struct doca_pe *pe, struct doca_ctx *ctx)
This method connects a context to a progress engine.
DOCA_STABLE doca_error_t doca_task_submit(struct doca_task *task)
Submit a task to a progress engine.
DOCA_STABLE uint8_t doca_pe_progress(struct doca_pe *pe)
Run the progress engine.
DOCA_STABLE doca_error_t doca_pe_create(struct doca_pe **pe)
Creates DOCA progress engine.
DOCA_STABLE void doca_task_free(struct doca_task *task)
Free a task back to where it was allocated from.
@ DOCA_ACCESS_FLAG_LOCAL_READ_WRITE
Definition: doca_types.h:83
static const char * doca_version(void)
Function returning DOCA's (SDK) exact version string.
Definition: doca_version.h:90
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
type value
std::string to_string(storage::control::message_type type)
doca_mmap * make_mmap(doca_dev *dev, char *memory_region, size_t memory_region_size, uint32_t permissions)
Definition: doca_utils.cpp:146
static constexpr value_requirement optional_value
Definition: doca_utils.hpp:228
void write_binary_content_to_file(std::string const &file_name, storage::binary_content const &sbc)
doca_buf_inventory * make_buf_inventory(size_t num_elements)
Definition: doca_utils.cpp:205
void create_doca_logger_backend(void) noexcept
Definition: doca_utils.cpp:471
std::vector< uint8_t > load_file_bytes(std::string const &file_name)
Definition: file_utils.cpp:58
void register_cli_argument(doca_argp_type type, char const *short_name, char const *long_name, char const *description, value_requirement requirement, value_multiplicity multiplicity, doca_argp_param_cb_t callback)
Definition: doca_utils.cpp:413
doca_ec_matrix_type matrix_type_from_string(std::string const &matrix_type)
Definition: doca_utils.cpp:503
static constexpr value_multiplicity single_value
Definition: doca_utils.hpp:230
static constexpr value_requirement required_value
Definition: doca_utils.hpp:227
doca_dev * open_device(std::string const &identifier)
Definition: doca_utils.cpp:43
#define htobe32
Definition: os_utils.hpp:40
#define false
Definition: stdbool.h:22
Convenience type for representing opaque data.
Definition: doca_types.h:56
void * ptr
Definition: doca_types.h:57
struct upf_accel_ctx * ctx