utils: Add example for model sharing
authorJiho Chu <jiho.chu@samsung.com>
Fri, 24 May 2024 03:45:19 +0000 (12:45 +0900)
committerWook Song <wook16.song@samsung.com>
Tue, 18 Mar 2025 07:28:09 +0000 (16:28 +0900)
A model needs to be shared between the threads. It register the model
with allocated weight buffer, and it share the buffer with other threads
to work along with.

Signed-off-by: Jiho Chu <jiho.chu@samsung.com>
utils/examples/meson.build [new file with mode: 0644]
utils/examples/model_share.cc [new file with mode: 0644]
utils/meson.build

diff --git a/utils/examples/meson.build b/utils/examples/meson.build
new file mode 100644 (file)
index 0000000..d241485
--- /dev/null
@@ -0,0 +1,10 @@
+
+executable ('model_share',
+  'model_share.cc',
+  include_directories : [ne_core_utils_inc, ne_host_inc],
+  dependencies : [npubinfmt_dep, ne_test_utils_common_dep, thread_dep],
+  link_with : ne_library_shared,
+  install : true,
+  install_rpath : ne_libdir,
+  install_dir : join_paths(ne_bindir, 'utils')
+)
diff --git a/utils/examples/model_share.cc b/utils/examples/model_share.cc
new file mode 100644 (file)
index 0000000..cbcf62f
--- /dev/null
@@ -0,0 +1,225 @@
+
+
+#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;
+}
index 6a79a34734990de628ee4df928d01cbfbccf85d5..7340e4d3c80ddef67165adfa61fbcdf9a2127824 100644 (file)
@@ -4,3 +4,4 @@ subdir('trinity_cuse')
 subdir('trinity_test')
 subdir('trinity_trace')
 subdir('idu_load')
+subdir('examples')