This patch revises some apptests to use common test utility.
Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
/**
* @file tvn_triv2.cc
* @date 09 Jul 2020
- * @brief AppTest to test multiple runs with the same model
+ * @brief AppTest to test a single inference for TRIV2 device
* @author Dongju Chae <dongju.chae@samsung.com>
* @bug No known bugs except for NYI items
*/
-#include <libnpuhost.h>
#include <ne_test_utils.h>
-#include <string.h>
-#include <unistd.h>
-#include <iostream>
-#include <fstream>
-
-#include <mutex>
-#include <condition_variable>
-
-/** ./include/typedef.h */
-#define TRIV2_TYPE NPUCOND_TRIV2_CONN_SOCIP
-#define NPU_MODEL_NAME "model.tvn"
#define NPU_TIMEOUT_MS 5000
+using namespace std;
+
/** @brief C++ class to describe how to use npu-engine library */
-class TesterTRIV2 {
+class Tester : public UtilTRIV2
+{
public:
- TesterTRIV2 () : dev_ (nullptr), meta_ (nullptr), model_id_ (0) {
- success_ = done_ = 0;
- async_ = false;
- noti_mode_ = NPU_INTERRUPT;
- repeat_ = 1;
- }
-
- ~TesterTRIV2 () {
- /** release resources */
- if (dev_ != nullptr) {
- if (model_id_ > 0)
- unregisterNPUmodel (dev_, model_id_);
-
- if (meta_ != nullptr)
- free (meta_);
-
- putNPUdevice (dev_);
- }
- }
-
- void set_async () {
- async_ = true;
- }
-
- void set_repeat (const std::string repeat_str) {
- repeat_ = std::stoi (repeat_str);
- }
-
- void set_noti_mode (const std::string mode_str) {
- if (mode_str == "polling")
- noti_mode_ = NPU_POLLING;
- else if (mode_str == "intr")
- noti_mode_ = NPU_INTERRUPT;
- else
- std::cerr << "Unknown notimode: " << mode_str << std::endl;
- }
+ Tester () : model_id_ (0) {}
/** @brief initilize the device handle */
- int init (const std::string dir) {
- int num_devices = getnumNPUdeviceByType (TRIV2_TYPE);
- if (num_devices <= 0)
- return -ENODEV;
-
- /** use any available TRIV2 device. (0 <= dev_id < num_devices) */
- int dev_id = num_devices - 1;
-
- dir_ = dir;
- return getNPUdeviceByType (&dev_, TRIV2_TYPE, dev_id);
- }
-
- /** @brief run the inference (with dummy data) */
- int run () {
- int status = prepare_model ();
- if (status != 0)
- return status;
-
- status = set_data_info ();
- if (status != 0)
- return status;
-
- status = set_constraint ();
- if (status != 0)
+ int init (std::string model_dir) {
+ int status = UtilTRIV2::init ();
+ if (status != test_ret_success) {
+ cerr << "Failed to initialize\n";
return status;
-
- for (uint32_t i = 0; i < repeat_; i++) {
- input_buffers input;
-
- status = prepare_input (&input);
- if (status != 0)
- return status;
-
- if (async_) {
- status = runNPU_async (dev_, model_id_, &input, callback,
- NULL, this, NPUASYNC_WAIT);
- if (status != 0)
- return status;
- } else {
- output_buffers output;
-
- status = runNPU_sync (dev_, model_id_, &input, &output);
- if (status != 0)
- return status;
-
- compare_result (&output);
- }
-
- cleanNPU_inputBuffers (dev_, &input);
}
- return wait_runs ();
+ return UtilTRIV2::loadModel (
+ model_dir, &model_id_, NPU_PRIORITY_MID, NPU_TIMEOUT_MS);
}
- int wait_runs () {
- std::unique_lock<std::mutex> lock (m_);
- cv_.wait (lock, [this]() { return done_ == repeat_; });
-
- return success_ == repeat_ ? 0 : -EINVAL;
- }
+ /** @brief run the inference */
+ int run () {
+ if (model_id_ == 0)
+ return test_ret_failure;
- static void callback (output_buffers *output, uint64_t sequence,
- void *data) {
- TesterTRIV2 *tester = static_cast<TesterTRIV2 *>(data);
+ int task_id = UtilTRIV2::run (model_id_);
+ if (task_id < 0)
+ return task_id;
- tester->compare_result (output);
+ return wait () == 1 ? test_ret_success : test_ret_failure;
}
private:
- int prepare_model () {
- generic_buffer model;
- std::string model_path;
-
- model_path = dir_ + "/" + NPU_MODEL_NAME;
-
- meta_ = getNPUmodel_metadata (model_path.c_str(), false);
- if (meta_ == nullptr)
- return -EINVAL;
-
- if (NPUBIN_VERSION (meta_->magiccode) != 3)
- return -EINVAL;
-
- model.type = BUFFER_FILE;
- model.size = meta_->size;
- model.filepath = model_path.c_str();
-
- int status = allocNPU_modelBuffer (dev_, &model);
- if (status != 0)
- return status;
-
- status = registerNPUmodel (dev_, &model, &model_id_);
- cleanNPU_modelBuffer (dev_, &model);
-
- return status;
- }
-
- int prepare_input (input_buffers *input) {
- input->num_buffers = meta_->input_seg_num;
- for (uint32_t idx = 0; idx < meta_->input_seg_num; idx++) {
- const char *filepath = input_path_[idx].c_str();
-
- input->bufs[idx].size = get_file_size (filepath);
- input->bufs[idx].filepath = filepath;
- input->bufs[idx].type = BUFFER_FILE;
- }
-
- return allocNPU_inputBuffers (dev_, input);
- }
-
- int set_data_info () {
- tensors_data_info info_in;
- tensors_data_info info_out;
-
- /* No data manipulation & quantization in this test */
-
- info_in.num_info = meta_->input_seg_num;
- for (uint32_t idx = 0; idx < info_in.num_info; idx++) {
- info_in.info[idx].layout = DATA_LAYOUT_TRIV2;
- info_in.info[idx].type = DATA_TYPE_QASYMM8;
-
- input_path_[idx] = dir_ + "/input_fmap_" + std::to_string (idx) + ".bin";
- }
-
- info_out.num_info = meta_->output_seg_num;
- for (uint32_t idx = 0; idx < info_out.num_info; idx++) {
- info_out.info[idx].layout = DATA_LAYOUT_TRIV2;
- info_out.info[idx].type = DATA_TYPE_QASYMM8;
-
- output_path_[idx] = dir_ + "/output_fmap_" + std::to_string (idx) + ".bin";
- }
-
- return setNPU_dataInfo (dev_, model_id_, &info_in, &info_out);
- }
-
- int set_constraint () {
- npuConstraint constraint;
-
- constraint.timeout_ms = NPU_TIMEOUT_MS;
- constraint.priority = NPU_PRIORITY_MID;
- constraint.notimode = noti_mode_;
-
- return setNPU_constraint (dev_, model_id_, constraint);
- }
-
- void compare_result (output_buffers * output) {
- int err = 0;
-
- for (uint32_t idx = 0; idx < output->num_buffers; idx++) {
- char * output_data = static_cast<char*> (output->bufs[idx].addr);
- off_t output_size = output->bufs[idx].size;
- std::string golden_path;
-
- err = compare_data (output_path_[idx].c_str(), output_data, output_size);
- assert (output->bufs[idx].type == BUFFER_MAPPED);
-
- free (output_data);
-
- if (err != 0)
- break;
- }
-
- {
- std::unique_lock<std::mutex> lock (m_);
- done_++;
- if (err == 0)
- success_++;
- cv_.notify_one ();
- }
- }
-
- std::string dir_;
-
- npudev_h dev_;
-
- npubin_meta *meta_;
uint32_t model_id_;
-
- bool async_;
- uint32_t success_;
- uint32_t done_;
- uint32_t repeat_;
-
- npu_notimode noti_mode_;
-
- std::mutex m_;
- std::condition_variable cv_;
-
- std::string input_path_[MAX_TENSORS];
- std::string output_path_[MAX_TENSORS];
};
-static void
-print_usage (const char *prog_name)
-{
- std::cerr << "Usage: " << prog_name << " [options] model_dir\n";
- std::cerr << "Options: \n";
- std::cerr << " -i <arg> \t Set output notimode [intr|polling]\n";
- std::cerr << " -n <arg> \t Set number of repetition\n";
- std::cerr << " -a \t\t Set async mode\n";
- std::cerr << " -h \t\t Show help messages\n";
-}
-
/** @brief apptest main */
int
main (int argc, char **argv)
{
- TesterTRIV2 tester;
- int c, status;
-
- optind = 0;
- opterr = 0;
- while ((c = getopt (argc, argv, "ahn:i:")) != -1) {
- switch (c) {
- case 'a':
- tester.set_async ();
- break;
- case 'n':
- tester.set_repeat (optarg);
- break;
- case 'i':
- tester.set_noti_mode (optarg);
- break;
- case '?':
- if (optopt == 'i' || optopt == 'n')
- std::cerr << "Option -i or -n requires an extra argument";
- else
- std::cerr << "Unknown flag: " << c;
- std::cerr << std::endl;
- // no-break
- case 'h':
- print_usage(argv[0]);
- return 0;
- }
- }
-
- if (optind >= argc) {
- std::cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
- return 0;
- }
+ Tester tester;
+ char * dir;
+ int status;
+
+ status = tester.parseArgs (argc, argv, &dir, "[model dir]");
+ if (status == test_ret_skipped || dir == nullptr)
+ goto skip;
+ else if (status != test_ret_success)
+ goto err;
/** initialize triv2 device */
- status = tester.init (argv[optind]);
- if (status != 0)
+ status = tester.init (dir);
+ if (status < test_ret_success)
goto err;
/** run the inference with the device */
status = tester.run ();
- if (status != 0)
+ if (status < test_ret_success)
goto err;
- std::cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
+ cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
return 0;
err:
- std::cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
+ cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
return status;
+
+skip:
+ cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+ return 0;
}
* @bug No known bugs except for NYI items
*/
-#include <string.h>
-#include <unistd.h>
-
#include <ne_test_utils.h>
+#define NPU_TIMEOUT_MS 5000
+
using namespace std;
+/** @brief C++ class to describe how to use npu-engine library */
class Tester : public UtilTRIV2
{
public:
- Tester () : total_ (0), debug_ (false), sync_ (false) {}
-
- void set_debug () {
- debug_ = true;
- }
-
- void set_mute () {
- /** redirect to /dev/null */
- if (freopen("/dev/null", "w", stdout) == NULL)
- cerr << "Warning: Failed to reopen stdout\n";
- if (freopen("/dev/null", "w", stderr) == NULL)
- cerr << "Warning: Failed to reopen stderr\n";
- }
-
- void set_sync () {
- sync_ = true;
- }
-
- int load_model (std::string model) {
- npu_priority priority = NPU_PRIORITY_MID;
- uint32_t timeout = 1000;
+ Tester () : model_id_ (0) {}
- total_++;
-
- return UtilTRIV2::loadModel (model, &model_id_,
- static_cast<npu_priority>(priority), timeout);
- }
-
- int init (std::string model) {
+ /** @brief initilize the device handle */
+ int init (std::string model_dir) {
int status = UtilTRIV2::init ();
- if (status != 0) {
+ if (status != test_ret_success) {
cerr << "Failed to initialize\n";
return status;
}
- return load_model (model);
+ return UtilTRIV2::loadModel (
+ model_dir, &model_id_, NPU_PRIORITY_MID, NPU_TIMEOUT_MS);
}
+ /** @brief run the inference */
int run () {
- int status = UtilTRIV2::run (model_id_, callback, sync_);
- if (status < 0) {
- cerr << "Failed to run the model: " << status << "\n";
- return status;
- }
+ if (model_id_ == 0)
+ return test_ret_failure;
- wait_runs ();
+ int task_id = UtilTRIV2::run (model_id_);
+ if (task_id < 0)
+ return task_id;
- print_profile (status);
+ int result = wait () == 1 ? test_ret_success : test_ret_failure;
- return passed_ == total_ ? 0 : -EINVAL;
+ print_profile (task_id);
+
+ return result;
}
+ /** @brief print profile */
void print_profile (int task_id) {
npu_profile profile;
int status = UtilTRIV2::getProfile (task_id, &profile);
}
}
- void wait_runs () {
- unique_lock<mutex> lock (m_);
- cv_.wait (lock, [this]() { return done_ == total_; });
- }
-
- static void callback (output_buffers *output, uint64_t sequence,
- void *data) {
- const char *dirpath = static_cast<const char *> (data);
- int err = 0;
-
- for (uint32_t idx = 0; idx < output->num_buffers; idx++) {
- char * output_data = static_cast<char*> (output->bufs[idx].addr);
- off_t output_size = output->bufs[idx].size;
- std::string golden_path (dirpath);
-
- golden_path += "/output_fmap_" + std::to_string (idx) + ".bin";
- err = compare_data (golden_path.c_str(), output_data, output_size);
- free (output_data);
-
- if (err != 0)
- break;
- }
-
- report (err == 0);
- }
-
- static void report (bool passed) {
- unique_lock<mutex> lock (m_);
- done_++;
- if (passed)
- passed_++;
- cv_.notify_one ();
- }
-
private:
- static mutex m_;
- static condition_variable cv_;
- static uint32_t done_;
- static uint32_t passed_;
-
uint32_t model_id_;
- uint32_t total_;
- bool debug_;
- bool sync_;
};
-mutex Tester::m_;
-condition_variable Tester::cv_;
-uint32_t Tester::done_ = 0;
-uint32_t Tester::passed_ = 0;
-
-static void
-print_usage (const char *prog_name)
-{
- cerr << "Usage: " << prog_name << " [options] [model dirpath]\n";
- cerr << "Options: \n";
- cerr << " -h \t\t Show help messages\n";
- cerr << " -m \t\t Mute stdout/stderr messages\n";
- cerr << " -d \t\t Enable debugging mode\n";
- cerr << " -s \t\t Enable run sync mode\n";
-}
-
/** @brief apptest main */
int
main (int argc, char **argv)
{
Tester tester;
- int c, status;
-
- optind = 0;
- opterr = 0;
- while ((c = getopt (argc, argv, "dmsh")) != -1) {
- switch (c) {
- case 'd':
- tester.set_debug ();
- break;
- case 'm':
- tester.set_mute ();
- break;
- case 's':
- tester.set_sync ();
- break;
- case 'h':
- print_usage(argv[0]);
- return 0;
- }
- }
+ char * dir;
+ int status;
- if (optind >= argc) {
- cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
- return 0;
- }
+ status = tester.parseArgs (argc, argv, &dir, "[model dir]");
+ if (status == test_ret_skipped || dir == nullptr)
+ goto skip;
+ else if (status != test_ret_success)
+ goto err;
/** initialize triv2 device */
- status = tester.init (argv[optind]);
- if (status != 0)
+ status = tester.init (dir);
+ if (status < test_ret_success)
goto err;
/** run the inference with the device */
status = tester.run ();
- if (status != 0)
+ if (status < test_ret_success)
goto err;
cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
err:
cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
return status;
+
+skip:
+ cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+ return 0;
}
* </testcases>
*/
-#include <string.h>
-#include <unistd.h>
-
#include <tinyxml2.h>
#include <ne_test_utils.h>
using namespace std;
using namespace tinyxml2;
+/** @brief C++ class to describe how to use npu-engine library */
class Tester : public UtilTRIV2
{
public:
- Tester () : total_ (0), debug_ (false), sync_ (false) {}
+ Tester () : total_ (0) {}
- void set_debug () {
- debug_ = true;
- }
+ /** @brief initilize the device handle */
+ int init (std::string xml_file) {
+ int status = UtilTRIV2::init ();
+ if (status != 0) {
+ cerr << "Failed to initialize\n";
+ return status;
+ }
- void set_mute () {
- /** redirect to /dev/null */
- if (freopen("/dev/null", "w", stdout) == NULL)
- cerr << "Warning: Failed to reopen stdout\n";
- if (freopen("/dev/null", "w", stderr) == NULL)
- cerr << "Warning: Failed to reopen stderr\n";
- }
+ XMLDocument doc;
+ if (doc.LoadFile (xml_file.c_str ()) != XML_SUCCESS) {
+ cerr << "Unable to find the given xml file\n";
+ return -ENOENT;
+ }
- void set_sync () {
- sync_ = true;
+ status = parse_xml (doc);
+ if (status != 0) {
+ cerr << "Invalid model description detected\n";
+ return status;
+ }
+
+ return 0;
}
+ /** @brief parse the model xml file */
int parse_xml (XMLDocument& xml) {
XMLElement *root = xml.RootElement ();
if (root == nullptr)
return 0;
}
- int init (string xml_file) {
- int status = UtilTRIV2::init ();
- if (status != 0) {
- cerr << "Failed to initialize\n";
- return status;
- }
-
- XMLDocument doc;
- if (doc.LoadFile (xml_file.c_str ()) != XML_SUCCESS) {
- cerr << "Unable to find the given xml file\n";
- return -ENOENT;
- }
-
- status = parse_xml (doc);
- if (status != 0) {
- cerr << "Invalid model description detected\n";
- return status;
- }
-
- return 0;
- }
-
+ /** @brief run the inference */
int run () {
- int status = UtilTRIV2::runAll (callback, sync_);
+ int status = UtilTRIV2::runAll ();
if (status != 0) {
- cerr << "Failed to run the model: " << status << "\n";
+ cerr << "Failed to run models in .xml file: " << status << "\n";
return status;
}
- wait_runs ();
-
- return passed_ == total_ ? 0 : -EINVAL;
- }
-
- void wait_runs () {
- unique_lock<mutex> lock (m_);
- cv_.wait (lock, [this]() { return done_ == total_; });
- }
-
- static void callback (output_buffers *output, uint64_t sequence,
- void *data) {
- const char *dirpath = static_cast<const char *> (data);
- int err = 0;
-
- for (uint32_t idx = 0; idx < output->num_buffers; idx++) {
- char * output_data = static_cast<char*> (output->bufs[idx].addr);
- off_t output_size = output->bufs[idx].size;
- std::string golden_path (dirpath);
-
- golden_path += "/output_fmap_" + std::to_string (idx) + ".bin";
- err = compare_data (golden_path.c_str(), output_data, output_size);
- free (output_data);
-
- if (err != 0)
- break;
- }
-
- report (err == 0);
- }
-
- static void report (bool passed) {
- unique_lock<mutex> lock (m_);
- done_++;
- if (passed)
- passed_++;
- cv_.notify_one ();
+ return wait () == total_ ? test_ret_success : test_ret_failure;
}
private:
- static mutex m_;
- static condition_variable cv_;
- static uint32_t done_;
- static uint32_t passed_;
-
uint32_t total_;
- bool debug_;
- bool sync_;
};
-mutex Tester::m_;
-condition_variable Tester::cv_;
-uint32_t Tester::done_ = 0;
-uint32_t Tester::passed_ = 0;
-
-static void
-print_usage (const char *prog_name)
-{
- cerr << "Usage: " << prog_name << " [options] [.xml file]\n";
- cerr << "Options: \n";
- cerr << " -h \t\t Show help messages\n";
- cerr << " -m \t\t Mute stdout/stderr messages\n";
- cerr << " -d \t\t Enable debugging mode\n";
- cerr << " -s \t\t Enable run sync mode\n";
-}
-
/** @brief apptest main */
int
main (int argc, char **argv)
{
Tester tester;
- int c, status;
-
- optind = 0;
- opterr = 0;
- while ((c = getopt (argc, argv, "dmsh")) != -1) {
- switch (c) {
- case 'd':
- tester.set_debug ();
- break;
- case 'm':
- tester.set_mute ();
- break;
- case 's':
- tester.set_sync ();
- break;
- case 'h':
- print_usage(argv[0]);
- return 0;
- }
- }
+ char * xml_file;
+ int status;
- if (optind >= argc) {
- cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
- return 0;
- }
+ status = tester.parseArgs (argc, argv, &xml_file, "[.xml file]");
+ if (status == test_ret_skipped || xml_file == nullptr)
+ goto skip;
+ else if (status != test_ret_success)
+ goto err;
/** initialize triv2 device */
- status = tester.init (argv[optind]);
- if (status != 0)
+ status = tester.init (xml_file);
+ if (status < test_ret_success)
goto err;
/** run the inference with the device */
status = tester.run ();
- if (status != 0)
+ if (status < test_ret_success)
goto err;
cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
err:
cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
return status;
+
+skip:
+ cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+ return 0;
}
putNPUdevice (dev);
}
-struct test_sync {
- std::mutex m;
- std::condition_variable cv;
- int done;
-};
-
-static struct test_sync tsync;
-
-static void wait_runs (int total)
-{
- std::unique_lock<std::mutex> lock (tsync.m);
- tsync.cv.wait (lock, [&]() { return tsync.done == total; });
-}
-
-/**
- * @brief dummy callback for testing
- */
-static void callback (output_buffers *output,
- uint64_t sequence, void *data)
-{
- for (uint32_t idx = 0; idx < output->num_buffers; idx++) {
- /* do not check the validity of output data */
- free (output->bufs[idx].addr);
- }
-
- std::unique_lock<std::mutex> lock (tsync.m);
- tsync.done++;
- tsync.cv.notify_one ();
-}
-
/**
* @brief test APIs to run model with input data (TRIV)
*/
uint32_t model_id = 0;
- tsync.done = 0;
-
if (tester.loadModel (model_dir, &model_id) != 0)
/* skip */
return;
- EXPECT_EQ (tester.run (model_id, callback, true), 0);
- EXPECT_EQ (tester.run (model_id, callback, false), 0);
- EXPECT_EQ (tester.runAll (callback, true), 0);
- EXPECT_EQ (tester.runAll (callback, false), 0);
+ EXPECT_EQ (tester.run (model_id, true), 0);
+ EXPECT_EQ (tester.run (model_id, false), 0);
- wait_runs (4);
+ EXPECT_EQ (tester.runAll (true), 0);
+ EXPECT_EQ (tester.runAll (false), 0);
+
+ EXPECT_EQ (tester.wait (), 4);
}
/**
UtilTRIV tester;
/* without init */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
ASSERT_EQ (tester.init (), 0);
/* run without model */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
/* invalid model id */
std::string model_dir (NE_DATADIR);
/* skip */
return;
- EXPECT_NE (tester.run (model_id + 1, callback, true), 0);
+ EXPECT_NE (tester.run (model_id + 1, true), 0);
}
/**
uint32_t model_id = 0;
- tsync.done = 0;
-
if (tester.loadModel (model_dir, &model_id) != 0)
/* skip */
return;
- EXPECT_EQ (tester.run (model_id, callback, true), 0);
- EXPECT_EQ (tester.run (model_id, callback, false), 0);
+ EXPECT_EQ (tester.run (model_id, true), 0);
+ EXPECT_EQ (tester.run (model_id, false), 0);
- EXPECT_EQ (tester.runAll (callback, true), 0);
- EXPECT_EQ (tester.runAll (callback, false), 0);
+ EXPECT_EQ (tester.runAll (true), 0);
+ EXPECT_EQ (tester.runAll (false), 0);
- wait_runs (4);
+ EXPECT_EQ (tester.wait (), 4);
}
/**
UtilTRIV tester;
/* without init */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
ASSERT_EQ (tester.init (), 0);
/* run without model */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
/* invalid model id */
std::string model_dir (NE_DATADIR);
/* skip */
return;
- EXPECT_NE (tester.run (model_id + 1, callback, true), 0);
+ EXPECT_NE (tester.run (model_id + 1, true), 0);
}
#if defined(ENABLE_EMUL)
ASSERT_EQ (tester.init (), 0);
- tsync.done = 0;
+ EXPECT_EQ (tester.run (0, true), 0);
+ EXPECT_EQ (tester.run (0, false), 0);
- EXPECT_EQ (tester.run (0, callback, true), 0);
- EXPECT_EQ (tester.run (0, callback, false), 0);
-
- wait_runs (2);
+ EXPECT_EQ (tester.wait (), 2);
}
/**
UtilTRIA tester;
/* without init */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
}
#endif
uint32_t model_id = 0;
- tsync.done = 0;
-
if (tester.loadModel (model_dir, &model_id) != 0)
/* skip */
return;
- EXPECT_EQ (tester.run (model_id, callback, true), 0);
- EXPECT_EQ (tester.run (model_id, callback, false), 0);
+ EXPECT_EQ (tester.run (model_id, true), 0);
+ EXPECT_EQ (tester.run (model_id, false), 0);
- EXPECT_EQ (tester.runAll (callback, true), 0);
- EXPECT_EQ (tester.runAll (callback, false), 0);
+ EXPECT_EQ (tester.runAll (true), 0);
+ EXPECT_EQ (tester.runAll (false), 0);
- wait_runs (4);
+ EXPECT_EQ (tester.wait (), 4);
}
/**
UtilTRIV2 tester;
/* without init */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
ASSERT_EQ (tester.init (), 0);
/* run without model */
- EXPECT_NE (tester.run (0, callback, true), 0);
- EXPECT_NE (tester.run (0, callback, false), 0);
+ EXPECT_NE (tester.run (0, true), 0);
+ EXPECT_NE (tester.run (0, false), 0);
/* invalid model id */
std::string model_dir (NE_DATADIR);
/* skip */
return;
- EXPECT_NE (tester.run (model_id + 1, callback, true), 0);
+ EXPECT_NE (tester.run (model_id + 1, true), 0);
}
/**
return err;
}
+std::mutex UtilTrinity::m_;
+std::condition_variable UtilTrinity::cv_;
+uint32_t UtilTrinity::success_ = 0;
+uint32_t UtilTrinity::total_ = 0;
+uint32_t UtilTrinity::done_ = 0;
+
/** @brief constructor of UtilTrinity */
UtilTrinity::UtilTrinity (dev_type type, bool need_model)
{
type_ = type;
noti_mode_ = NPU_INTERRUPT;
need_model_ = need_model;
+
+ mute_ = false;
+ sync_ = false;
+ debug_ = false;
}
/** @brief destructor of UtilTrinity */
return getNPUdeviceByType (&dev_, type_, dev_id);
}
+/** @brief print program usage */
+void UtilTrinity::printUsage (const char *prog_name, const char *param_str)
+{
+ if (param_str)
+ std::cerr << "Usage: " << prog_name << " [options] " << param_str << "\n";
+ else
+ std::cerr << "Usage: " << prog_name << " [options]\n";
+ std::cerr << "Options: \n";
+ std::cerr << " -n <arg> \t Set output notimode [intr|polling]\n";
+ std::cerr << " -m \t\t Mute stdout/stderr messages\n";
+ std::cerr << " -d \t\t Enable debugging mode (and dump results)\n";
+ std::cerr << " -s \t\t Enable run sync mode\n";
+ std::cerr << " -h \t\t Show help messages\n";
+}
+
+/** @brief disable stdout/stderr */
+void UtilTrinity::setMute ()
+{
+ /** redirect to /dev/null */
+ if (freopen("/dev/null", "w", stdout) == NULL)
+ std::cerr << "Warning: Failed to reopen stdout\n";
+ if (freopen("/dev/null", "w", stderr) == NULL)
+ std::cerr << "Warning: Failed to reopen stderr\n";
+
+ mute_ = true;
+}
+
+/** @brief set output notification mode */
+void UtilTrinity::setNotiMode (const std::string mode)
+{
+ if (mode == "polling") {
+ noti_mode_ = NPU_POLLING;
+ } else if (mode == "intr") {
+ noti_mode_ = NPU_INTERRUPT;
+ } else {
+ std::cerr << "Unknown notimode: " << mode << std::endl;
+ }
+}
+
+/** @brief parse/set arguments and get working directory */
+int UtilTrinity::parseArgs (int argc, char **argv, char **param,
+ const char *param_str)
+{
+ int c;
+
+ optind = 0;
+ opterr = 0;
+ while ((c = getopt (argc, argv, "dmshn:")) != -1) {
+ switch (c) {
+ case 'd':
+ setDebug ();
+ break;
+ case 'm':
+ setMute ();
+ break;
+ case 's':
+ setSync ();
+ break;
+ case 'n':
+ setNotiMode (optarg);
+ break;
+ case '?':
+ if (optopt == 'n')
+ std::cerr << "Option -i requires an extra argument";
+ else
+ std::cerr << "Unknown flag: " << c;
+ std::cerr << std::endl;
+ printUsage (argv[0], param_str);
+ return test_ret_failure;
+ case 'h':
+ printUsage (argv[0], param_str);
+ return test_ret_skipped;
+ }
+ }
+
+ if (optind < argc)
+ *param = argv[optind];
+ else
+ *param = nullptr;
+
+ return test_ret_success;
+}
+
/** @brief load NPU model and set relevant info */
int UtilTrinity::loadModel (std::string dirpath, uint32_t *model_id_ptr,
npu_priority priority, uint32_t timeout)
model->setDirpath (dirpath);
model->setModelID (model_id);
- status = prepare_input (model);
+ status = prepare_model (model);
if (status != 0) {
delete model;
return status;
return nullptr;
}
+uint32_t UtilTrinity::wait ()
+{
+ uint32_t result;
+ std::unique_lock<std::mutex> lock (m_);
+
+ cv_.wait (lock, [this]() { return done_ == total_; });
+ result = success_;
+
+ total_ = 0;
+ done_ = 0;
+ success_ = 0;
+
+ return result;
+}
+
+void UtilTrinity::callback (output_buffers *output, uint64_t sequence,
+ void *data)
+{
+ bool success = true;
+ UtilModel *model = static_cast <UtilModel *> (data);
+
+ for (uint32_t idx = 0; idx < output->num_buffers; idx++) {
+ if (model != nullptr) {
+ char *buf = static_cast<char*>(output->bufs[idx].addr);
+ size_t size = output->bufs[idx].size;
+
+ if (compare_data (model->getOutputPath (idx), buf, size) != 0)
+ success = false;
+ }
+
+ free (output->bufs[idx].addr);
+ }
+
+ std::unique_lock<std::mutex> lock (m_);
+ done_++;
+ if (success)
+ success_++;
+ cv_.notify_one ();
+}
+
/** @brief run inference with the given model info */
-int UtilTrinity::run_each (UtilModel *model, npuOutputNotify cb, bool sync)
+int UtilTrinity::run_each (UtilModel *model, bool sync)
{
int status = -EINVAL;
- void *cb_data = nullptr;
-
- if (cb == nullptr)
- return -EINVAL;
+ void *callback_data = nullptr;
if (need_model_ && model == nullptr)
return -ENOENT;
if (model)
- cb_data = const_cast <char *> (model->getDirpath ().c_str ());
+ callback_data = static_cast<void*> (model);
if (sync) {
output_buffers output;
cleanNPU_inputBuffers (dev_, &input);
}
- if (status >= 0)
- cb (&output, 0, cb_data);
+ if (status >= 0) {
+ {
+ std::unique_lock<std::mutex> lock (m_);
+ total_++;
+ }
+
+ callback (&output, 0, callback_data);
+ }
} else {
if (model) {
status = runNPU_async (dev_, model->getModelID (), model->getInput (),
- cb, NULL, cb_data, NPUASYNC_WAIT);
+ callback, NULL, callback_data, NPUASYNC_WAIT);
} else {
/* TODO: revise this when TRIA is implemented */
input_buffers input;
if (status != 0)
return status;
- status = runNPU_async (dev_, 0, &input, cb, NULL, cb_data, NPUASYNC_WAIT);
+ status = runNPU_async (dev_, 0, &input, callback, NULL, callback_data,
+ NPUASYNC_WAIT);
cleanNPU_inputBuffers (dev_, &input);
}
+
+ if (status >= 0) {
+ std::unique_lock<std::mutex> lock (m_);
+ total_++;
+ }
}
return status;
}
+/** @brief run inference with the given model id (default sync) */
+int UtilTrinity::run (uint32_t model_id)
+{
+ return run (model_id, sync_);
+}
+
/** @brief run inference with the given model id */
-int UtilTrinity::run (uint32_t model_id, npuOutputNotify cb, bool sync)
+int UtilTrinity::run (uint32_t model_id, bool sync)
{
UtilModel *model = findModel (model_id);
- return run_each (model, cb, sync);
+ return run_each (model, sync);
+}
+
+/** @brief run inference across all registered models (default sync) */
+int UtilTrinity::runAll ()
+{
+ return runAll (sync_);
}
/** @brief run inference across all registered models */
-int UtilTrinity::runAll (npuOutputNotify cb, bool sync)
+int UtilTrinity::runAll (bool sync)
{
for (auto& model : models_) {
- int status = run_each (model.get (), cb, sync);
+ int status = run_each (model.get (), sync);
if (status < 0)
return status;
}
return setNPU_dataInfo (dev_, model_id, &info_in, &info_out);
}
-int UtilTRIV::prepare_input (UtilModel* model) {
+int UtilTRIV::prepare_model (UtilModel *model) {
input_buffers *input = model->getInput ();
npubin_meta *meta = model->getMetadata ();
std::string dirpath = model->getDirpath ();
uint32_t input_num;
+ uint32_t output_num;
if (NPUBIN_VERSION (meta->magiccode) <= 1) {
input_num = 1;
+ output_num = 1;
} else {
input_num = meta->input_num;
+ output_num = meta->output_num;
}
model->prepareInputPath (input_num);
+ model->prepareOutputPath (output_num);
+
input->num_buffers = input_num;
for (uint32_t idx = 0; idx < input_num; idx++) {
return setNPU_dataInfo (dev_, model_id, &info_in, &info_out);
}
-int UtilTRIV2::prepare_input (UtilModel* model) {
+int UtilTRIV2::prepare_model (UtilModel *model) {
input_buffers *input = model->getInput ();
npubin_meta *meta = model->getMetadata ();
std::string dirpath = model->getDirpath ();
model->prepareInputPath (meta->input_seg_num);
+ model->prepareOutputPath (meta->output_seg_num);
+
input->num_buffers = meta->input_seg_num;
for (uint32_t idx = 0; idx < meta->input_seg_num; idx++) {
inpath_[idx] = dirpath_ + "/input_fmap_" + std::to_string (idx) + ".bin";
}
}
-
+ void prepareOutputPath (uint32_t num) {
+ if (NPUBIN_VERSION (meta_->magiccode) <= 1) {
+ outpath_.resize (1);
+ outpath_[0] = dirpath_ + "/output_fmap.bin";
+ } else {
+ outpath_.resize (num);
+ for (uint32_t idx = 0; idx < num; idx++)
+ outpath_[idx] = dirpath_ + "/output_fmap_" + std::to_string (idx) + ".bin";
+ }
+ }
const char *getInputPath (uint32_t idx) { return inpath_[idx].c_str (); }
+ const char *getOutputPath (uint32_t idx) { return outpath_[idx].c_str (); }
+
npubin_meta *getMetadata () { return meta_; }
std::string& getDirpath () { return dirpath_; }
uint32_t getModelID () { return model_id_; }
input_buffers input_;
std::vector<std::string> inpath_;
+ std::vector<std::string> outpath_;
};
/** @brief utility to access trinity device */
npudev_h getDeviceHandle () { return dev_; }
void setNotiMode (npu_notimode noti_mode) { noti_mode_ = noti_mode; }
+ void setSync () { sync_ = true; }
+ void setDebug () { debug_ = true; }
+ void setMute ();
+ void setNotiMode (const std::string mode);
int init ();
+ void printUsage (const char *prog_name, const char *param_str = nullptr);
+ int parseArgs (int argc, char **argv, char **param, const char *param_str = nullptr);
int loadModel (std::string dirpath, uint32_t *model_id,
npu_priority priority = NPU_PRIORITY_MID,
uint32_t timeout = 5000);
- int run (uint32_t model_id, npuOutputNotify cb, bool sync = false);
- int runAll (npuOutputNotify cb, bool sync = false);
+
+ int run (uint32_t model_id);
+ int run (uint32_t model_id, bool sync);
+ int runAll ();
+ int runAll (bool sync);
int runInternal (uint32_t model_id, std::string dev_path);
int stopInternal (int task_id);
UtilModel *findModel (uint32_t model_id);
+ static void callback (output_buffers *output, uint64_t sequence,
+ void *data);
+
+ uint32_t wait ();
+
protected:
npudev_h dev_;
- npu_notimode noti_mode_;
std::vector<std::unique_ptr<UtilModel>> models_;
+ npu_notimode noti_mode_;
bool need_model_;
+ bool mute_;
+ bool sync_;
+ bool debug_;
+
private:
int set_constraint (uint32_t model_id, uint32_t timeout, npu_priority priority);
- int run_each (UtilModel *model, npuOutputNotify cb, bool sync);
+ int run_each (UtilModel *model, bool sync);
virtual bool check_version (npubin_meta *meta) { return false; }
- virtual int prepare_input (UtilModel* model) { return -EPERM; }
+ virtual int prepare_model (UtilModel *model) { return -EPERM; }
virtual int set_data_info (npubin_meta *meta, uint32_t model_id) { return -EPERM; }
dev_type type_;
+
+ static std::mutex m_;
+ static std::condition_variable cv_;
+
+ static uint32_t success_;
+ static uint32_t done_;
+ static uint32_t total_;
};
class UtilTRIV : public UtilTrinity {
private:
bool check_version (npubin_meta *meta);
int set_data_info (npubin_meta *meta, uint32_t model_id);
- int prepare_input (UtilModel* model);
+ int prepare_model (UtilModel *model);
};
class UtilTRIA : public UtilTrinity {
private:
bool check_version (npubin_meta *meta);
int set_data_info (npubin_meta *meta, uint32_t model_id);
- int prepare_input (UtilModel* model);
+ int prepare_model (UtilModel *model);
};
extern "C" {
#endif
enum test_ret {
+ test_ret_failure = -1,
test_ret_success = 0,
test_ret_skipped,
test_ret_skipped_wrong_num_args,