--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file ne_libnpuhost_test.cc
+ * @date 12 Aug 2020
+ * @brief UnitTests to test functionality of libnpuhost APIs
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <errno.h>
+#include <dirent.h>
+#include <linux/limits.h>
+#include <pthread.h>
+
+#include <libnpuhost.h>
+#include <ne_test_utils.h>
+
+#include "ne_unittest_utils.h"
+
+/**
+ * @brief test APIs to check number of devices
+ */
+TEST (ne_libnpuhost_test, get_num_devices)
+{
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_TRIV_CONN_SOCIP), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_TRIV2_CONN_SOCIP), 0);
+
+ /* other aliases also work */
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_CONN_UNKNOWN), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_CONN_USB), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_CONN_SOCIP), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_CONN_PCIE), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_CONN_FILESYS), 0);
+
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_TRIV_CONN_UNKNOWN), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_TRIV2_CONN_UNKNOWN), 0);
+
+ /* TRIA is not supported in FastModel */
+#if defined(ENABLE_EMUL)
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_TRIA_CONN_SOCIP), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_TRIA_CONN_UNKNOWN), 0);
+
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_ASR_CONN_SOCIP), 0);
+ EXPECT_GT (getnumNPUdeviceByType (NPUCOND_ASR_CONN_UNKNOWN), 0);
+#endif
+}
+
+/**
+ * @brief test APIs to check number of devices (negative cases)
+ */
+TEST (ne_libnpuhost_test, get_num_devices_n)
+{
+ EXPECT_EQ (getnumNPUdeviceByType ((dev_type) 0), 0);
+ EXPECT_EQ (getnumNPUdeviceByType ((dev_type) 0x1234), 0);
+ EXPECT_EQ (getnumNPUdeviceByType ((dev_type) 0xdeadbeef), 0);
+ EXPECT_EQ (getnumNPUdeviceByType ((dev_type) 0xffffffff), 0);
+}
+
+static dev_type test_types[] = {
+ NPUCOND_TRIV_CONN_SOCIP,
+#if defined(ENABLE_EMUL)
+ NPUCOND_TRIA_CONN_SOCIP,
+#endif
+ NPUCOND_TRIV2_CONN_SOCIP
+};
+
+/**
+ * @brief test APIs to get a device instance
+ */
+TEST (ne_libnpuhost_test, get_device_instance)
+{
+ npudev_h dev;
+ int num_devices;
+
+ for (int i = 0; i < sizeof(test_types) / sizeof(dev_type); i++) {
+ dev_type type = test_types[i];
+ num_devices = getnumNPUdeviceByType (type);
+ ASSERT_GT (num_devices, 0);
+
+ for (int j = 0; j < num_devices; j++) {
+ EXPECT_EQ (getNPUdeviceByType (&dev, type, j), 0);
+ putNPUdevice (dev);
+ }
+ }
+}
+
+/**
+ * @brief test APIs to get a device instance (negative cases)
+ */
+TEST (ne_libnpuhost_test, get_device_instance_n)
+{
+ npudev_h dev;
+ int num_devices;
+
+ for (int i = 0; i < sizeof(test_types) / sizeof(dev_type); i++) {
+ dev_type type = test_types[i];
+ num_devices = getnumNPUdeviceByType (type);
+ ASSERT_GT (num_devices, 0);
+
+ for (int j = 0; j < num_devices; j++) {
+ EXPECT_NE (getNPUdeviceByType (&dev, (dev_type) 0x0, j), 0);
+ EXPECT_NE (getNPUdeviceByType (&dev, (dev_type) 0x1234, j), 0);
+ EXPECT_NE (getNPUdeviceByType (&dev, (dev_type) 0xdeadbeef, j), 0);
+ EXPECT_NE (getNPUdeviceByType (&dev, (dev_type) 0xffffffff, j), 0);
+ }
+ }
+}
+
+class TesterTrinity {
+ public:
+ TesterTrinity () : done_ (0), repeat_ (0) {}
+
+ void wait_runs () {
+ std::unique_lock<std::mutex> lock (m_);
+ cv_.wait (lock, [this]() { return done_ == repeat_; });
+ }
+
+ void setRepeat (uint32_t repeat) { repeat_ = repeat; }
+
+ static void callback (output_buffers *output, uint64_t sequence,
+ void *data) {
+ TesterTrinity *tester = static_cast<TesterTrinity *>(data);
+ tester->finish (output);
+ }
+
+ private:
+ void finish (output_buffers * output) {
+ for (uint32_t idx = 0; idx < output->num_buffers; idx++) {
+ char * output_data = static_cast<char*> (output->bufs[idx].addr);
+ /* do nothing */
+ free (output_data);
+
+ }
+
+ std::unique_lock<std::mutex> lock (m_);
+ done_++;
+ cv_.notify_one ();
+ }
+
+ uint32_t done_;
+ uint32_t repeat_;
+
+ std::mutex m_;
+ std::condition_variable cv_;
+};
+
+class TesterTRIA : public TesterTrinity, public UtilTRIA {
+ public:
+ TesterTRIA () {}
+};
+
+class TesterTRIV : public TesterTrinity, public UtilTRIV {
+ public:
+ TesterTRIV () {}
+};
+
+class TesterTRIV2 : public TesterTrinity, public UtilTRIV2 {
+ public:
+ TesterTRIV2 () {}
+};
+
+/**
+ * @brief test APIs to run model with input data (TRIV)
+ */
+TEST (ne_libnpuhost_test, run_input_triv_binfmt_v1)
+{
+ TesterTRIV tester;
+
+ ASSERT_EQ (tester.init (), 0);
+
+ std::string model_dir (NE_DATADIR);
+ model_dir += "/testdata/npubinfmt_v1/testcase1";
+
+ tester.setModelDir (model_dir);
+ ASSERT_EQ (tester.loadModel (), 0);
+
+ const npubin_meta *meta = tester.getMetadata ();
+ ASSERT_NE (meta, nullptr);
+
+ /* prepare input */
+ std::string input_path = model_dir + "/input_fmap.bin";
+
+ input_buffers input;
+ input.num_buffers = 1;
+
+ input.bufs[0].size = get_file_size (input_path.c_str ());
+ input.bufs[0].filepath = input_path.c_str ();
+ input.bufs[0].type = BUFFER_FILE;
+
+ /* run input */
+ output_buffers output;
+ EXPECT_EQ (tester.run (&input, &output), 0);
+
+ tester.setRepeat (3);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ tester.wait_runs ();
+}
+
+/**
+ * @brief test APIs to run model with input data (TRIV)
+ */
+TEST (ne_libnpuhost_test, run_input_triv_binfmt_v2)
+{
+ TesterTRIV tester;
+
+ ASSERT_EQ (tester.init (), 0);
+
+ std::string model_dir (NE_DATADIR);
+ model_dir += "/testdata/npubinfmt_v2/testcase1";
+
+ tester.setModelDir (model_dir);
+ ASSERT_EQ (tester.loadModel (), 0);
+
+ const npubin_meta *meta = tester.getMetadata ();
+ ASSERT_NE (meta, nullptr);
+
+ /* prepare input */
+ std::vector<std::string> input_path;
+ input_buffers input;
+
+ input_path.resize (meta->input_num);
+ input.num_buffers = meta->input_num;
+ for (uint32_t idx = 0; idx < meta->input_num; idx++) {
+ input_path[idx] = model_dir + "/input_fmap_" + std::to_string (idx) + ".bin";
+ input.bufs[idx].size = get_file_size (input_path[idx].c_str ());
+ input.bufs[idx].filepath = input_path[idx].c_str ();
+ input.bufs[idx].type = BUFFER_FILE;
+ }
+
+ /* run input */
+ output_buffers output;
+ EXPECT_EQ (tester.run (&input, &output), 0);
+
+ tester.setRepeat (3);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ tester.wait_runs ();
+}
+
+#if defined(ENABLE_EMUL)
+/**
+ * @brief test APIs to run model with input data (TRIA)
+ */
+TEST (ne_libnpuhost_test, run_input_tria)
+{
+ TesterTRIA tester;
+
+ ASSERT_EQ (tester.init (), 0);
+
+ /* run input */
+ input_buffers input;
+ input.num_buffers = 1;
+ input.bufs[0].size = 4096;
+ input.bufs[0].type = BUFFER_MAPPED;
+
+ ASSERT_EQ (allocNPU_inputBuffers (tester.getDeviceHandle (), &input), 0);
+
+ output_buffers output;
+ EXPECT_EQ (tester.run (&input, &output), 0);
+
+ tester.setRepeat (3);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ tester.wait_runs ();
+
+ cleanNPU_inputBuffers (tester.getDeviceHandle (), &input);
+}
+#endif
+
+/**
+ * @brief test APIs to run model with input data (TRIV2)
+ */
+TEST (ne_libnpuhost_test, run_input_triv2_binfmt_v3)
+{
+ TesterTRIV2 tester;
+
+ ASSERT_EQ (tester.init (), 0);
+
+ std::string model_dir (NE_DATADIR);
+ model_dir += "/testdata/npubinfmt_v3/CONV_I8_008";
+
+ tester.setModelDir (model_dir);
+ ASSERT_EQ (tester.loadModel (), 0);
+
+ const npubin_meta *meta = tester.getMetadata ();
+ ASSERT_NE (meta, nullptr);
+
+ /* prepare input */
+ std::vector<std::string> input_path;
+ input_buffers input;
+
+ input_path.resize (meta->input_seg_num);
+ input.num_buffers = meta->input_seg_num;
+ for (uint32_t idx = 0; idx < meta->input_seg_num; idx++) {
+ input_path[idx] = model_dir + "/input_fmap_" + std::to_string (idx) + ".bin";
+ input.bufs[idx].size = get_file_size (input_path[idx].c_str ());
+ input.bufs[idx].filepath = input_path[idx].c_str ();
+ input.bufs[idx].type = BUFFER_FILE;
+ }
+
+ /* run input */
+ output_buffers output;
+ EXPECT_EQ (tester.run (&input, &output), 0);
+
+ tester.setRepeat (3);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+ EXPECT_EQ (tester.run (&input, TesterTrinity::callback,
+ dynamic_cast<TesterTrinity *>(&tester)), 0);
+
+ tester.wait_runs ();
+}
+
+/**
+ * @brief test APIs to run model with internal input (TRIV2)
+ */
+TEST (ne_libnpuhost_test, run_internal_triv2_binfmt_v3)
+{
+ TesterTRIV2 tester;
+
+ ASSERT_EQ (tester.init (), 0);
+
+ std::string model_dir (NE_DATADIR);
+ model_dir += "/testdata/npubinfmt_v3/CONV_I8_008";
+
+ tester.setModelDir (model_dir);
+ ASSERT_EQ (tester.loadModel (), 0);
+
+ const npubin_meta *meta = tester.getMetadata ();
+ ASSERT_NE (meta, nullptr);
+
+ /* run internal */
+ int id = tester.run ("/dev/dummy");
+ EXPECT_GT (id, 0);
+
+ usleep (TEST_SLEEP_MS);
+
+ EXPECT_EQ (tester.stop (id), 0);
+}
+
+/**
+ * @brief main function for unit test
+ */
+int
+main (int argc, char **argv)
+{
+ return start_gtest (argc, argv);
+}