/**
* @brief create input/output tensors using metadata
* @param[in] meta [OPTIONAL] the metadata of model
+ * @return 0 if no error, otherwise a negative errno
* @note if metadata is not provided, this assumes that
* there is a single pair of input/output tensors.
*/
-void Buffer::createTensors (const Metadata *meta)
+int Buffer::createTensors (const Metadata *meta)
{
if (meta != nullptr) {
num_input_ = meta->getInputNum ();
for (uint32_t i = 0; i < num_output_; i++)
output_.push_back (new HWmem (new HWmemChunk));
+ int status = 0;
if (meta != nullptr) {
- for (uint32_t i = 0; i < meta->getInputNum(); i++)
- setInputTensor (i, meta->getInputOffset (i),
+ for (uint32_t i = 0; i < meta->getInputNum(); i++) {
+ status = setInputTensor (i, meta->getInputOffset (i),
meta->getInputTensorSize (i, DATA_LAYOUT_SRNPU));
- for (uint32_t i = 0; i < meta->getOutputNum(); i++)
- setOutputTensor (i, meta->getOutputOffset (i),
+ if (status != 0) {
+ logerr (TAG, "failed to set input tensor: index (%d)\n", i);
+ return status;
+ }
+ }
+ for (uint32_t i = 0; i < meta->getOutputNum(); i++) {
+ status = setOutputTensor (i, meta->getOutputOffset (i),
meta->getOutputTensorSize (i, DATA_LAYOUT_SRNPU));
+ if (status != 0) {
+ logerr (TAG, "failed to set output tensor: index (%d)\n", i);
+ return status;
+ }
+ }
} else {
- setInputTensor (0, 0, getSize());
- setOutputTensor (0, 0, getSize());
+ status = setInputTensor (0, 0, getSize());
+ if (status != 0) {
+ logerr (TAG, "failed to set input tensor: index (0)\n");
+ return status;
+ }
+ status = setOutputTensor (0, 0, getSize());
+ if (status != 0) {
+ logerr (TAG, "failed to set output tensor: index (0)\n");
+ return status;
+ }
}
+
+ return 0;
}
/**
* @param[in] idx tensor index
* @param[in] offset tensor offset in the base buffer
* @param[in] size tensor size
+ * @return 0 if no error. otherwise a negative errno
*/
-void
+int
Buffer::setInputTensor (uint32_t idx, size_t offset, size_t size) {
+ if (size == 0) {
+ logerr (TAG, "Zero size was given\n");
+ return -EINVAL;
+ }
+
if (idx < num_input_) {
input_[idx]->setParent (this);
input_[idx]->setOffset (offset);
if (input_[idx]->alloc (size) != 0) {
logerr (TAG, "failed to allocate output tensor %d\n", idx);
- throw std::bad_alloc();
+ return -ENOMEM;
}
}
+
+ return 0;
}
/**
* @param[in] idx tensor index
* @param[in] offset tensor offset in the base buffer
* @param[in] size tensor size
+ * @return 0 if no error. otherwise a negative errno
*/
-void
+int
Buffer::setOutputTensor (uint32_t idx, size_t offset, size_t size) {
+ if (size == 0) {
+ logerr (TAG, "Zero size was given\n");
+ return -EINVAL;
+ }
+
if (idx < num_output_) {
output_[idx]->setParent (this);
output_[idx]->setOffset (offset);
if (output_[idx]->alloc (size) != 0) {
logerr (TAG, "failed to allocate output tensor %d\n", idx);
- throw std::bad_alloc();
+ return -ENOMEM;
}
}
+
+ return 0;
}
/**
--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file ne_core_buffer_test.cc
+ * @date 14 Apr 2020
+ * @brief Test functionality of buffer
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <ne-buffer.h>
+
+#include "ne_unittest_utils.h"
+
+/**
+ * @brief fill dummy metadata v1
+ */
+static void
+fill_test_metadata_v1 (npubin_meta & data, uint32_t input_size, uint32_t output_size)
+{
+ data.magiccode = NPUBIN_MAGICCODE | 0x1; /* v1 */
+ data.size = 8192;
+ data.buffer_size = 4096;
+ data.program_size = 2048;
+ data.weight_size = 2048;
+
+ data.input_offset = 0;
+ data.input_size = input_size;
+ data.output_offset = 2048;
+ data.output_size = output_size;
+}
+
+/**
+ * @brief fill dummy metadata v2
+ */
+static void
+fill_test_metadata_v2 (npubin_meta & data, uint32_t input_num, uint32_t output_num)
+{
+ data.magiccode = NPUBIN_MAGICCODE | 0x2; /* v2 */
+ data.size = 8192;
+ data.buffer_size = 4096;
+ data.program_size = 2048;
+ data.weight_size = 2048;
+
+ 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);
+ }
+}
+/**
+ * @brief check buffer primitives
+ */
+TEST (ne_core_buffer_test, buffer_primitives)
+{
+ std::unique_ptr<DriverAPI> api;
+ api = DriverAPI::createDriverAPI (NPUCOND_TRIV_CONN_SOCIP, 0);
+ ASSERT_NE (api.get(), nullptr);
+
+ std::unique_ptr<Buffer> buffer (new Buffer (new HWmemDevice));
+ buffer->setDriverAPI (api.get ());
+
+ uint32_t size = 4096;
+ EXPECT_EQ (buffer->alloc (size), 0);
+ EXPECT_EQ (buffer->getSize (), size);
+ EXPECT_EQ (api.get(), buffer->getDriverAPI ());
+
+ /** it's okay even if metadata is nullptr */
+ EXPECT_EQ (buffer->createTensors (nullptr), 0);
+ EXPECT_EQ (buffer->getInputNum (), 1);
+ EXPECT_EQ (buffer->getOutputNum (), 1);
+ EXPECT_EQ (buffer->getInputTensor (0)->getSize (), size);
+ EXPECT_EQ (buffer->getOutputTensor (0)->getSize (), size);
+
+ npubin_meta data;
+ /** with metadata v1 */
+ uint32_t input_size = 1024;
+ uint32_t output_size = 2048;
+ fill_test_metadata_v1 (data, input_size, output_size);
+
+ std::unique_ptr<Metadata> meta = Metadata::extractMetadata (&data);
+ EXPECT_EQ (buffer->createTensors (meta.get()), 0);
+ EXPECT_EQ (buffer->getInputNum (), 1);
+ EXPECT_EQ (buffer->getOutputNum (), 1);
+ EXPECT_EQ (buffer->getInputTensor (0)->getSize (), input_size);
+ EXPECT_EQ (buffer->getOutputTensor (0)->getSize (), output_size);
+
+ /** with metadata v2 */
+ uint32_t input_num = 2;
+ uint32_t output_num = 3;
+ fill_test_metadata_v2 (data, input_num, output_num);
+
+ meta = Metadata::extractMetadata (&data);
+ size = data.size;
+
+ std::unique_ptr<Buffer> buffer2 (new Buffer (new HWmemDevice));
+ buffer2->setDriverAPI (api.get ());
+
+ EXPECT_EQ (buffer2->alloc (size), 0);
+ EXPECT_EQ (buffer2->getSize (), size);
+ EXPECT_EQ (buffer2->createTensors (meta.get()), 0);
+ EXPECT_EQ (buffer2->getInputNum (), input_num);
+ EXPECT_EQ (buffer2->getOutputNum (), output_num);
+
+ for (uint32_t i = 0; i < data.input_num; i++)
+ EXPECT_EQ (buffer2->getInputTensor (i)->getSize (),
+ meta->getInputTensorSize (i, DATA_LAYOUT_SRNPU));
+ for (uint32_t i = 0; i < data.output_num; i++)
+ EXPECT_EQ (buffer2->getOutputTensor (i)->getSize (),
+ meta->getOutputTensorSize (i, DATA_LAYOUT_SRNPU));
+}
+
+/**
+ * @brief check buffer alloc with error handling
+ */
+TEST (ne_core_buffer_test, buffer_alloc_no_drv_api_n)
+{
+ std::unique_ptr<Buffer> buffer (new Buffer (new HWmemDevice));
+
+ uint32_t size = 4096;
+ EXPECT_NE (buffer->alloc (size), 0);
+ EXPECT_NE (buffer->getSize (), size);
+}
+
+/**
+ * @brief check buffer's createTensors() with error handling
+ */
+TEST (ne_core_buffer_test, buffer_create_tensors_n)
+{
+ std::unique_ptr<DriverAPI> api;
+ api = DriverAPI::createDriverAPI (NPUCOND_TRIV_CONN_SOCIP, 0);
+ ASSERT_NE (api.get(), nullptr);
+
+ uint32_t size = 4096;
+ std::unique_ptr<Buffer> buffer (new Buffer (new HWmemDevice));
+ buffer->setDriverAPI (api.get());
+ ASSERT_EQ (buffer->alloc (size), 0);
+
+ /** createTensors() after dealloc the base buffer */
+ EXPECT_EQ (buffer->dealloc (), 0);
+ EXPECT_NE (buffer->createTensors (nullptr), 0);
+}
+
+/**
+ * @brief check buffer getInput/OutputTensor with error handling
+ */
+TEST (ne_core_buffer_test, buffer_get_tensor_n)
+{
+ std::unique_ptr<DriverAPI> api;
+ api = DriverAPI::createDriverAPI (NPUCOND_TRIV_CONN_SOCIP, 0);
+ ASSERT_NE (api.get(), nullptr);
+
+ std::unique_ptr<Buffer> buffer (new Buffer (new HWmemDevice));
+ buffer->setDriverAPI (api.get ());
+
+ uint32_t input_num = 2;
+ uint32_t output_num = 3;
+
+ npubin_meta data;
+ fill_test_metadata_v2 (data, input_num, output_num);
+ ASSERT_EQ (buffer->alloc (data.buffer_size), 0);
+
+ /** invalid index */
+ EXPECT_EQ (buffer->getInputTensor (input_num + 1), nullptr);
+ EXPECT_EQ (buffer->getOutputTensor (output_num + 1), nullptr);
+}
+
+/**
+ * @brief main function for unit test
+ */
+int
+main (int argc, char **argv)
+{
+ return start_gtest (argc, argv);
+}