if (model == nullptr)
return -ENOENT;
- model->setDataInfo (in, out);
-
- return 0;
+ return model->setDataInfo (in, out);
}
/**
#include <string.h>
-std::atomic<uint32_t> Model::global_model_id_ (0);
+#define TAG _N71
+
+std::atomic<uint32_t> Model::global_model_id_ (1);
+
+/**
+ * @brief constructor of metadata class
+ */
+Metadata::Metadata (npubin_meta *meta)
+ : meta_ (meta)
+{
+ version_ = NPUBIN_VERSION (meta->magiccode);
+ if (version_ == 0) /* backward-compatability */
+ version_ = 1;
+}
/**
* @brief extract metadata from model binary data
npubin_meta * meta_data = static_cast <npubin_meta *> (data);
/** check whether it's npu binary */
- if (!CHECK_NPUBIN (meta_data->magiccode))
+ if (!CHECK_NPUBIN (meta_data->magiccode)) {
+ logerr (TAG, "Non-compatible binary format\n");
return nullptr;
+ }
+
+ std::unique_ptr<Metadata> meta_ptr;
+ Metadata * meta_ins = nullptr;
- std::unique_ptr<Metadata> meta (nullptr);
switch (NPUBIN_VERSION (meta_data->magiccode)) {
case 0:
case 1:
- meta.reset (new Metadata_v1 (meta_data));
+ meta_ins = new Metadata_v1 (meta_data);
break;
case 2:
- meta.reset (new Metadata_v2 (meta_data));
+ meta_ins = new Metadata_v2 (meta_data);
+ break;
+ default:
+ logerr (TAG, "Invalid NPU binary format version: %d\n",
+ NPUBIN_VERSION (meta_data->magiccode));
break;
}
- return meta;
+
+ if (meta_ins != nullptr && !meta_ins->checkSanity ()) {
+ delete meta_ins;
+ meta_ins = nullptr;
+ }
+
+ meta_ptr.reset (meta_ins);
+ return meta_ptr;
+}
+
+/** @brief constructor of npubinfmt v1 */
+Metadata_v1::Metadata_v1 (npubin_meta *meta)
+ : Metadata (meta)
+{
+ /** set dummy input/output dimensions as metadata v1 does not have dimension info. */
+ for (uint32_t idx = 0; idx < MAX_TENSORS; idx++) {
+ input_dims[idx][0] = getInputTensorSize (idx, DATA_LAYOUT_SRNPU);
+ output_dims[idx][0] = getOutputTensorSize (idx, DATA_LAYOUT_SRNPU);
+ for (uint32_t rank_idx = 1; rank_idx < MAX_RANK; rank_idx++) {
+ input_dims[idx][rank_idx] = 1;
+ output_dims[idx][rank_idx] = 1;
+ }
+ }
+}
+
+/** @brief sanity check for npubinfmt v1 */
+bool
+Metadata_v1::checkSanity () const
+{
+ if (getVersion () != 1)
+ return false;
+
+ return getSize () == getMetaSize () + getProgramSize () + getWeightSize ();
+}
+
+/** @brief constructor of npubinfmt v2 */
+Metadata_v2::Metadata_v2 (npubin_meta *meta)
+ : Metadata (meta)
+{
+}
+
+/** @brief sanity check for npubinfmt v2 */
+bool
+Metadata_v2::checkSanity () const
+{
+ if (getVersion () != 2)
+ return false;
+ if (getInputNum () > MAX_TENSORS)
+ return false;
+ if (getOutputNum () > MAX_TENSORS)
+ return false;
+
+ return getSize () == getMetaSize () + getProgramSize () + getWeightSize ();
+}
+
+/** @brief calculate tensor size depending on specified layout */
+uint32_t
+Metadata_v2::getInputTensorSize (uint32_t idx, data_layout layout) const
+{
+ assert (idx < getInputNum ());
+
+ const uint32_t *dims = getInputDims (idx);
+ uint32_t elem_size = getInputElemSize (idx);
+ uint32_t tensor_size = elem_size;
+
+ for (uint32_t rank_idx = 0; rank_idx < MAX_RANK; rank_idx++)
+ tensor_size *= dims[rank_idx];
+
+ /** special handling for TRIV */
+ if (layout == DATA_LAYOUT_SRNPU && dims[3] != 3 &&
+ dims[3] % DATA_GRANULARITY != 0) {
+ tensor_size *= (1 + dims[3] / DATA_GRANULARITY);
+ }
+
+ return tensor_size;
+}
+
+/** @brief calculate tensor size depending on specified layout */
+uint32_t
+Metadata_v2::getOutputTensorSize (uint32_t idx, data_layout layout) const
+{
+ assert (idx < getOutputNum ());
+
+ const uint32_t *dims = getOutputDims (idx);
+ uint32_t elem_size = getOutputElemSize (idx);
+ uint32_t tensor_size = elem_size;
+
+ for (uint32_t rank_idx = 0; rank_idx < MAX_RANK; rank_idx++)
+ tensor_size *= dims[rank_idx];
+
+ /** special handling for TRIV */
+ if (layout == DATA_LAYOUT_SRNPU && dims[3] != 3 &&
+ dims[3] % DATA_GRANULARITY != 0) {
+ tensor_size *= (1 + dims[3] / DATA_GRANULARITY);
+ }
+
+ return tensor_size;
}
/** @brief constructor of model class */
* @brief set data info of input/output tensors
* @param[in] in input tensors' data info
* @param[in] out output tensors' data info
+ * @return 0 if no error, otherwise a negative errno
*/
-void
+int
Model::setDataInfo (const tensors_data_info *in, const tensors_data_info *out)
{
+ if (in == nullptr || out == nullptr) {
+ logerr (TAG, "invalid arguments provided\n");
+ return -EINVAL;
+ }
+
in_ = *in;
out_ = *out;
+
+ return 0;
}
/**
int
Model::setMetadata (void *data)
{
+ if (data == nullptr)
+ return -EINVAL;
+
this->meta_ = Metadata::extractMetadata (data);
if (this->meta_.get() == nullptr)
return -EINVAL;
}
/**
+ * @brief get the number of input tensors
+ */
+uint32_t
+Model::getInputTensorNum () const
+{
+ if (meta_.get() == nullptr) {
+ logerr (TAG, "Invalid metadata\n");
+ return 0;
+ }
+
+ return meta_->getInputNum ();
+}
+
+/**
+ * @brief get the number of input tensors
+ */
+uint32_t
+Model::getOutputTensorNum () const
+{
+ if (meta_.get() == nullptr) {
+ logerr (TAG, "Invalid metadata\n");
+ return 0;
+ }
+
+ return meta_->getOutputNum ();
+}
+
+/**
* @brief get the size of input tensor
* @param[in] idx input tensor index
* @return the size of input tensor
uint32_t
Model::getInputTensorSize (uint32_t idx) const
{
+ if (meta_.get() == nullptr) {
+ logerr (TAG, "Invalid metadata\n");
+ return 0;
+ }
+
+ if (in_.num_info <= idx) {
+ logerr (TAG, "Input tensor info mismatch. Do setNPU_dataInfo() first properly\n");
+ return 0;
+ }
+
data_layout layout = in_.info[idx].layout;
return meta_->getInputTensorSize (idx, layout);
}
uint32_t
Model::getOutputTensorSize (uint32_t idx) const
{
+ if (meta_.get() == nullptr) {
+ logerr (TAG, "Invalid metadata\n");
+ return 0;
+ }
+
+ if (out_.num_info <= idx) {
+ logerr (TAG, "Output tensor info mismatch. Do setNPU_dataInfo() first properly\n");
+ return 0;
+ }
+
data_layout layout = out_.info[idx].layout;
return meta_->getOutputTensorSize (idx, layout);
}
*/
const tensor_data_info *
Model::getInputDataInfo (uint32_t idx) const {
- if (in_.num_info <= idx)
+ if (meta_.get() == nullptr) {
+ logerr (TAG, "Invalid metadata\n");
+ return nullptr;
+ }
+
+ if (in_.num_info <= idx) {
+ logerr (TAG, "Input tensor info mismatch. Do setNPU_dataInfo() first properly\n");
return nullptr;
+ }
+
return &in_.info[idx];
}
*/
const tensor_data_info *
Model::getOutputDataInfo (uint32_t idx) const {
- if (out_.num_info <= idx)
+ if (meta_.get() == nullptr) {
+ logerr (TAG, "Invalid metadata\n");
return nullptr;
+ }
+
+ if (out_.num_info <= idx) {
+ logerr (TAG, "Output tensor info mismatch. Do setNPU_dataInfo() first properly\n");
+ return nullptr;
+ }
+
return &out_.info[idx];
}
#include <atomic>
#include <mutex>
+#include <assert.h>
+
/** this assumes uint8 zero quantization */
#define DEFAULT_ZERO_POINT (127)
#define DEFAULT_SCALE (1.0)
public:
static std::unique_ptr<Metadata> extractMetadata (void *data);
- Metadata (npubin_meta *meta) : meta_(meta), version_(0) {}
+ Metadata (npubin_meta *meta);
virtual ~Metadata () {};
+ virtual bool checkSanity () const = 0;
+
virtual uint32_t getInputNum () const = 0;
virtual uint32_t getOutputNum () const = 0;
uint64_t getBufferSize () const { return meta_->buffer_size; }
uint32_t getMetaSize () const { return NPUBIN_META_TOTAL_SIZE(meta_->magiccode); }
+ int getVersion () const { return version_; }
+
protected:
npubin_meta *meta_; /**< user-exposed metadata structure */
int version_; /**< metadata version */
/** @brief metadata version 1: support only a single pair of input/ouput tensors */
class Metadata_v1 : public Metadata {
public:
- Metadata_v1 (npubin_meta *meta) : Metadata (meta) {
- /** set dummy input/output dimensions as metadata v1 does not have dimension info. */
- for (uint32_t idx = 0; idx < MAX_TENSORS; idx++) {
- input_dims[idx][0] = getInputTensorSize (idx, DATA_LAYOUT_SRNPU);
- output_dims[idx][0] = getOutputTensorSize (idx, DATA_LAYOUT_SRNPU);
- for (uint32_t rank_idx = 1; rank_idx < MAX_RANK; rank_idx++) {
- input_dims[idx][rank_idx] = 1;
- output_dims[idx][rank_idx] = 1;
- }
- }
- }
+ Metadata_v1 (npubin_meta *meta);
+
+ bool checkSanity () const;
uint32_t getInputNum () const override { return 1; }
uint32_t getOutputNum () const override { return 1; }
/** @brief metadata version 2: support multiple input/output tensors */
class Metadata_v2 : public Metadata {
public:
- Metadata_v2 (npubin_meta *meta) : Metadata (meta) {}
+ Metadata_v2 (npubin_meta *meta);
+
+ bool checkSanity () const;
uint32_t getInputNum () const override { return meta_->input_num; }
uint32_t getOutputNum () const override { return meta_->output_num; }
uint32_t getInputOffset (uint32_t idx) const override {
+ assert (idx < getInputNum ());
return meta_->input_offsets[idx];
}
uint32_t getOutputOffset (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
return meta_->output_offsets[idx];
}
- uint32_t getInputTensorSize (uint32_t idx, data_layout layout) const override {
- const uint32_t *dims = getInputDims (idx);
- uint32_t elem_size = getInputElemSize (idx);
- uint32_t tensor_size = elem_size;
-
- for (uint32_t rank_idx = 0; rank_idx < MAX_RANK; rank_idx++)
- tensor_size *= dims[rank_idx];
-
- /** special handling for TRIV */
- if (layout == DATA_LAYOUT_SRNPU && dims[3] != 3 &&
- dims[3] % DATA_GRANULARITY != 0) {
- tensor_size *= (1 + dims[3] / DATA_GRANULARITY);
- }
-
- return tensor_size;
- }
- uint32_t getOutputTensorSize (uint32_t idx, data_layout layout) const override {
- const uint32_t *dims = getOutputDims (idx);
- uint32_t elem_size = getOutputElemSize (idx);
- uint32_t tensor_size = elem_size;
- for (uint32_t rank_idx = 0; rank_idx < MAX_RANK; rank_idx++)
- tensor_size *= dims[rank_idx];
+ uint32_t getInputTensorSize (uint32_t idx, data_layout layout) const override;
+ uint32_t getOutputTensorSize (uint32_t idx, data_layout layout) const override;
- /** special handling for TRIV */
- if (layout == DATA_LAYOUT_SRNPU && dims[3] != 3 &&
- dims[3] % DATA_GRANULARITY != 0) {
- tensor_size *= (1 + dims[3] / DATA_GRANULARITY);
- }
-
- return tensor_size;
- }
uint32_t getInputElemSize (uint32_t idx) const override {
+ assert (idx < getInputNum ());
return meta_->input_elem_size[idx];
}
uint32_t getOutputElemSize (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
return meta_->output_elem_size[idx];
}
const uint32_t* getInputDims (uint32_t idx) const override {
+ assert (idx < getInputNum ());
return meta_->input_dims[idx];
}
const uint32_t* getOutputDims (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
return meta_->output_dims[idx];
}
uint32_t getInputQuantZero (uint32_t idx) const override {
+ assert (idx < getInputNum ());
return meta_->input_quant_z[idx];
}
float getInputQuantScale (uint32_t idx) const override {
+ assert (idx < getInputNum ());
return meta_->input_quant_s[idx];
}
uint32_t getOutputQuantZero (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
return meta_->output_quant_z[idx];
}
float getOutputQuantScale (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
return meta_->output_quant_s[idx];
}
};
public:
Model (const HWmemImpl* impl);
- void setDataInfo (const tensors_data_info *in, const tensors_data_info *out);
void setConstraint (const npuConstraint& constraint) { constraint_ = constraint; }
+ int setDataInfo (const tensors_data_info *in, const tensors_data_info *out);
int setMetadata (void *data);
const Metadata *getMetadata () const { return meta_.get(); }
uint32_t getID () const { return model_id_; }
+
+ uint32_t getInputTensorNum () const;
+ uint32_t getOutputTensorNum () const;
+
uint32_t getInputTensorSize (uint32_t idx) const;
uint32_t getOutputTensorSize (uint32_t idx) const;
)
test('unittest_ne_core_hwmem', unittest_ne_core_hwmem)
+ unittest_ne_core_model = executable('unittest_ne_core_model',
+ ['ne_core_model_test.cc'],
+ dependencies: [gtest_dep, ne_core_dep],
+ install : true,
+ install_rpath : ne_libdir,
+ install_dir : join_paths(ne_bindir, 'unittests')
+ )
+ test('unittest_ne_core_model', unittest_ne_core_model)
+
# unittest_ne_core_handler = executable('unittest_ne_core_handler',
# ['ne_core_handler_test.cpp'],
# include_directories: ne_host_inc,
--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file ne_core_model_test.cc
+ * @date 14 Apr 2020
+ * @brief Test functionality of model
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <ne-model.h>
+
+#include "ne_unittest_utils.h"
+
+/**
+ * @brief check set/get primitives of model
+ */
+TEST (ne_core_model_test, model_primitives)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ EXPECT_GT (model->getID (), 0);
+
+ /** make dummy metadata */
+ npubin_meta data;
+ data.magiccode = NPUBIN_MAGICCODE | 0x1; /* v1 */
+ data.size = 4096;
+ data.buffer_size = 4096;
+ data.input_size = 2048;
+ data.input_offset = 0;
+ data.output_size = 2048;
+ data.output_offset = 2048;
+ data.program_size = 0;
+ data.weight_size = 0;
+
+ EXPECT_EQ (model->setMetadata (&data), 0);
+ EXPECT_NE (model->getMetadata (), nullptr);
+
+ EXPECT_EQ (model->getInputTensorNum (), 1); /* v1 has one input/output tensors */
+ EXPECT_EQ (model->getOutputTensorNum (), 1);
+
+ EXPECT_EQ (model->getInputTensorSize (0), 2048);
+ EXPECT_EQ (model->getOutputTensorSize (0), 2048);
+
+ /** check default values */
+ npuConstraint constraint = model->getConstraint ();
+ EXPECT_EQ (constraint.timeout_ms, DEFAULT_TIMEOUT);
+ EXPECT_EQ (constraint.priority, DEFAULT_PRIORITY);
+
+ const tensor_data_info * in = model->getInputDataInfo (0);
+ EXPECT_NE (in, nullptr);
+ EXPECT_EQ (in->layout, DATA_LAYOUT_SRNPU);
+ EXPECT_EQ (in->type, DATA_TYPE_SRNPU);
+
+ const tensor_data_info * out = model->getOutputDataInfo (0);
+ EXPECT_NE (out, nullptr);
+ EXPECT_EQ (out->layout, DATA_LAYOUT_SRNPU);
+ EXPECT_EQ (out->type, DATA_TYPE_SRNPU);
+
+ /** user can specify constraint & info */
+ constraint.timeout_ms = 100;
+ constraint.priority = NPU_PRIORITY_HIGH;
+ model->setConstraint (constraint);
+ EXPECT_EQ (constraint.timeout_ms, 100);
+ EXPECT_EQ (constraint.priority, NPU_PRIORITY_HIGH);
+
+ tensors_data_info in_info;
+ in_info.num_info = 2;
+ in_info.info[1].layout = DATA_LAYOUT_NHWC;
+ in_info.info[1].type = DATA_TYPE_QSYMM16;
+
+ tensors_data_info out_info;
+ out_info.num_info = 3;
+ out_info.info[2].layout = DATA_LAYOUT_NCHW;
+ out_info.info[2].type = DATA_TYPE_QASYMM8;
+
+ model->setDataInfo (&in_info, &out_info);
+
+ in = model->getInputDataInfo (1);
+ EXPECT_NE (in, nullptr);
+ EXPECT_EQ (in->layout, DATA_LAYOUT_NHWC);
+ EXPECT_EQ (in->type, DATA_TYPE_QSYMM16);
+
+ out = model->getOutputDataInfo (2);
+ EXPECT_NE (out, nullptr);
+ EXPECT_EQ (out->layout, DATA_LAYOUT_NCHW);
+ EXPECT_EQ (out->type, DATA_TYPE_QASYMM8);
+}
+
+/**
+ * @brief check set/get primitives of model with error handling
+ */
+TEST (ne_core_model_test, model_primitives_invalid_args_n)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ /** invalid arguments */
+ EXPECT_NE (model->setMetadata (nullptr), 0);
+
+ tensors_data_info info;
+ EXPECT_NE (model->setDataInfo (nullptr, nullptr), 0);
+ EXPECT_NE (model->setDataInfo (&info, nullptr), 0);
+ EXPECT_NE (model->setDataInfo (nullptr, &info), 0);
+
+ /** out-of-range */
+ info.num_info = 2;
+ EXPECT_EQ (model->setDataInfo (&info, &info), 0);
+ EXPECT_EQ (model->getInputDataInfo (3), nullptr);
+ EXPECT_EQ (model->getOutputDataInfo (3), nullptr);
+ EXPECT_EQ (model->getInputTensorSize (3), 0);
+ EXPECT_EQ (model->getOutputTensorSize (3), 0);
+}
+
+/**
+ * @brief check set/get primitives of model with error handling
+ */
+TEST (ne_core_model_test, model_primitives_no_metadata_n)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ /** access info without setting metadata */
+ EXPECT_EQ (model->getMetadata (), nullptr);
+ EXPECT_EQ (model->getInputTensorSize (0), 0);
+ EXPECT_EQ (model->getOutputTensorSize (0), 0);
+ EXPECT_EQ (model->getInputDataInfo (0), nullptr);
+ EXPECT_EQ (model->getOutputDataInfo (0), nullptr);
+}
+
+/**
+ * @brief check setMetadata with invalid contents
+ */
+TEST (ne_core_model_test, model_set_metadata_n)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ /** start with the valid metadata */
+ npubin_meta data;
+ data.magiccode = NPUBIN_MAGICCODE | 0x1; /* v1 */
+ data.size = 8192;
+ data.program_size = 2048;
+ data.weight_size = 2048;
+ EXPECT_EQ (model->setMetadata (&data), 0);
+
+ /** invalid magiccode */
+ data.magiccode = 0;
+ EXPECT_NE (model->setMetadata (&data), 0);
+
+ /** unsupported version */
+ data.magiccode = NPUBIN_MAGICCODE | 0x9; /* v9 ?? */
+ EXPECT_NE (model->setMetadata (&data), 0);
+
+ /** invalid number of tensors */
+ data.magiccode = NPUBIN_MAGICCODE | 0x2; /* v2 */
+ data.input_num = MAX_TENSORS + 1;
+ EXPECT_NE (model->setMetadata (&data), 0);
+ data.output_num = MAX_TENSORS + 1;
+ EXPECT_NE (model->setMetadata (&data), 0);
+
+ /** size mismatch */
+ data.input_num = 1;
+ data.output_num = 1;
+ data.size = NPUBIN_META_SIZE / 2;
+ EXPECT_NE (model->setMetadata (&data), 0); /* at least metadata size */
+ data.size = NPUBIN_META_SIZE;
+ data.program_size = NPUBIN_META_SIZE;
+ data.weight_size = NPUBIN_META_SIZE;
+ EXPECT_NE (model->setMetadata (&data), 0); /* size overflow */
+
+ /** TODO add more */
+}
+
+/**
+ * @brief check set/get primitives of metadata v1
+ */
+TEST (ne_core_model_test, metadata_primitives_v1)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ /** make dummy metadata v1 */
+ npubin_meta data;
+
+ data.magiccode = NPUBIN_MAGICCODE | 0x1; /* v1 */
+ data.size = 8192;
+ data.buffer_size = 4096;
+ data.program_size = 2048;
+ data.weight_size = 2048;
+ data.input_offset = 1024;
+ data.input_size = 1024;
+ data.output_offset = 2048;
+ data.output_size = 2048;
+
+ EXPECT_EQ (model->setMetadata (&data), 0);
+
+ const Metadata * meta = model->getMetadata ();
+ EXPECT_NE (meta, nullptr);
+
+ EXPECT_EQ (meta->getVersion (), 1);
+ EXPECT_EQ (meta->getSize (), 8192);
+ EXPECT_EQ (meta->getBufferSize (), 4096);
+ EXPECT_EQ (meta->getProgramSize (), 2048);
+ EXPECT_EQ (meta->getWeightSize (), 2048);
+ EXPECT_EQ (meta->getMetaSize (), 4096);
+
+ EXPECT_EQ (meta->getInputNum (), 1);
+ EXPECT_EQ (meta->getOutputNum (), 1);
+ EXPECT_EQ (meta->getInputOffset (0), 1024);
+ EXPECT_EQ (meta->getInputTensorSize (0, DATA_LAYOUT_SRNPU), 1024);
+ EXPECT_EQ (meta->getOutputOffset (0), 2048);
+ EXPECT_EQ (meta->getOutputTensorSize (0, DATA_LAYOUT_SRNPU), 2048);
+
+ /** return default values for unsupported info */
+ EXPECT_EQ (meta->getInputElemSize (0), 1);
+ EXPECT_EQ (meta->getOutputElemSize (0), 1);
+ EXPECT_EQ (meta->getInputDims (0)[0], meta->getInputTensorSize (0, DATA_LAYOUT_SRNPU));
+ EXPECT_EQ (meta->getOutputDims (0)[0], meta->getOutputTensorSize (0, DATA_LAYOUT_SRNPU));
+ EXPECT_EQ (meta->getInputQuantZero (0), DEFAULT_ZERO_POINT);
+ EXPECT_EQ (meta->getOutputQuantZero (0), DEFAULT_ZERO_POINT);
+ EXPECT_EQ (meta->getInputQuantScale (0), DEFAULT_SCALE);
+ EXPECT_EQ (meta->getOutputQuantScale (0), DEFAULT_SCALE);
+}
+
+/**
+ * @brief check set/get primitives of metadata v2
+ */
+TEST (ne_core_model_test, metadata_primitives_v2)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ /** make dummy metadata v2 */
+ npubin_meta data;
+
+ data.magiccode = NPUBIN_MAGICCODE | 0x2; /* v2 */
+ data.size = 8192;
+ data.buffer_size = 4096;
+ data.program_size = 2048;
+ data.weight_size = 2048;
+
+ uint32_t input_num = 3;
+ uint32_t output_num = 4;
+
+ data.input_num = input_num;
+ for (uint32_t i = 0; i < data.input_num; i++) {
+ data.input_offsets[i] = 100 * (i + 1);
+ data.input_elem_size[i] = 1 * (i + 1);
+ for (uint32_t j = 0; j < MAX_RANK; j++)
+ data.input_dims[i][j] = 2 * (i + 1);
+ data.input_quant_z[i] = 3 * (i + 1);
+ data.input_quant_s[i] = 4 * (i + 1);
+ }
+
+ data.output_num = output_num;
+ for (uint32_t i = 0; i < data.output_num; i++) {
+ data.output_offsets[i] = 100 * (i + 1);
+ data.output_elem_size[i] = 1 * (i + 1);
+ for (uint32_t j = 0; j < MAX_RANK; j++)
+ data.output_dims[i][j] = 2 * (i + 1);
+ data.output_quant_z[i] = 3 * (i + 1);
+ data.output_quant_s[i] = 4 * (i + 1);
+ }
+
+ EXPECT_EQ (model->setMetadata (&data), 0);
+
+ const Metadata * meta = model->getMetadata ();
+ EXPECT_NE (meta, nullptr);
+
+ EXPECT_EQ (meta->getVersion (), 2);
+ EXPECT_EQ (meta->getBufferSize(), 4096);
+ EXPECT_EQ (meta->getProgramSize(), 2048);
+ EXPECT_EQ (meta->getWeightSize(), 2048);
+
+ EXPECT_EQ (meta->getInputNum (), input_num);
+ for (uint32_t i = 0; i < meta->getInputNum (); i++) {
+ EXPECT_EQ (meta->getInputOffset (i), 100 * (i + 1));
+ EXPECT_EQ (meta->getInputElemSize (i), 1 * (i + 1));
+ for (uint32_t j = 0; j < MAX_RANK; j++)
+ EXPECT_EQ (meta->getInputDims(i)[j], 2 * (i + 1));
+ EXPECT_EQ (meta->getInputQuantZero (i), 3 * (i + 1));
+ EXPECT_EQ (meta->getInputQuantScale (i), 4 * (i + 1));
+ }
+
+ EXPECT_EQ (meta->getOutputNum (), output_num);
+ for (uint32_t i = 0; i < meta->getOutputNum (); i++) {
+ EXPECT_EQ (meta->getOutputOffset (i), 100 * (i + 1));
+ EXPECT_EQ (meta->getOutputElemSize (i), 1 * (i + 1));
+ for (uint32_t j = 0; j < MAX_RANK; j++)
+ EXPECT_EQ (meta->getOutputDims(i)[j], 2 * (i + 1));
+ EXPECT_EQ (meta->getOutputQuantZero (i), 3 * (i + 1));
+ EXPECT_EQ (meta->getOutputQuantScale (i), 4 * (i + 1));
+ }
+}
+
+/**
+ * @brief model alloc without driver api
+ */
+TEST (ne_core_model_test, model_alloc_no_drv_api_n)
+{
+ std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+ EXPECT_EQ (model->getDriverAPI (), nullptr);
+ EXPECT_NE (model->alloc (4096), 0);
+}
+
+/** TODO v3 */
+
+/**
+ * @brief main function for unit test
+ */
+int
+main (int argc, char **argv)
+{
+ return start_gtest (argc, argv);
+}