57 using namespace std::string_literals;
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;
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;
75 struct gga_offload_sbc_gen_result {
77 std::vector<uint8_t> data_1_content;
78 std::vector<uint8_t> data_2_content;
79 std::vector<uint8_t> data_p_content;
83 LZ4F_preferences_t
const cfg;
90 lz4_context(lz4_context
const &) =
delete;
92 lz4_context(lz4_context &&) noexcept = delete;
94 lz4_context &operator=(lz4_context const &) = delete;
96 lz4_context &operator=(lz4_context &&) noexcept = delete;
98 uint32_t compress(uint8_t const *in_bytes, uint32_t in_byte_count, uint8_t *out_bytes, uint32_t out_bytes_size);
101 class gga_offload_sbc_gen_app {
103 ~gga_offload_sbc_gen_app();
105 gga_offload_sbc_gen_app() =
delete;
107 gga_offload_sbc_gen_app(std::string
const &device_id, std::string
const &ec_matrix_type, uint32_t block_size);
109 gga_offload_sbc_gen_app(gga_offload_sbc_gen_app
const &) =
delete;
111 gga_offload_sbc_gen_app(gga_offload_sbc_gen_app &&) noexcept = delete;
113 gga_offload_sbc_gen_app &operator=(gga_offload_sbc_gen_app const &) = delete;
115 gga_offload_sbc_gen_app &operator=(gga_offload_sbc_gen_app &&) noexcept = delete;
117 gga_offload_sbc_gen_result generate_binary_content(std::vector<uint8_t> input_data);
120 lz4_context m_lz4_ctx;
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;
131 doca_ec_matrix *m_ec_matrix;
132 doca_ec_task_create *m_ec_task;
133 uint32_t m_block_size;
142 void print_config(gga_offload_sbc_gen_configuration const &
cfg) noexcept;
153 gga_offload_sbc_gen_configuration parse_cli_args(
int argc,
char **argv);
161 void pad_input_to_multiple_of_block_size(std::vector<uint8_t> &
input, uint32_t block_size);
171 int main(
int argc,
char **argv)
173 int rc = EXIT_SUCCESS;
178 auto const cfg = parse_cli_args(argc, argv);
181 gga_offload_sbc_gen_app app{
cfg.device_id,
cfg.ec_matrix_type,
cfg.block_size};
184 pad_input_to_multiple_of_block_size(input_data,
cfg.block_size);
186 printf(
"Processing data...");
187 auto const results = app.generate_binary_content(input_data);
189 printf(
"Output info:\n");
190 printf(
"\tBlock size: %u\n",
cfg.block_size);
191 printf(
"\tOut block count: %u\n", 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());
201 std::move(results.data_2_content)});
202 printf(
"\tData 2(%s) created successfully\n",
cfg.data_2_file_name.c_str());
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) {
218 void print_config(gga_offload_sbc_gen_configuration
const &
cfg) noexcept
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());
231 gga_offload_sbc_gen_configuration parse_cli_args(
int argc,
char **argv)
234 gga_offload_sbc_gen_configuration config{};
235 config.block_size = 4096;
236 config.ec_matrix_type =
"vandermonde";
249 [](
void *
value,
void *
cfg) noexcept {
250 static_cast<gga_offload_sbc_gen_configuration *
>(
cfg)->device_id =
251 static_cast<char const *
>(
value);
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);
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);
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);
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);
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);
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);
329 if (config.block_size % 64 != 0) {
336 void pad_input_to_multiple_of_block_size(std::vector<uint8_t> &
input, uint32_t block_size)
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);
345 LZ4F_preferences_t make_lz4_cfg()
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;
360 lz4_context::~lz4_context()
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));
368 lz4_context::lz4_context() :
cfg{make_lz4_cfg()},
ctx{nullptr}
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)};
377 uint32_t lz4_context::compress(uint8_t
const *in_bytes,
378 uint32_t in_byte_count,
380 uint32_t out_bytes_size)
382 uint32_t constexpr trailer_byte_count = 4;
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))};
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))};
405 auto const final_byte_count = LZ4F_compressEnd(
ctx,
406 out_bytes + compressed_byte_count,
407 out_bytes_size - compressed_byte_count,
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))};
416 return (compressed_byte_count + final_byte_count) - trailer_byte_count;
419 gga_offload_sbc_gen_app::~gga_offload_sbc_gen_app()
433 m_ec_matrix =
nullptr;
464 m_input_buf =
nullptr;
472 m_output_buf =
nullptr;
495 m_input_mmap =
nullptr;
509 m_output_mmap =
nullptr;
522 gga_offload_sbc_gen_app::gga_offload_sbc_gen_app(std::string
const &device_id,
523 std::string
const &ec_matrix_type,
527 m_compressed_bytes_buffer{},
528 m_gga_output_buffer_bytes{},
529 m_input_mmap{nullptr},
530 m_output_mmap{nullptr},
532 m_input_buf{nullptr},
533 m_output_buf{nullptr},
536 m_ec_matrix{nullptr},
538 m_block_size{block_size},
565 reinterpret_cast<gga_offload_sbc_gen_app *
>(ctx_user_data.
ptr)->m_error_flag =
true;
594 m_compressed_bytes_buffer.resize(m_block_size * 2, padding_byte);
595 m_gga_output_buffer_bytes.resize(m_block_size, padding_byte);
598 reinterpret_cast<char *
>(m_compressed_bytes_buffer.data()),
599 m_compressed_bytes_buffer.size(),
603 reinterpret_cast<char *
>(m_gga_output_buffer_bytes.data()),
604 m_gga_output_buffer_bytes.size(),
612 m_compressed_bytes_buffer.data(),
613 m_compressed_bytes_buffer.size(),
621 m_gga_output_buffer_bytes.data(),
622 m_gga_output_buffer_bytes.size(),
634 uint32_t get_out_byte_count(doca_ec_task_create *task)
641 gga_offload_sbc_gen_result gga_offload_sbc_gen_app::generate_binary_content(std::vector<uint8_t> input_data)
646 auto const metadata_overhead_size = metadata_header_size + metadata_trailer_size;
648 auto const total_block_count = input_data.size() / m_block_size;
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);
656 for (uint32_t ii = 0; ii != total_block_count; ++ii) {
658 auto const compresed_size =
659 m_lz4_ctx.compress(input_data.data() + (ii * m_block_size),
661 m_compressed_bytes_buffer.data() + metadata_header_size,
662 m_compressed_bytes_buffer.size() - metadata_overhead_size);
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 : " +
669 ". Block compressed to a size of: " +
std::to_string(compresed_size)};
676 std::copy(
reinterpret_cast<char const *
>(&hdr),
677 reinterpret_cast<char const *
>(&hdr) +
sizeof(hdr),
678 m_compressed_bytes_buffer.data());
682 ::memset(m_compressed_bytes_buffer.data() + metadata_header_size + compresed_size,
684 m_compressed_bytes_buffer.size() -
685 (metadata_header_size + compresed_size + metadata_trailer_size));
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));
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));
703 static_cast<void>(
doca_buf_set_data(m_input_buf, m_compressed_bytes_buffer.data(), m_block_size));
712 size_t in_flight_count = 0;
714 if (in_flight_count) {
718 throw std::runtime_error{
"Failed to execute doca_ec task"};
724 if (get_out_byte_count(m_ec_task) != (m_block_size / 2)) {
725 throw std::runtime_error{
"doca_ec task return invalid result"};
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));
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());
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_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
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
#define DOCA_LOG_TRC(format,...)
Generates a TRACE application log message.
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
static const char * doca_version(void)
Function returning DOCA's (SDK) exact version string.
const struct ip_frag_config * cfg
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)
static constexpr value_requirement optional_value
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)
void create_doca_logger_backend(void) noexcept
std::vector< uint8_t > load_file_bytes(std::string const &file_name)
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)
doca_ec_matrix_type matrix_type_from_string(std::string const &matrix_type)
static constexpr value_multiplicity single_value
static constexpr value_requirement required_value
doca_dev * open_device(std::string const &identifier)
Convenience type for representing opaque data.
struct upf_accel_ctx * ctx