Updated MVTVM layer of the driver to call TVM C runtime API functions, instead on the TVMDP wrapper library APIs.
Drop all dependencies on TVMDP wrapper library. Signed-off-by: Srikanth Yalavarthi <[email protected]> --- doc/guides/mldevs/cnxk.rst | 35 +- drivers/ml/cnxk/cnxk_ml_io.h | 20 +- drivers/ml/cnxk/cnxk_ml_ops.c | 12 +- drivers/ml/cnxk/meson.build | 14 +- drivers/ml/cnxk/mvtvm_ml_dev.h | 3 - drivers/ml/cnxk/mvtvm_ml_model.c | 638 ++++++++++++++++++++++++++++--- drivers/ml/cnxk/mvtvm_ml_model.h | 81 +++- drivers/ml/cnxk/mvtvm_ml_ops.c | 440 ++++++++++++++------- drivers/ml/cnxk/mvtvm_ml_ops.h | 5 +- drivers/ml/cnxk/mvtvm_ml_stubs.c | 17 - drivers/ml/cnxk/mvtvm_ml_stubs.h | 2 - 11 files changed, 985 insertions(+), 282 deletions(-) diff --git a/doc/guides/mldevs/cnxk.rst b/doc/guides/mldevs/cnxk.rst index fc1bcd9cdb4..17e58d81c0b 100644 --- a/doc/guides/mldevs/cnxk.rst +++ b/doc/guides/mldevs/cnxk.rst @@ -111,13 +111,13 @@ on CPU cores or hardware accelerators. .. note:: - DPDK CNXK ML driver requires TVM version 0.10.0 + DPDK CNXK ML driver requires TVM version legacy-v0.19.post branch. .. code-block:: console git clone https://github.com/apache/tvm.git cd tvm - git checkout v0.11.0 -b v0.11.0 + git checkout legacy-v0.19.post -b legacy-v0.19.post git submodule update --init cmake -S ./ -B build \ -DCMAKE_INSTALL_PREFIX=<install_prefix> \ @@ -135,37 +135,6 @@ When cross-compiling, more options must be provided to CMake: -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY -TVMDP -~~~~~ - - Marvell's `TVM Dataplane Library <https://github.com/MarvellEmbeddedProcessors/tvmdp>`_ - works as an interface between TVM runtime and DPDK drivers. - TVMDP library provides a simplified C interface - for TVM's runtime based on C++. - -.. note:: - - TVMDP library is dependent on TVM, dlpack, jansson and dmlc-core libraries. - -.. code-block:: console - - git clone https://github.com/MarvellEmbeddedProcessors/tvmdp.git - cd tvmdp - git checkout main - cmake -S ./ -B build \ - -DCMAKE_INSTALL_PREFIX=<install_prefix> \ - -DBUILD_SHARED_LIBS=ON - make -C build - make -C build install - -When cross-compiling, more options must be provided to CMake: - -.. code-block:: console - - -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \ - -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \ - -DCMAKE_FIND_ROOT_PATH=<install_prefix> - libarchive ~~~~~~~~~~ diff --git a/drivers/ml/cnxk/cnxk_ml_io.h b/drivers/ml/cnxk/cnxk_ml_io.h index 83329c237aa..17f5b4619f0 100644 --- a/drivers/ml/cnxk/cnxk_ml_io.h +++ b/drivers/ml/cnxk/cnxk_ml_io.h @@ -6,7 +6,7 @@ #define _CNXK_ML_IO_H_ #ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM -#include <tvmdp.h> +#include <dlpack/dlpack.h> #endif #include <rte_mldev.h> @@ -16,7 +16,7 @@ /* Maximum number of layers per model */ #ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM -#define ML_CNXK_MODEL_MAX_LAYERS TVMDP_MODEL_LAYERS_MAX +#define ML_CNXK_MODEL_MAX_LAYERS 128 #else #define ML_CNXK_MODEL_MAX_LAYERS 1 #endif @@ -41,7 +41,7 @@ struct cnxk_ml_io { /* Number of dimensions in shape */ uint32_t nb_dims; - /* Shape of input */ + /* Shape */ uint32_t shape[ML_CNXK_MODEL_MAX_DIMS]; /* Number of elements */ @@ -58,6 +58,20 @@ struct cnxk_ml_io { /* Zero point */ int64_t zero_point; + +#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM + /* Shape - int64_t */ + int64_t shape_i64[ML_CNXK_MODEL_MAX_DIMS]; + + /* Data type */ + DLDataType datatype; + + /* Model data type */ + DLDataType model_datatype; + + /* Device */ + DLDevice device; +#endif }; /* Model / Layer IO structure */ diff --git a/drivers/ml/cnxk/cnxk_ml_ops.c b/drivers/ml/cnxk/cnxk_ml_ops.c index 9958945670a..938982c7556 100644 --- a/drivers/ml/cnxk/cnxk_ml_ops.c +++ b/drivers/ml/cnxk/cnxk_ml_ops.c @@ -634,10 +634,6 @@ cnxk_ml_dev_configure(struct rte_ml_dev *dev, const struct rte_ml_dev_config *co } } - ret = mvtvm_ml_dev_configure(cnxk_mldev, conf); - if (ret != 0) - goto error; - /* Set device capabilities */ if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_PCI) cnxk_mldev->max_nb_layers = @@ -705,9 +701,6 @@ cnxk_ml_dev_close(struct rte_ml_dev *dev) /* Un-initialize xstats */ cnxk_ml_xstats_uninit(cnxk_mldev); - if (mvtvm_ml_dev_close(cnxk_mldev) != 0) - plt_err("Failed to close MVTVM ML Device"); - if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_PCI) { if (cn10k_ml_dev_close(cnxk_mldev) != 0) plt_err("Failed to close CN10K ML Device"); @@ -1234,7 +1227,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u model->layer[layer_id].glow.ocm_map.scratch_pages); #ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM } else { - for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) { + for (layer_id = 0; layer_id < model->nb_layers; layer_id++) { if (model->layer[layer_id].type == ML_CNXK_LAYER_TYPE_MRVL) { total_wb_pages = total_wb_pages + model->layer[layer_id].glow.ocm_map.wb_pages; @@ -1256,8 +1249,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u model->layer[layer_id].glow.ocm_map.scratch_pages); #ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM } else { - for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; - layer_id++) { + for (layer_id = 0; layer_id < model->nb_layers; layer_id++) { if (model->layer[layer_id].type == ML_CNXK_LAYER_TYPE_MRVL) { plt_ml_dbg( "layer_id = %u: wb_pages = %u, scratch_pages = %u", diff --git a/drivers/ml/cnxk/meson.build b/drivers/ml/cnxk/meson.build index ef7e21d7476..5f078bd4fd7 100644 --- a/drivers/ml/cnxk/meson.build +++ b/drivers/ml/cnxk/meson.build @@ -19,30 +19,24 @@ if not jansson_dep.found() enable_mvtvm = false endif -dlpack_dep = dependency('dlpack', method: 'cmake', required: false, cmake_args: 'CONFIG') +dlpack_dep = dependency('dlpack', method: 'cmake', required: false) if not dlpack_dep.found() message('drivers/ml/cnxk: dlpack not found') enable_mvtvm = false endif -dmlc_dep = dependency('dmlc', method: 'cmake', required: false, cmake_args: 'CONFIG') +dmlc_dep = dependency('dmlc', method: 'cmake', required: false) if not dmlc_dep.found() message('drivers/ml/cnxk: dmlc not found') enable_mvtvm = false endif -tvm_dep = dependency('tvm', method: 'cmake', required: false, cmake_args: 'CONFIG', modules : ['tvm::tvm_runtime']) +tvm_dep = dependency('tvm', method: 'cmake', required: false, modules : ['tvm::tvm_runtime']) if not tvm_dep.found() message('drivers/ml/cnxk: tvm_runtime not found') enable_mvtvm = false endif -tvmdp_dep = dependency('tvmdp', method: 'pkg-config', required: false) -if not tvmdp_dep.found() - message('drivers/ml/cnxk: tvmdp not found') - enable_mvtvm = false -endif - sources = files( 'cn10k_ml_dev.c', 'cn10k_ml_ops.c', @@ -68,10 +62,10 @@ sources += files( ) ext_deps += jansson_dep +ext_deps += libarchive ext_deps += dlpack_dep ext_deps += dmlc_dep ext_deps += tvm_dep -ext_deps += tvmdp_dep stdcpp_dep = cc.find_library('stdc++', required: true) if not cc.links(min_c_code, dependencies: stdcpp_dep) error('broken dependency, "libstdc++"') diff --git a/drivers/ml/cnxk/mvtvm_ml_dev.h b/drivers/ml/cnxk/mvtvm_ml_dev.h index 6922c193372..05e30f094cd 100644 --- a/drivers/ml/cnxk/mvtvm_ml_dev.h +++ b/drivers/ml/cnxk/mvtvm_ml_dev.h @@ -19,9 +19,6 @@ extern struct rte_ml_dev_ops cnxk_ml_ops; /* Maximum number of descriptors per queue-pair */ #define ML_MVTVM_MAX_DESC_PER_QP 1024 -/* Maximum number of inputs / outputs per model */ -#define ML_MVTVM_MAX_INPUT_OUTPUT 32 - /* Maximum number of segments for IO data */ #define ML_MVTVM_MAX_SEGMENTS 1 diff --git a/drivers/ml/cnxk/mvtvm_ml_model.c b/drivers/ml/cnxk/mvtvm_ml_model.c index 4c7aa906da0..e1946607629 100644 --- a/drivers/ml/cnxk/mvtvm_ml_model.c +++ b/drivers/ml/cnxk/mvtvm_ml_model.c @@ -2,6 +2,12 @@ * Copyright (c) 2023 Marvell. */ +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + #include <archive.h> #include <archive_entry.h> @@ -23,6 +29,7 @@ enum cnxk_ml_model_type mvtvm_ml_model_type_get(struct rte_ml_model_params *params) { bool object_found[ML_MVTVM_MODEL_OBJECT_MAX] = {false, false, false}; + enum cnxk_ml_model_type model_type; struct archive_entry *entry; struct archive *a; uint8_t i; @@ -33,9 +40,10 @@ mvtvm_ml_model_type_get(struct rte_ml_model_params *params) archive_read_support_filter_all(a); archive_read_support_format_all(a); + model_type = ML_CNXK_MODEL_TYPE_UNKNOWN; ret = archive_read_open_memory(a, params->addr, params->size); if (ret != ARCHIVE_OK) - return ML_CNXK_MODEL_TYPE_UNKNOWN; + goto cleanup; /* Parse buffer for available objects */ while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { @@ -51,11 +59,18 @@ mvtvm_ml_model_type_get(struct rte_ml_model_params *params) for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) { if (!object_found[i]) { plt_err("Object %s not found in archive!", mvtvm_object_list[i]); - return ML_CNXK_MODEL_TYPE_INVALID; + model_type = ML_CNXK_MODEL_TYPE_INVALID; + goto cleanup; } } - return ML_CNXK_MODEL_TYPE_TVM; + model_type = ML_CNXK_MODEL_TYPE_TVM; + +cleanup: + archive_read_close(a); + archive_read_free(a); + + return model_type; } int @@ -67,14 +82,18 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo uint8_t i; int ret; + memset(object, 0, ML_MVTVM_MODEL_OBJECT_MAX * sizeof(*object)); + /* Open archive */ a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); ret = archive_read_open_memory(a, params->addr, params->size); - if (ret != ARCHIVE_OK) - return archive_errno(a); + if (ret != ARCHIVE_OK) { + ret = archive_errno(a); + goto cleanup; + } /* Read archive */ while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { @@ -84,11 +103,16 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo memcpy(object[i].name, mvtvm_object_list[i], RTE_ML_STR_MAX); object[i].size = archive_entry_size(entry); object[i].buffer = rte_malloc(NULL, object[i].size, 0); + if (object[i].buffer == NULL) { + ret = -ENOMEM; + goto error; + } if (archive_read_data(a, object[i].buffer, object[i].size) != object[i].size) { plt_err("Failed to read object from model archive: %s", object[i].name); + ret = -EINVAL; goto error; } object_found[i] = true; @@ -101,17 +125,24 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) { if (!object_found[i]) { plt_err("Object %s not found in archive!", mvtvm_object_list[i]); + ret = -EINVAL; goto error; } } - return 0; + ret = 0; + goto cleanup; error: for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) { - rte_free(object[i].buffer); + if (object[i].buffer != NULL) + rte_free(object[i].buffer); } - return -EINVAL; +cleanup: + archive_read_close(a); + archive_read_free(a); + + return ret; } int @@ -119,12 +150,12 @@ mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, { uint16_t i; - for (i = 0; i < model->mvtvm.metadata.model.nb_layers; i++) { + for (i = 0; i < model->nb_layers; i++) { if (strcmp(model->layer[i].name, layer_name) == 0) break; } - if (i == model->mvtvm.metadata.model.nb_layers) { + if (i == model->nb_layers) { plt_err("Invalid layer name: %s", layer_name); return -EINVAL; } @@ -139,6 +170,506 @@ mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, return 0; } +static void +mvtvm_ml_param_names_free(struct mvtvm_ml_param_names *param_names) +{ + size_t i; + + for (i = 0; i < param_names->count; i++) + free(param_names->name[i]); + + free(param_names->name); + param_names->name = NULL; + param_names->count = 0; +} + +static int +mvtvm_ml_blob_read_u64(const uint8_t *blob, size_t blob_size, size_t *offset, uint64_t *value) +{ + if (*offset + sizeof(*value) > blob_size) + return -EINVAL; + + memcpy(value, blob + *offset, sizeof(*value)); + *offset += sizeof(*value); + + return 0; +} + +static int +mvtvm_ml_param_names_parse(const uint8_t *blob, size_t blob_size, + struct mvtvm_ml_param_names *param_names) +{ + uint64_t magic = 0; + uint64_t reserved = 0; + uint64_t count = 0; + size_t offset = 0; + int ret; + size_t i; + + memset(param_names, 0, sizeof(*param_names)); + + ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &magic); + if (ret != 0) + return ret; + + if (magic != TVM_NDARRAY_LIST_MAGIC) + return -EINVAL; + + ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &reserved); + if (ret != 0) + return ret; + + ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &count); + if (ret != 0) + return ret; + + if (count > SIZE_MAX / sizeof(*param_names->name)) + return -EINVAL; + + param_names->name = calloc(count, sizeof(*param_names->name)); + if (count != 0 && param_names->name == NULL) + return -ENOMEM; + + param_names->count = count; + for (i = 0; i < count; i++) { + uint64_t name_len = 0; + + ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &name_len); + if (ret != 0) + goto error; + + if (name_len == SIZE_MAX) { + ret = -EINVAL; + goto error; + } + + if (offset + name_len > blob_size) { + ret = -EINVAL; + goto error; + } + + param_names->name[i] = calloc(name_len + 1, 1); + if (param_names->name[i] == NULL) { + ret = -ENOMEM; + goto error; + } + + memcpy(param_names->name[i], blob + offset, name_len); + offset += name_len; + } + + return 0; + +error: + mvtvm_ml_param_names_free(param_names); + return ret; +} + +static int +mvtvm_ml_dtype_parse(const char *dtype_str, DLDataType *dtype) +{ + const char *lanes_str; + char base[32] = {0}; + long bits; + long lanes = 1; + + if (dtype_str == NULL || dtype == NULL) + return -EINVAL; + + lanes_str = strchr(dtype_str, 'x'); + if (lanes_str != NULL) { + size_t base_len = lanes_str - dtype_str; + + if (base_len >= sizeof(base)) + return -EINVAL; + memcpy(base, dtype_str, base_len); + lanes = strtol(lanes_str + 1, NULL, 10); + if (lanes <= 0 || lanes > UINT16_MAX) + return -EINVAL; + } else { + snprintf(base, sizeof(base), "%s", dtype_str); + } + + memset(dtype, 0, sizeof(*dtype)); + dtype->lanes = (uint16_t)lanes; + + if (strncmp(base, "int", 3) == 0) { + bits = strtol(base + 3, NULL, 10); + dtype->code = kDLInt; + } else if (strncmp(base, "uint", 4) == 0) { + bits = strtol(base + 4, NULL, 10); + dtype->code = kDLUInt; + } else if (strncmp(base, "float", 5) == 0) { + bits = strtol(base + 5, NULL, 10); + dtype->code = kDLFloat; + } else if (strncmp(base, "bfloat", 6) == 0) { + bits = strtol(base + 6, NULL, 10); + dtype->code = kDLBfloat; + } else if (strcmp(base, "bool") == 0) { + bits = 1; + dtype->code = kDLUInt; + } else { + return -EINVAL; + } + + if (bits <= 0 || bits > UINT8_MAX) + return -EINVAL; + + dtype->bits = (uint8_t)bits; + + return 0; +} + +static int +mvtvm_ml_model_io_set(struct cnxk_ml_io *io, const char *name, json_t *shape, const char *dtype_str, + DLDevice device) +{ + size_t i; + int ret; + + memset(io, 0, sizeof(*io)); + if (name != NULL) + snprintf(io->name, sizeof(io->name), "%s", name); + + if (!json_is_array(shape)) + return -EINVAL; + + io->nb_dims = json_array_size(shape); + if (io->nb_dims > ML_CNXK_MODEL_MAX_DIMS) + return -ENOTSUP; + + for (i = 0; i < (size_t)io->nb_dims; i++) { + json_t *dim = json_array_get(shape, i); + + if (!json_is_integer(dim)) + return -EINVAL; + io->shape_i64[i] = json_integer_value(dim); + } + + ret = mvtvm_ml_dtype_parse(dtype_str, &io->datatype); + if (ret != 0) + return ret; + + io->model_datatype = io->datatype; + io->scale = 1.0f; + io->device = device; + + return 0; +} + +static int +mvtvm_ml_json_graph_get_arrays(json_t *json_parsed, json_t **nodes, json_t **arg_nodes, + json_t **heads, json_t **node_row_ptr, json_t **shape_values, + json_t **dtype_values) +{ + json_t *attrs; + json_t *shape_attr; + json_t *dtype_attr; + + *nodes = json_object_get(json_parsed, "nodes"); + *arg_nodes = json_object_get(json_parsed, "arg_nodes"); + *heads = json_object_get(json_parsed, "heads"); + *node_row_ptr = json_object_get(json_parsed, "node_row_ptr"); + attrs = json_object_get(json_parsed, "attrs"); + + if (!json_is_array(*nodes) || !json_is_array(*arg_nodes) || !json_is_array(*heads) || + !json_is_array(*node_row_ptr) || !json_is_object(attrs)) + return -EINVAL; + + if (json_array_size(*node_row_ptr) != json_array_size(*nodes) + 1) + return -EINVAL; + + shape_attr = json_object_get(attrs, "shape"); + dtype_attr = json_object_get(attrs, "dltype"); + if (!json_is_array(shape_attr) || json_array_size(shape_attr) < 2 || + !json_is_array(dtype_attr) || json_array_size(dtype_attr) < 2) + return -EINVAL; + + *shape_values = json_array_get(shape_attr, 1); + *dtype_values = json_array_get(dtype_attr, 1); + + if (!json_is_array(*shape_values) || !json_is_array(*dtype_values)) + return -EINVAL; + + return 0; +} + +int +mvtvm_ml_model_json_parse(struct cnxk_ml_model *model) +{ + struct mvtvm_ml_param_names param_names; + json_error_t json_error; + json_t *json_parsed; + json_t *json_nodes; + json_t *json_arg_nodes; + json_t *json_heads; + json_t *json_node_row_ptr; + json_t *json_shape_values; + json_t *json_dtype_values; + uint16_t nb_mrvl_layers; + uint16_t nb_llvm_layers; + DLDevice device; + int ret; + size_t i; + size_t j; + + /* Parse param names from params buffer */ + ret = mvtvm_ml_param_names_parse(model->mvtvm.params.buffer, model->mvtvm.params.size, + ¶m_names); + if (ret != 0) + return ret; + + /* Load JSON graph (single load for both stages) */ + json_parsed = json_loadb((const char *)model->mvtvm.json.buffer, model->mvtvm.json.size, 0, + &json_error); + if (json_parsed == NULL) { + mvtvm_ml_param_names_free(¶m_names); + plt_err("TVM runtime: Failed to parse JSON graph, model_id = %u", model->model_id); + return -EINVAL; + } + + /* Parse nodes to extract layer info */ + json_nodes = json_object_get(json_parsed, "nodes"); + if (!json_is_array(json_nodes)) { + ret = -EINVAL; + plt_err("TVM runtime: Failed to parse JSON nodes, model_id = %u, error = %d", + model->model_id, ret); + goto error; + } + + model->nb_layers = 0; + nb_mrvl_layers = 0; + nb_llvm_layers = 0; + for (i = 0; i < json_array_size(json_nodes); i++) { + json_t *node = json_array_get(json_nodes, i); + json_t *op = json_object_get(node, "op"); + json_t *name; + json_t *attrs; + json_t *compiler; + + if (!json_is_string(op) || strcmp(json_string_value(op), "tvm_op") != 0) + continue; + + if (model->nb_layers >= ML_CNXK_MODEL_MAX_LAYERS) { + ret = -ENOTSUP; + plt_err("TVM runtime: Number of layers exceeds maximum (%u), model_id = %u, error = %d", + ML_CNXK_MODEL_MAX_LAYERS, model->model_id, ret); + goto error; + } + + name = json_object_get(node, "name"); + if (!json_is_string(name)) { + ret = -EINVAL; + plt_err("TVM runtime: Failed to parse JSON node name, model_id = %u, error = %d", + model->model_id, ret); + goto error; + } + + if (json_string_value(name) != NULL) + snprintf(model->layer[model->nb_layers].name, + sizeof(model->layer[model->nb_layers].name), "%s", + json_string_value(name)); + else + snprintf(model->layer[model->nb_layers].name, + sizeof(model->layer[model->nb_layers].name), "tvm_layer_%u", + model->nb_layers); + + attrs = json_object_get(node, "attrs"); + compiler = json_is_object(attrs) ? json_object_get(attrs, "Compiler") : NULL; + if (json_is_string(compiler)) { + if (strcmp(json_string_value(compiler), "mrvl") == 0 || + strcmp(json_string_value(compiler), "MRVL") == 0) { + model->layer[model->nb_layers].type = ML_CNXK_LAYER_TYPE_MRVL; + nb_mrvl_layers++; + } else { + model->layer[model->nb_layers].type = ML_CNXK_LAYER_TYPE_UNKNOWN; + } + } else { + model->layer[model->nb_layers].type = ML_CNXK_LAYER_TYPE_LLVM; + nb_llvm_layers++; + } + model->nb_layers++; + } + + /* Set model fields */ + snprintf(model->name, sizeof(model->name), "tvm_model_%u", model->model_id); + model->batch_size = 1; + + /* Validate layer counts */ + if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 0)) { + plt_err("Invalid model, nb_llvm_layers = %u, nb_mrvl_layers = %u", nb_llvm_layers, + nb_mrvl_layers); + ret = -EINVAL; + goto error; + } + + if (nb_llvm_layers + nb_mrvl_layers != model->nb_layers) { + plt_err("Invalid model, nb_llvm_layers = %u, nb_mrvl_layers = %u, nb_layers = %u", + nb_llvm_layers, nb_mrvl_layers, model->nb_layers); + ret = -EINVAL; + goto error; + } + + /* Set model subtype */ + if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 1)) + model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_MRVL; + else if ((nb_llvm_layers > 0) && (nb_mrvl_layers == 0)) + model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_LLVM; + else + model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_HYBRID; + + /* Parse I/O info from the same JSON graph */ + device.device_type = kDLCPU; + device.device_id = 0; + + ret = mvtvm_ml_json_graph_get_arrays(json_parsed, &json_nodes, &json_arg_nodes, &json_heads, + &json_node_row_ptr, &json_shape_values, + &json_dtype_values); + if (ret == 0) { + model->mvtvm.info.nb_inputs = 0; + model->mvtvm.info.nb_outputs = 0; + + for (i = 0; i < json_array_size(json_arg_nodes); i++) { + json_t *arg_node_idx = json_array_get(json_arg_nodes, i); + json_t *node; + json_t *shape; + json_t *dtype; + json_t *name; + json_int_t node_id; + + if (!json_is_integer(arg_node_idx)) { + ret = -EINVAL; + break; + } + + node_id = json_integer_value(arg_node_idx); + node = json_array_get(json_nodes, node_id); + shape = json_array_get(json_shape_values, node_id); + dtype = json_array_get(json_dtype_values, node_id); + name = json_object_get(node, "name"); + if (!json_is_object(node) || !json_is_array(shape) || + !json_is_string(dtype) || !json_is_string(name)) { + ret = -EINVAL; + break; + } + + for (j = 0; j < param_names.count; j++) { + if (strcmp(param_names.name[j], json_string_value(name)) == 0) + break; + } + + if (j < param_names.count) + continue; + + if (model->mvtvm.info.nb_inputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) { + ret = -ENOTSUP; + break; + } + + ret = mvtvm_ml_model_io_set( + &model->mvtvm.info.input[model->mvtvm.info.nb_inputs], + json_string_value(name), shape, json_string_value(dtype), device); + if (ret != 0) + break; + + model->mvtvm.info.nb_inputs++; + } + + for (i = 0; ret == 0 && i < json_array_size(json_heads); i++) { + json_t *head = json_array_get(json_heads, i); + json_t *node; + json_t *shape; + json_t *dtype; + json_t *name; + json_t *node_id_json; + json_t *output_idx_json; + json_t *entry_base_json; + json_t *entry_limit_json; + json_int_t node_id; + json_int_t output_idx; + json_int_t entry_base; + json_int_t entry_limit; + size_t entry_id; + + if (!json_is_array(head) || json_array_size(head) < 2) { + ret = -EINVAL; + break; + } + + node_id_json = json_array_get(head, 0); + output_idx_json = json_array_get(head, 1); + if (!json_is_integer(node_id_json) || !json_is_integer(output_idx_json)) { + ret = -EINVAL; + break; + } + + node_id = json_integer_value(node_id_json); + output_idx = json_integer_value(output_idx_json); + if (node_id < 0 || output_idx < 0) { + ret = -EINVAL; + break; + } + + node = json_array_get(json_nodes, (size_t)node_id); + entry_base_json = json_array_get(json_node_row_ptr, (size_t)node_id); + entry_limit_json = json_array_get(json_node_row_ptr, (size_t)node_id + 1); + if (!json_is_object(node) || !json_is_integer(entry_base_json) || + !json_is_integer(entry_limit_json)) { + ret = -EINVAL; + break; + } + + entry_base = json_integer_value(entry_base_json); + entry_limit = json_integer_value(entry_limit_json); + if (entry_base < 0 || entry_limit < entry_base) { + ret = -EINVAL; + break; + } + + if (output_idx >= (entry_limit - entry_base)) { + ret = -EINVAL; + break; + } + + entry_id = (size_t)entry_base + (size_t)output_idx; + shape = json_array_get(json_shape_values, entry_id); + dtype = json_array_get(json_dtype_values, entry_id); + name = json_object_get(node, "name"); + if (!json_is_array(shape) || !json_is_string(dtype) || + !json_is_string(name)) { + ret = -EINVAL; + break; + } + + if (model->mvtvm.info.nb_outputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) { + ret = -ENOTSUP; + break; + } + + ret = mvtvm_ml_model_io_set( + &model->mvtvm.info.output[model->mvtvm.info.nb_outputs], + json_string_value(name), shape, json_string_value(dtype), device); + if (ret != 0) + break; + + model->mvtvm.info.nb_outputs++; + } + } + + if (ret != 0) + plt_err("TVM runtime: Failed to get metadata, model_id = %u, error = %d", + model->model_id, ret); + + json_decref(json_parsed); + mvtvm_ml_param_names_free(¶m_names); + return ret; + +error: + json_decref(json_parsed); + mvtvm_ml_param_names_free(¶m_names); + return ret; +} + static enum rte_ml_io_type mvtvm_ml_io_type_map(DLDataType dltype) { @@ -185,32 +716,27 @@ mvtvm_ml_io_type_map(DLDataType dltype) void mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model) { - struct tvmdp_model_metadata *metadata; int32_t i; - int32_t j; + uint32_t j; if (model->subtype == ML_CNXK_MODEL_SUBTYPE_TVM_MRVL) goto tvm_mrvl_model; - metadata = &model->mvtvm.metadata; - /* Inputs, set for layer_id = 0 */ - model->mvtvm.info.nb_inputs = metadata->model.num_input; model->mvtvm.info.total_input_sz_d = 0; model->mvtvm.info.total_input_sz_q = 0; - for (i = 0; i < metadata->model.num_input; i++) { - rte_strscpy(model->mvtvm.info.input[i].name, metadata->input[i].name, - TVMDP_NAME_STRLEN); + for (i = 0; i < model->mvtvm.info.nb_inputs; i++) { model->mvtvm.info.input[i].dtype = - mvtvm_ml_io_type_map(metadata->input[i].datatype); + mvtvm_ml_io_type_map(model->mvtvm.info.input[i].datatype); model->mvtvm.info.input[i].qtype = - mvtvm_ml_io_type_map(metadata->input[i].model_datatype); - model->mvtvm.info.input[i].nb_dims = metadata->input[i].ndim; + mvtvm_ml_io_type_map(model->mvtvm.info.input[i].model_datatype); model->mvtvm.info.input[i].nb_elements = 1; - for (j = 0; j < metadata->input[i].ndim; j++) { - model->mvtvm.info.input[i].shape[j] = metadata->input[i].shape[j]; - model->mvtvm.info.input[i].nb_elements *= metadata->input[i].shape[j]; + for (j = 0; j < model->mvtvm.info.input[i].nb_dims; j++) { + model->mvtvm.info.input[i].shape[j] = + PLT_U32_CAST(model->mvtvm.info.input[i].shape_i64[j]); + model->mvtvm.info.input[i].nb_elements *= + model->mvtvm.info.input[i].shape[j]; } model->mvtvm.info.input[i].sz_d = @@ -219,15 +745,14 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model) model->mvtvm.info.input[i].sz_q = model->mvtvm.info.input[i].nb_elements * rte_ml_io_type_size_get(model->mvtvm.info.input[i].qtype); - model->mvtvm.info.input[i].scale = metadata->input[i].scale; model->mvtvm.info.total_input_sz_d += model->mvtvm.info.input[i].sz_d; model->mvtvm.info.total_input_sz_q += model->mvtvm.info.input[i].sz_q; - model->mvtvm.input_tensor[i].device = metadata->input[i].device; - model->mvtvm.input_tensor[i].ndim = metadata->input[i].ndim; - model->mvtvm.input_tensor[i].dtype = metadata->input[i].datatype; - model->mvtvm.input_tensor[i].shape = metadata->input[i].shape; + model->mvtvm.input_tensor[i].device = model->mvtvm.info.input[i].device; + model->mvtvm.input_tensor[i].ndim = model->mvtvm.info.input[i].nb_dims; + model->mvtvm.input_tensor[i].dtype = model->mvtvm.info.input[i].datatype; + model->mvtvm.input_tensor[i].shape = model->mvtvm.info.input[i].shape_i64; model->mvtvm.input_tensor[i].strides = NULL; model->mvtvm.input_tensor[i].byte_offset = 0; @@ -236,22 +761,20 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model) } /* Outputs, set for nb_layers - 1 */ - model->mvtvm.info.nb_outputs = metadata->model.num_output; model->mvtvm.info.total_output_sz_d = 0; model->mvtvm.info.total_output_sz_q = 0; - for (i = 0; i < metadata->model.num_output; i++) { - rte_strscpy(model->mvtvm.info.output[i].name, metadata->output[i].name, - TVMDP_NAME_STRLEN); + for (i = 0; i < model->mvtvm.info.nb_outputs; i++) { model->mvtvm.info.output[i].dtype = - mvtvm_ml_io_type_map(metadata->output[i].datatype); + mvtvm_ml_io_type_map(model->mvtvm.info.output[i].datatype); model->mvtvm.info.output[i].qtype = - mvtvm_ml_io_type_map(metadata->output[i].model_datatype); - model->mvtvm.info.output[i].nb_dims = metadata->output[i].ndim; + mvtvm_ml_io_type_map(model->mvtvm.info.output[i].model_datatype); model->mvtvm.info.output[i].nb_elements = 1; - for (j = 0; j < metadata->output[i].ndim; j++) { - model->mvtvm.info.output[i].shape[j] = metadata->output[i].shape[j]; - model->mvtvm.info.output[i].nb_elements *= metadata->output[i].shape[j]; + for (j = 0; j < model->mvtvm.info.output[i].nb_dims; j++) { + model->mvtvm.info.output[i].shape[j] = + PLT_U32_CAST(model->mvtvm.info.output[i].shape_i64[j]); + model->mvtvm.info.output[i].nb_elements *= + model->mvtvm.info.output[i].shape[j]; } model->mvtvm.info.output[i].sz_d = @@ -260,15 +783,14 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model) model->mvtvm.info.output[i].sz_q = model->mvtvm.info.output[i].nb_elements * rte_ml_io_type_size_get(model->mvtvm.info.output[i].qtype); - model->mvtvm.info.output[i].scale = metadata->output[i].scale; model->mvtvm.info.total_output_sz_d += model->mvtvm.info.output[i].sz_d; model->mvtvm.info.total_output_sz_q += model->mvtvm.info.output[i].sz_q; - model->mvtvm.output_tensor[i].device = metadata->output[i].device; - model->mvtvm.output_tensor[i].ndim = metadata->output[i].ndim; - model->mvtvm.output_tensor[i].dtype = metadata->output[i].datatype; - model->mvtvm.output_tensor[i].shape = metadata->output[i].shape; + model->mvtvm.output_tensor[i].device = model->mvtvm.info.output[i].device; + model->mvtvm.output_tensor[i].ndim = model->mvtvm.info.output[i].nb_dims; + model->mvtvm.output_tensor[i].dtype = model->mvtvm.info.output[i].datatype; + model->mvtvm.output_tensor[i].shape = model->mvtvm.info.output[i].shape_i64; model->mvtvm.output_tensor[i].strides = NULL; model->mvtvm.output_tensor[i].byte_offset = 0; @@ -293,7 +815,6 @@ mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id) void mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model) { - struct tvmdp_model_metadata *metadata; struct rte_ml_model_info *info; struct rte_ml_io_info *output; struct rte_ml_io_info *input; @@ -309,26 +830,23 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo if (model->subtype == ML_CNXK_MODEL_SUBTYPE_TVM_MRVL) goto tvm_mrvl_model; - metadata = &model->mvtvm.metadata; - rte_memcpy(info->name, metadata->model.name, TVMDP_NAME_STRLEN); - snprintf(info->version, RTE_ML_STR_MAX, "%u.%u.%u.%u", metadata->model.version[0], - metadata->model.version[1], metadata->model.version[2], - metadata->model.version[3]); + rte_memcpy(info->name, model->name, RTE_ML_STR_MAX); + snprintf(info->version, RTE_ML_STR_MAX, "%u.%u.%u.%u", 0, 0, 0, 0); info->model_id = model->model_id; info->device_id = cnxk_mldev->mldev->data->dev_id; info->io_layout = RTE_ML_IO_LAYOUT_SPLIT; info->min_batches = model->batch_size; info->max_batches = model->batch_size; - info->nb_inputs = metadata->model.num_input; + info->nb_inputs = model->mvtvm.info.nb_inputs; info->input_info = input; - info->nb_outputs = metadata->model.num_output; + info->nb_outputs = model->mvtvm.info.nb_outputs; info->output_info = output; info->wb_size = 0; /* Set input info */ for (i = 0; i < info->nb_inputs; i++) { - rte_memcpy(input[i].name, metadata->input[i].name, MRVL_ML_INPUT_NAME_LEN); - input[i].nb_dims = metadata->input[i].ndim; + rte_memcpy(input[i].name, model->mvtvm.info.input[i].name, MRVL_ML_INPUT_NAME_LEN); + input[i].nb_dims = model->mvtvm.info.input[i].nb_dims; input[i].shape = &model->mvtvm.info.input[i].shape[0]; input[i].type = model->mvtvm.info.input[i].qtype; input[i].nb_elements = model->mvtvm.info.input[i].nb_elements; @@ -340,15 +858,16 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo /* Set output info */ for (i = 0; i < info->nb_outputs; i++) { - rte_memcpy(output[i].name, metadata->output[i].name, MRVL_ML_OUTPUT_NAME_LEN); - output[i].nb_dims = metadata->output[i].ndim; + rte_memcpy(output[i].name, model->mvtvm.info.output[i].name, + MRVL_ML_OUTPUT_NAME_LEN); + output[i].nb_dims = model->mvtvm.info.output[i].nb_dims; output[i].shape = &model->mvtvm.info.output[i].shape[0]; output[i].type = model->mvtvm.info.output[i].qtype; output[i].nb_elements = model->mvtvm.info.output[i].nb_elements; output[i].size = model->mvtvm.info.output[i].nb_elements * rte_ml_io_type_size_get(model->mvtvm.info.output[i].qtype); - input[i].scale = model->mvtvm.info.output[i].scale; - input[i].zero_point = 0; + output[i].scale = model->mvtvm.info.output[i].scale; + output[i].zero_point = 0; } return; @@ -357,8 +876,7 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo cn10k_ml_model_info_set(cnxk_mldev, model, &model->mvtvm.info, &model->layer[0].glow.metadata); - metadata = &model->mvtvm.metadata; - strlcpy(info->name, metadata->model.name, TVMDP_NAME_STRLEN); + strlcpy(info->name, model->name, RTE_ML_STR_MAX); info->io_layout = RTE_ML_IO_LAYOUT_PACKED; } diff --git a/drivers/ml/cnxk/mvtvm_ml_model.h b/drivers/ml/cnxk/mvtvm_ml_model.h index 7ffce380945..1151b0a39ed 100644 --- a/drivers/ml/cnxk/mvtvm_ml_model.h +++ b/drivers/ml/cnxk/mvtvm_ml_model.h @@ -5,7 +5,21 @@ #ifndef _MVTVM_ML_MODEL_H_ #define _MVTVM_ML_MODEL_H_ -#include <tvmdp.h> +#include <dlpack/dlpack.h> +#include <jansson.h> +#include <rte_common.h> + +#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG) +__rte_diagnostic_push +RTE_PRAGMA(GCC diagnostic ignored "-Wstrict-prototypes") +#include <tvm/runtime/c_runtime_api.h> +__rte_diagnostic_pop +#else +#include <tvm/runtime/c_runtime_api.h> +#endif + +#include <stddef.h> +#include <stdint.h> #include <rte_mldev.h> @@ -18,19 +32,56 @@ struct cnxk_ml_layer; /* Maximum number of objects per model */ #define ML_MVTVM_MODEL_OBJECT_MAX 3 -/* Objects list */ -extern char mvtvm_object_list[ML_MVTVM_MODEL_OBJECT_MAX][RTE_ML_STR_MAX]; +/* Magic number for TVM parameter blobs. */ +#define TVM_NDARRAY_LIST_MAGIC 0xF7E58D4F05049CB7ULL -/* Model object structure */ +/* TVM parameter names structure */ +struct mvtvm_ml_param_names { + char **name; + size_t count; +}; + +/* TVM object / artifact info structure */ struct mvtvm_ml_model_object { /* Name */ char name[RTE_ML_STR_MAX]; - /* Temporary buffer */ + /* Buffer address */ uint8_t *buffer; /* Buffer size */ int64_t size; + + /* Offset */ + uint32_t offset; +}; + +/* Glow model callback functions */ +typedef int (*tvmrt_glow_layer_load_cb)(void *device, uint16_t model_id, const char *layer_name, + uint8_t *buffer, size_t size, uint16_t *index); +typedef int (*tvmrt_glow_layer_unload_cb)(void *device, uint16_t model_id, const char *layer_name); +typedef int (*tvmrt_io_alloc_cb)(void *device, uint16_t model_id, const char *layer_name, + uint64_t **input_qbuffer, uint64_t **output_qbuffer); +typedef int (*tvmrt_io_free_cb)(void *device, uint16_t model_id, const char *layer_name); +typedef int (*tvmrt_malloc_cb)(const char *name, size_t size, uint32_t align, void **addr); +typedef int (*tvmrt_free_cb)(const char *name); +typedef int (*tvmrt_quantize_cb)(void *device, uint16_t model_id, const char *layer_name, + const DLTensor **deq_tensor, void *qbuffer); +typedef int (*tvmrt_dequantize_cb)(void *device, uint16_t model_id, const char *layer_name, + void *qbuffer, const DLTensor **deq_tensor); +typedef int (*tvmrt_inference_cb)(void *device, uint16_t index, void *input, void *output, + uint16_t nb_batches); + +struct tvmrt_glow_callback { + tvmrt_glow_layer_load_cb tvmrt_glow_layer_load; + tvmrt_glow_layer_unload_cb tvmrt_glow_layer_unload; + tvmrt_io_alloc_cb tvmrt_io_alloc; + tvmrt_io_free_cb tvmrt_io_free; + tvmrt_malloc_cb tvmrt_malloc; + tvmrt_free_cb tvmrt_free; + tvmrt_quantize_cb tvmrt_quantize; + tvmrt_dequantize_cb tvmrt_dequantize; + tvmrt_inference_cb tvmrt_inference; }; /* Model fast-path stats */ @@ -55,15 +106,26 @@ struct mvtvm_ml_model_xstats { }; struct mvtvm_ml_model_data { - /* Model metadata */ - struct tvmdp_model_metadata metadata; - /* Model objects */ - struct tvmdp_model_object object; + struct mvtvm_ml_model_object so; + struct mvtvm_ml_model_object json; + struct mvtvm_ml_model_object params; /* TVM runtime callbacks */ struct tvmrt_glow_callback cb; + /* TVM Graph Module */ + TVMModuleHandle graph_module; + + /* Shared object memfd used to load the TVM module */ + int fd; + + /* TVM Function Handles */ + TVMFunctionHandle load_params; + TVMFunctionHandle set_input_zero_copy; + TVMFunctionHandle set_output_zero_copy; + TVMFunctionHandle run; + /* Model I/O info */ struct cnxk_ml_io_info info; @@ -86,5 +148,6 @@ void mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model); struct cnxk_ml_io_info *mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id); void mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model); void mvtvm_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp); +int mvtvm_ml_model_json_parse(struct cnxk_ml_model *model); #endif /* _MVTVM_ML_MODEL_H_ */ diff --git a/drivers/ml/cnxk/mvtvm_ml_ops.c b/drivers/ml/cnxk/mvtvm_ml_ops.c index 80b22460db9..bc47a4bbd75 100644 --- a/drivers/ml/cnxk/mvtvm_ml_ops.c +++ b/drivers/ml/cnxk/mvtvm_ml_ops.c @@ -2,7 +2,17 @@ * Copyright (c) 2023 Marvell. */ +#include <errno.h> +#include <linux/limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + #include <dlpack/dlpack.h> +#include <jansson.h> #include <rte_common.h> #include <rte_cycles.h> @@ -19,6 +29,76 @@ /* ML model macros */ #define MVTVM_ML_MODEL_MEMZONE_NAME "ml_mvtvm_model_mz" +/* Shared memory file descriptor name */ +#define ML_MODEL_SHMFD_NAME "mvtvm_shmfd" + +/* Shared memory file descriptor path */ +#define ML_MODEL_SHMFD_PATH "/proc/%d/fd/%d" + +static int +mvtvm_ml_tvm_func_get(struct cnxk_ml_model *model, TVMModuleHandle module, const char *name, + TVMFunctionHandle *func) +{ + int ret; + + ret = TVMModGetFunction(module, name, 0, func); + if (ret != 0) { + plt_err("Model load failed, model_id = %u, ret = %d, msg = %s", model->model_id, + ret, TVMGetLastError()); + return ret; + } + + if (*func == NULL) { + ret = -ENOENT; + plt_err("Model load failed, model_id = %u, function '%s' not found", + model->model_id, name); + } + + return ret; +} + +static int +mvtvm_ml_tvm_func_call(struct cnxk_ml_model *model, TVMFunctionHandle func, const char *name, + TVMValue *values, int *types, int num_args, TVMValue *ret_val, int *ret_type, + int ret_type_code) +{ + int ret; + + ret = TVMFuncCall(func, values, types, num_args, ret_val, ret_type); + if (ret != 0) { + plt_err("Error calling TVM function '%s', model_id = %u, ret = %d, msg = %s", name, + model->model_id, ret, TVMGetLastError()); + return ret; + } + + if (*ret_type != ret_type_code) { + ret = -EINVAL; + plt_err("TVM function '%s' returned unexpected type, model_id = %u, expected = %d, " + "actual = %d", + name, model->model_id, ret_type_code, *ret_type); + } + + return ret; +} + +static void +mvtvm_ml_tvm_func_free(TVMFunctionHandle *func) +{ + if ((func != NULL) && (*func != NULL)) { + TVMFuncFree(*func); + *func = NULL; + } +} + +static void +mvtvm_ml_tvm_mod_free(TVMModuleHandle *mod) +{ + if ((mod != NULL) && (*mod != NULL)) { + TVMModFree(*mod); + *mod = NULL; + } +} + __rte_hot static void mvtvm_ml_set_poll_addr(struct cnxk_ml_req *req) { @@ -30,8 +110,8 @@ mvtvm_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_mod uint16_t stat_id, uint16_t entry, char *suffix) { snprintf(cnxk_mldev->xstats.entries[stat_id].map.name, - sizeof(cnxk_mldev->xstats.entries[stat_id].map.name), "%s-%s-%s", - model->mvtvm.metadata.model.name, model_xstats[entry].name, suffix); + sizeof(cnxk_mldev->xstats.entries[stat_id].map.name), "%s-%s-%s", model->name, + model_xstats[entry].name, suffix); } #define ML_AVG_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count) \ @@ -106,43 +186,13 @@ mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *de dev_info->max_queue_pairs = mvtvm_mldev->max_nb_qpairs; dev_info->max_desc = ML_MVTVM_MAX_DESC_PER_QP; - dev_info->max_io = ML_MVTVM_MAX_INPUT_OUTPUT; + dev_info->max_io = ML_CNXK_MODEL_MAX_INPUT_OUTPUT; dev_info->max_segments = ML_MVTVM_MAX_SEGMENTS; dev_info->align_size = RTE_CACHE_LINE_SIZE; return 0; } -int -mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf) -{ - int ret; - - RTE_SET_USED(conf); - - /* Configure TVMDP library */ - ret = tvmdp_configure(cnxk_mldev->mldev->data->nb_models, rte_get_tsc_cycles); - if (ret != 0) - plt_err("TVMDP configuration failed, error = %d", ret); - - return ret; -} - -int -mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev) -{ - int ret; - - RTE_SET_USED(cnxk_mldev); - - /* Close TVMDP library configuration */ - ret = tvmdp_close(); - if (ret != 0) - plt_err("TVMDP close failed, error = %d", ret); - - return ret; -} - int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp) { @@ -159,16 +209,26 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params * struct mvtvm_ml_model_object object[ML_MVTVM_MODEL_OBJECT_MAX]; struct tvmrt_glow_callback *callback; char str[RTE_MEMZONE_NAMESIZE]; + char path[PATH_MAX]; const struct plt_memzone *mz; size_t model_object_size = 0; size_t model_xstats_size = 0; - uint16_t nb_mrvl_layers; - uint16_t nb_llvm_layers; - uint8_t layer_id = 0; uint64_t mz_size = 0; + TVMFunctionHandle create_fn = NULL; + TVMFunctionHandle register_cb_fn = NULL; + TVMModuleHandle module_so = NULL; + TVMByteArray tvm_params; + TVMValue ret_value = {0}; + TVMValue arg_values[4] = {0}; + TVMValue tvm_arg_values[1] = {0}; + int ret_type = kTVMNullptr; + int arg_types[4] = {0}; + int tvm_arg_types[1] = {0}; + DLDevice device; int ret; RTE_SET_USED(cnxk_mldev); + model->mvtvm.fd = -1; ret = mvtvm_ml_model_blob_parse(params, object); if (ret != 0) @@ -192,80 +252,39 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params * } /* Copy mod.so */ - model->mvtvm.object.so.addr = mz->addr; - model->mvtvm.object.so.size = object[0].size; - rte_memcpy(model->mvtvm.object.so.name, object[0].name, TVMDP_NAME_STRLEN); - rte_memcpy(model->mvtvm.object.so.addr, object[0].buffer, object[0].size); + model->mvtvm.so.buffer = mz->addr; + model->mvtvm.so.size = object[0].size; + rte_memcpy(model->mvtvm.so.name, object[0].name, RTE_ML_STR_MAX); + rte_memcpy(model->mvtvm.so.buffer, object[0].buffer, object[0].size); rte_free(object[0].buffer); /* Copy mod.json */ - model->mvtvm.object.json.addr = - RTE_PTR_ADD(model->mvtvm.object.so.addr, - RTE_ALIGN_CEIL(model->mvtvm.object.so.size, RTE_CACHE_LINE_MIN_SIZE)); - model->mvtvm.object.json.size = object[1].size; - rte_memcpy(model->mvtvm.object.json.name, object[1].name, TVMDP_NAME_STRLEN); - rte_memcpy(model->mvtvm.object.json.addr, object[1].buffer, object[1].size); + model->mvtvm.json.buffer = + RTE_PTR_ADD(model->mvtvm.so.buffer, + RTE_ALIGN_CEIL(model->mvtvm.so.size, RTE_CACHE_LINE_MIN_SIZE)); + model->mvtvm.json.size = object[1].size; + rte_memcpy(model->mvtvm.json.name, object[1].name, RTE_ML_STR_MAX); + rte_memcpy(model->mvtvm.json.buffer, object[1].buffer, object[1].size); rte_free(object[1].buffer); /* Copy mod.params */ - model->mvtvm.object.params.addr = - RTE_PTR_ADD(model->mvtvm.object.json.addr, - RTE_ALIGN_CEIL(model->mvtvm.object.json.size, RTE_CACHE_LINE_MIN_SIZE)); - model->mvtvm.object.params.size = object[2].size; - rte_memcpy(model->mvtvm.object.params.name, object[2].name, TVMDP_NAME_STRLEN); - rte_memcpy(model->mvtvm.object.params.addr, object[2].buffer, object[2].size); + model->mvtvm.params.buffer = + RTE_PTR_ADD(model->mvtvm.json.buffer, + RTE_ALIGN_CEIL(model->mvtvm.json.size, RTE_CACHE_LINE_MIN_SIZE)); + model->mvtvm.params.size = object[2].size; + rte_memcpy(model->mvtvm.params.name, object[2].name, RTE_ML_STR_MAX); + rte_memcpy(model->mvtvm.params.buffer, object[2].buffer, object[2].size); rte_free(object[2].buffer); - /* Get metadata - stage 1 */ - ret = tvmdp_model_metadata_get_stage1(model->mvtvm.object.json.addr, - model->mvtvm.object.json.size, - &model->mvtvm.metadata); - if (ret != 0) { - plt_err("TVMDP: Failed to parse metadata - stage 1, model_id = %u, error = %d", - model->model_id, ret); - goto error; - } - - /* Set model fields */ - plt_strlcpy(model->name, model->mvtvm.metadata.model.name, TVMDP_NAME_STRLEN); - model->batch_size = 1; - model->nb_layers = model->mvtvm.metadata.model.nb_layers; - - /* Update layer info */ - nb_mrvl_layers = 0; - nb_llvm_layers = 0; - for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) { - rte_strscpy(model->layer[layer_id].name, - model->mvtvm.metadata.model.layer[layer_id].name, TVMDP_NAME_STRLEN); - if (strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "mrvl") == 0 || - strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "MRVL") == 0) { - model->layer[layer_id].type = ML_CNXK_LAYER_TYPE_MRVL; - nb_mrvl_layers++; - } else if (strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "llvm") == 0 || - strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "LLVM") == 0) { - model->layer[layer_id].type = ML_CNXK_LAYER_TYPE_LLVM; - nb_llvm_layers++; - } - } - - if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 0)) { - plt_err("Invalid model, nb_llvm_layers = %u, nb_mrvl_layers = %u", nb_llvm_layers, - nb_mrvl_layers); + ret = mvtvm_ml_model_json_parse(model); + if (ret != 0) goto error; - } - - /* Set model subtype */ - if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 1)) - model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_MRVL; - else if ((nb_llvm_layers > 0) && (nb_mrvl_layers == 0)) - model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_LLVM; - else - model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_HYBRID; if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_VDEV && model->subtype != ML_CNXK_MODEL_SUBTYPE_TVM_LLVM) { plt_err("Unsupported model sub-type"); - return -ENOTSUP; + ret = -ENOTSUP; + goto error; } /* Set callback function array */ @@ -284,23 +303,120 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params * callback = NULL; } - /* Initialize model in TVMDP */ - ret = tvmdp_model_load(cnxk_mldev, model->model_id, (void *)(&model->mvtvm.object), - callback); + /* Initialize model in TVM runtime */ + if (model->mvtvm.graph_module != NULL) { + ret = -EBUSY; + plt_err("TVM runtime: Model load failed, model_id = %u, error = %d", + model->model_id, ret); + goto error; + } + + snprintf(path, sizeof(path), "%s_%d_%u", ML_MODEL_SHMFD_NAME, getpid(), model->model_id); + model->mvtvm.fd = memfd_create(path, 0); + if (model->mvtvm.fd < 0) { + ret = (errno == 0) ? -EIO : -errno; + plt_err("TVM runtime: Model load failed, model_id = %u, error = %d", + model->model_id, ret); + goto error; + } + + if (write(model->mvtvm.fd, model->mvtvm.so.buffer, model->mvtvm.so.size) != + (ssize_t)model->mvtvm.so.size) { + ret = (errno == 0) ? -EIO : -errno; + plt_err("TVM runtime: Model load failed, model_id = %u, error = %d", + model->model_id, ret); + goto error; + } + + if (lseek(model->mvtvm.fd, 0, SEEK_SET) < 0) { + ret = (errno == 0) ? -EIO : -errno; + plt_err("TVM runtime: Model load failed, model_id = %u, error = %d", + model->model_id, ret); + goto error; + } + + snprintf(path, sizeof(path), ML_MODEL_SHMFD_PATH, getpid(), model->mvtvm.fd); + ret = TVMModLoadFromFile(path, "so", &module_so); if (ret != 0) { - plt_err("TVMDP: Model load failed, model_id = %u, error = %d", model->model_id, - ret); + plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s", + model->model_id, ret, TVMGetLastError()); goto error; } - /* Get model metadata - stage 2 */ - ret = tvmdp_model_metadata_get_stage2(model->model_id, &model->mvtvm.metadata); + /* Set device info */ + device.device_type = kDLCPU; + device.device_id = 0; + + if (callback != NULL) { + ret = mvtvm_ml_tvm_func_get(model, module_so, "register_cb", ®ister_cb_fn); + if (ret != 0) + goto error; + + arg_values[0].v_handle = callback; + arg_types[0] = kTVMOpaqueHandle; + arg_values[1].v_handle = cnxk_mldev; + arg_types[1] = kTVMOpaqueHandle; + arg_values[2].v_int64 = model->model_id; + arg_types[2] = kDLInt; + + ret = mvtvm_ml_tvm_func_call(model, register_cb_fn, "register_cb", arg_values, + arg_types, 3, &ret_value, &ret_type, kTVMNullptr); + if (ret != 0) + goto error; + } + + ret = TVMFuncGetGlobal("tvm.graph_executor.create", &create_fn); if (ret != 0) { - plt_err("TVMDP: Failed to get metadata, model_id = %u, error = %d", - model->model_id, ret); + plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s", + model->model_id, ret, TVMGetLastError()); goto error; } + arg_values[0].v_str = (const char *)model->mvtvm.json.buffer; + arg_types[0] = kTVMStr; + arg_values[1].v_handle = module_so; + arg_types[1] = kTVMModuleHandle; + arg_values[2].v_int64 = device.device_type; + arg_types[2] = kDLInt; + arg_values[3].v_int64 = device.device_id; + arg_types[3] = kDLInt; + + ret = mvtvm_ml_tvm_func_call(model, create_fn, "tvm.graph_executor.create", arg_values, + arg_types, 4, &ret_value, &ret_type, kTVMModuleHandle); + if (ret != 0) + goto error; + model->mvtvm.graph_module = ret_value.v_handle; + + ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "load_params", + &model->mvtvm.load_params); + if (ret != 0) + goto error; + ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "set_input_zero_copy", + &model->mvtvm.set_input_zero_copy); + if (ret != 0) + goto error; + ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "set_output_zero_copy", + &model->mvtvm.set_output_zero_copy); + if (ret != 0) + goto error; + ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "run", &model->mvtvm.run); + if (ret != 0) + goto error; + + mvtvm_ml_tvm_func_free(®ister_cb_fn); + mvtvm_ml_tvm_mod_free(&module_so); + + /* Load model parameters into TVM runtime */ + tvm_params.data = (const char *)model->mvtvm.params.buffer; + tvm_params.size = model->mvtvm.params.size; + tvm_arg_values[0].v_handle = &tvm_params; + tvm_arg_types[0] = kTVMBytes; + + ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.load_params, "load_params", tvm_arg_values, + tvm_arg_types, 1, &ret_value, &ret_type, kTVMNullptr); + if (ret != 0) + goto error; + /* Update model I/O data */ mvtvm_ml_model_io_info_set(model); @@ -310,9 +426,9 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params * /* Update model xstats name */ cnxk_ml_xstats_model_name_update(cnxk_mldev, model->model_id); - model->mvtvm.burst_xstats = RTE_PTR_ADD( - model->mvtvm.object.params.addr, - RTE_ALIGN_CEIL(model->mvtvm.object.params.size, RTE_CACHE_LINE_MIN_SIZE)); + model->mvtvm.burst_xstats = + RTE_PTR_ADD(model->mvtvm.params.buffer, + RTE_ALIGN_CEIL(model->mvtvm.params.size, RTE_CACHE_LINE_MIN_SIZE)); for (int qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_tot = 0; @@ -341,7 +457,20 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params * return 0; error: - rte_memzone_free(mz); + mvtvm_ml_tvm_func_free(®ister_cb_fn); + if (model != NULL) { + mvtvm_ml_tvm_func_free(&model->mvtvm.load_params); + mvtvm_ml_tvm_func_free(&model->mvtvm.set_input_zero_copy); + mvtvm_ml_tvm_func_free(&model->mvtvm.set_output_zero_copy); + mvtvm_ml_tvm_func_free(&model->mvtvm.run); + mvtvm_ml_tvm_mod_free(&model->mvtvm.graph_module); + if (model->mvtvm.fd >= 0) + close(model->mvtvm.fd); + memset(&model->mvtvm, 0, sizeof(model->mvtvm)); + model->mvtvm.fd = -1; + } + mvtvm_ml_tvm_mod_free(&module_so); + plt_memzone_free(mz); return ret; } @@ -351,20 +480,28 @@ mvtvm_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mode { char str[RTE_MEMZONE_NAMESIZE]; const struct plt_memzone *mz; - int ret; RTE_SET_USED(cnxk_mldev); - /* Initialize model in TVMDP */ - ret = tvmdp_model_unload(model->model_id); - if (ret != 0) { - plt_err("TVMDP: Model unload failed, model_id = %u, error = %d", model->model_id, - ret); - return ret; - } + /* Unload model from TVM runtime */ + if (model->model_id >= cnxk_mldev->mldev->data->nb_models) + return -EINVAL; + + if (model->mvtvm.graph_module == NULL) + return -EINVAL; + + mvtvm_ml_tvm_func_free(&model->mvtvm.load_params); + mvtvm_ml_tvm_func_free(&model->mvtvm.set_input_zero_copy); + mvtvm_ml_tvm_func_free(&model->mvtvm.set_output_zero_copy); + mvtvm_ml_tvm_func_free(&model->mvtvm.run); + mvtvm_ml_tvm_mod_free(&model->mvtvm.graph_module); + if (model->mvtvm.fd >= 0) + close(model->mvtvm.fd); + memset(&model->mvtvm, 0, sizeof(model->mvtvm)); + model->mvtvm.fd = -1; snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", MVTVM_ML_MODEL_MEMZONE_NAME, model->model_id); - mz = rte_memzone_lookup(str); + mz = plt_memzone_lookup(str); if (mz == NULL) { plt_err("Memzone lookup failed for TVM model: model_id = %u, mz = %s", model->model_id, str); @@ -455,13 +592,13 @@ mvtvm_ml_io_quantize(void *device, uint16_t model_id, const char *layer_name, #endif /* Get layer id */ - for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) { + for (layer_id = 0; layer_id < model->nb_layers; layer_id++) { if (strcmp(model->layer[layer_id].name, layer_name) == 0) break; } #ifdef CNXK_ML_DEV_DEBUG - if (layer_id == model->mvtvm.metadata.model.nb_layers) { + if (layer_id == model->nb_layers) { plt_err("Invalid layer name: %s", layer_name); return -EINVAL; } @@ -516,13 +653,13 @@ mvtvm_ml_io_dequantize(void *device, uint16_t model_id, const char *layer_name, } #endif - for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) { + for (layer_id = 0; layer_id < model->nb_layers; layer_id++) { if (strcmp(model->layer[layer_id].name, layer_name) == 0) break; } #ifdef CNXK_ML_DEV_DEBUG - if (layer_id == model->mvtvm.metadata.model.nb_layers) { + if (layer_id == model->nb_layers) { plt_err("Invalid layer name: %s", layer_name); return -EINVAL; } @@ -553,28 +690,69 @@ static int mvtvm_ml_model_run(struct cnxk_ml_model *model, struct rte_ml_op *op, struct cnxk_ml_req *req) { uint8_t i; + struct mvtvm_ml_result *run_result; + TVMValue arg_values[2] = {0}; + int arg_types[2] = {0}; + TVMValue ret_value = {0}; + int ret_type = kTVMNullptr; + int ret = 0; rte_memcpy(req->mvtvm_req.input_tensor, model->mvtvm.input_tensor, - model->mvtvm.metadata.model.num_input * sizeof(DLTensor)); - for (i = 0; i < model->mvtvm.metadata.model.num_input; i++) { + model->mvtvm.info.nb_inputs * sizeof(DLTensor)); + for (i = 0; i < model->mvtvm.info.nb_inputs; i++) { req->mvtvm_req.input_tensor[i].data = op->input[i]->addr; req->mvtvm_req.input_tensor[i].byte_offset = 0; } rte_memcpy(req->mvtvm_req.output_tensor, model->mvtvm.output_tensor, - model->mvtvm.metadata.model.num_output * sizeof(DLTensor)); - for (i = 0; i < model->mvtvm.metadata.model.num_output; i++) { + model->mvtvm.info.nb_outputs * sizeof(DLTensor)); + for (i = 0; i < model->mvtvm.info.nb_outputs; i++) { req->mvtvm_req.output_tensor[i].data = op->output[i]->addr; req->mvtvm_req.output_tensor[i].byte_offset = 0; } - tvmdp_model_run(model->model_id, model->mvtvm.metadata.model.num_input, - req->mvtvm_req.input_tensor, model->mvtvm.metadata.model.num_output, - req->mvtvm_req.output_tensor, &req->mvtvm_req.result, - &req->mvtvm_req.status); + run_result = &req->mvtvm_req.result; + run_result->stats.start_ns = rte_get_tsc_cycles(); + run_result->error_code = 0; + + for (i = 0; i < model->mvtvm.info.nb_inputs; i++) { + arg_values[0].v_int64 = i; + arg_types[0] = kDLInt; + arg_values[1].v_handle = &req->mvtvm_req.input_tensor[i]; + arg_types[1] = kTVMDLTensorHandle; + ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.set_input_zero_copy, + "set_input_zero_copy", arg_values, arg_types, 2, + &ret_value, &ret_type, kTVMNullptr); + if (ret != 0) + goto out; + } + + for (i = 0; i < model->mvtvm.info.nb_outputs; i++) { + arg_values[0].v_int64 = i; + arg_types[0] = kDLInt; + arg_values[1].v_handle = &req->mvtvm_req.output_tensor[i]; + arg_types[1] = kTVMDLTensorHandle; + ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.set_output_zero_copy, + "set_output_zero_copy", arg_values, arg_types, 2, + &ret_value, &ret_type, kTVMNullptr); + if (ret != 0) + goto out; + } + + ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.run, "run", NULL, NULL, 0, &ret_value, + &ret_type, kTVMNullptr); + if (ret != 0) + goto out; + +out: + run_result->stats.end_ns = rte_get_tsc_cycles(); + req->mvtvm_req.status = 0x1; plt_write64(ML_CNXK_POLL_JOB_FINISH, req->status); + if (ret != 0) + run_result->error_code = -EIO; + return 0; } diff --git a/drivers/ml/cnxk/mvtvm_ml_ops.h b/drivers/ml/cnxk/mvtvm_ml_ops.h index d8f2f361fb1..593f4585b3c 100644 --- a/drivers/ml/cnxk/mvtvm_ml_ops.h +++ b/drivers/ml/cnxk/mvtvm_ml_ops.h @@ -7,11 +7,10 @@ #include <dlpack/dlpack.h> -#include <tvmdp.h> - #include <rte_mldev.h> #include "cnxk_ml_xstats.h" +#include "mvtvm_ml_model.h" struct cnxk_ml_dev; struct cnxk_ml_model; @@ -56,8 +55,6 @@ struct mvtvm_ml_req { }; int mvtvm_ml_dev_info_get(struct cnxk_ml_dev *mldev, struct rte_ml_dev_info *dev_info); -int mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf); -int mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev); int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp); int mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params, struct cnxk_ml_model *model); diff --git a/drivers/ml/cnxk/mvtvm_ml_stubs.c b/drivers/ml/cnxk/mvtvm_ml_stubs.c index 126a954c916..7c13fac42d6 100644 --- a/drivers/ml/cnxk/mvtvm_ml_stubs.c +++ b/drivers/ml/cnxk/mvtvm_ml_stubs.c @@ -76,23 +76,6 @@ mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *de return -ENOTSUP; } -int -mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf) -{ - RTE_SET_USED(cnxk_mldev); - RTE_SET_USED(conf); - - return 0; -} - -int -mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev) -{ - RTE_SET_USED(cnxk_mldev); - - return 0; -} - int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp) { diff --git a/drivers/ml/cnxk/mvtvm_ml_stubs.h b/drivers/ml/cnxk/mvtvm_ml_stubs.h index 4220a963f2d..15985a75bf4 100644 --- a/drivers/ml/cnxk/mvtvm_ml_stubs.h +++ b/drivers/ml/cnxk/mvtvm_ml_stubs.h @@ -15,8 +15,6 @@ struct cnxk_ml_layer; enum cnxk_ml_model_type mvtvm_ml_model_type_get(struct rte_ml_model_params *params); int mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *dev_info); -int mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf); -int mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev); int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp); int mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params, struct cnxk_ml_model *model); -- 2.34.1

