--- /dev/null
+
+
+#include <fcntl.h>
+#include <libnpuhost.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <thread>
+
+#include "ne-utils.h"
+
+#define MODEL_PATH "./model.tvn"
+#define INPUT_PATH "./input_fmap_0.bin"
+#define OUTPUT_PATH "./output_fmap_0.bin"
+
+static generic_buffers input, output, prog, weight;
+
+static inline off_t
+get_file_len (const char *path) {
+ struct stat s;
+
+ if (stat (path, &s) != 0) {
+ std::cerr << "Unable to get stat: " << path << "\n";
+ return -errno;
+ }
+
+ return s.st_size;
+}
+
+static int
+compare (const char *golden_path, const char *data, uint64_t size) {
+ std::ifstream ifs (golden_path, std::ios::binary | std::ios::ate);
+ if (!ifs.good ()) {
+ std::cerr << "Failed to open file " << golden_path << "\n";
+ return -ENOENT;
+ }
+
+ off_t len = get_file_len (golden_path);
+ if (len < 0 || len != size) {
+ std::cerr << "Output size mismatch\n";
+ return -1;
+ }
+
+ ifs.seekg (0, std::ios::beg);
+
+ std::vector<uint8_t> raw_data (data, data + size);
+ std::vector<uint8_t> golden_data;
+ golden_data.reserve (size);
+ golden_data.insert (golden_data.begin (), std::istreambuf_iterator<char> (ifs),
+ std::istreambuf_iterator<char> ());
+
+ if (golden_data.end () !=
+ std::mismatch (golden_data.begin (), golden_data.end (), raw_data.begin ()).first) {
+ std::cerr << "Output data mismatch\n";
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+main (void) {
+ int status;
+ npudev_h dev;
+ npubin_meta *meta;
+ generic_buffer modelfile;
+ uint32_t model_id = 0;
+ int tops = 2;
+ int req_id = -1;
+ std::thread *prog_provider = nullptr;
+ std::thread *weight_provider = nullptr;
+
+ // 1. register model
+ meta = getNPUmodel_metadata (MODEL_PATH, false);
+ if (meta == nullptr) {
+ std::cerr << "Failed to get model metadata" << std::endl;
+ return -1;
+ }
+
+ status = getNPUdeviceByTypeAny (&dev, NPUCOND_TRIV2_CONN_SOCIP, tops);
+ if (status < 0) {
+ std::cerr << "Failed to open the NPU device : " << status << std::endl;
+ return status;
+ }
+
+ modelfile.type = BUFFER_FILE;
+ modelfile.filepath = MODEL_PATH;
+ modelfile.size = meta->size;
+
+ // 2. Prepare Input/Output
+ input.num_buffers = meta->input_seg_num;
+ input.bufs[0].filepath = INPUT_PATH;
+ input.bufs[0].size = get_file_len (INPUT_PATH);
+ input.bufs[0].type = BUFFER_FILE;
+
+ output.num_buffers = meta->output_seg_num;
+ output.bufs[0].size = get_file_len (OUTPUT_PATH);
+ output.bufs[0].type = BUFFER_MAPPED;
+
+ prog.num_buffers = 1;
+ prog.bufs[0].size = meta->program_size;
+ prog.bufs[0].type = BUFFER_MAPPED;
+
+ weight.num_buffers = 1;
+ weight.bufs[0].size = meta->weight_size;
+ weight.bufs[0].type = BUFFER_MAPPED;
+
+ status = allocNPU_genericBuffers (dev, &output);
+ if (status < 0) {
+ std::cerr << "Failed to alloc output buffers : " << status << std::endl;
+ goto clean;
+ }
+
+ status = allocNPU_genericBuffers (dev, &prog);
+ if (status < 0) {
+ std::cerr << "Failed to alloc prog buffers : " << status << std::endl;
+ goto clean;
+ }
+
+ status = allocNPU_genericBuffers (dev, &weight);
+ if (status < 0) {
+ std::cerr << "Failed to alloc weight buffers : " << status << std::endl;
+ goto clean;
+ }
+
+ status = registerNPUmodel_ext (dev, &modelfile, &prog.bufs[0], &weight.bufs[0], &model_id);
+ if (status < 0) {
+ std::cerr << "Failed to register model " << status << std::endl;
+ goto clean;
+ }
+
+ // 3. Prepare request
+ status = createNPU_request (dev, model_id, &req_id);
+ if (status < 0) {
+ std::cerr << "Failed to create request : " << status << std::endl;
+ cleanNPU_genericBuffers (dev, &output);
+ goto clean;
+ }
+
+ status = setNPU_requestData (dev, req_id, &input, NULL, &output, NULL);
+ if (status < 0) {
+ std::cerr << "Failed to set input data : " << status << std::endl;
+ cleanNPU_genericBuffers (dev, &output);
+ goto clean;
+ }
+
+ weight_provider = new std::thread ([&] () {
+ int fd = open (modelfile.filepath, O_RDONLY);
+ void *model_w = mmap (NULL, ALIGNED_SIZE (meta->size + meta->program_size + meta->weight_size),
+ PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (model_w == MAP_FAILED) {
+ std::cerr << "Failed mmap: " << strerror (errno) << std::endl;
+ }
+
+ memcpy (weight.bufs[0].addr,
+ (char *) model_w + NPUBIN_META_SIZE + NPUBIN_META_EXTENDED_SIZE (meta->magiccode) +
+ meta->program_size,
+ meta->weight_size);
+ munmap (model_w, ALIGNED_SIZE (meta->size + meta->program_size + meta->weight_size));
+ close (fd);
+ });
+
+ prog_provider = new std::thread ([&] () {
+ int fd = open (modelfile.filepath, O_RDONLY);
+ void *model_p = mmap (NULL, ALIGNED_SIZE (meta->size + meta->program_size),
+ PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (model_p == MAP_FAILED) {
+ std::cerr << "Failed mmap: " << strerror (errno) << std::endl;
+ }
+
+ memcpy (prog.bufs[0].addr,
+ (char *) model_p + NPUBIN_META_SIZE + NPUBIN_META_EXTENDED_SIZE (meta->magiccode),
+ meta->program_size);
+ munmap (model_p, ALIGNED_SIZE (meta->size + meta->program_size));
+ close (fd);
+ });
+
+ prog_provider->join ();
+ weight_provider->join ();
+
+ // 4. Run and check result
+ status = submitNPU_request (dev, req_id);
+ if (status < 0) {
+ std::cerr << "Failed to submit request : " << status << std::endl;
+ cleanNPU_genericBuffers (dev, &output);
+ goto clean;
+ }
+
+ status = compare (OUTPUT_PATH, static_cast<char *> (output.bufs[0].addr), output.bufs[0].size);
+ if (status < 0) {
+ std::cerr << "Failed to check result : " << status << std::endl;
+ cleanNPU_genericBuffers (dev, &output);
+ goto clean;
+ }
+
+ std::cout << "Success\n";
+
+clean:
+ if (req_id >= 0)
+ removeNPU_request (dev, req_id);
+ if (model_id > 0)
+ unregisterNPUmodel (dev, model_id);
+ if (prog.bufs[0].dmabuf > 0)
+ cleanNPU_genericBuffers (dev, &prog);
+ if (weight.bufs[0].dmabuf > 0)
+ cleanNPU_genericBuffers (dev, &weight);
+ if (output.bufs[0].dmabuf > 0)
+ cleanNPU_genericBuffers (dev, &output);
+ putNPUdevice (dev);
+ if (prog_provider)
+ delete prog_provider;
+ if (weight_provider)
+ delete weight_provider;
+
+ return status;
+}