[Utils] Add npu-engine-utils packages
authorDongju Chae <dongju.chae@samsung.com>
Thu, 20 Aug 2020 08:19:53 +0000 (17:19 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Fri, 21 Aug 2020 01:06:12 +0000 (10:06 +0900)
This patch adds npu-engine-utils packages.
Currently, we support only model-inspect.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
debian/control
debian/npu-engine-example.install
meson.build
packaging/npu-engine.spec
utils/meson.build [new file with mode: 0644]
utils/model_inspect.cc [new file with mode: 0644]

index 297f506..79f4018 100644 (file)
@@ -32,3 +32,10 @@ Depends: npu-engine, ${shlibs:Depends}, ${misc:Depends}
 Recommends: npu-engine-testdata
 Description: NPU Engine Example Package
  Example application package for NPU Engine, including UnitTests and AppTest with realistic scenarios (TBD).
+
+Package: npu-engine-utils
+Architecture: amd64
+Multi-Arch: same
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: NPU Engine Utils Package
+ This provides utility packages for NPU Engine, including metadata extraction of model files.
index f3ee8d9..53674de 100644 (file)
@@ -1 +1,2 @@
-/opt/trinity/bin/*
+/opt/trinity/bin/unittests/*
+/opt/trinity/bin/apptests/*
index dd0ea3d..dbd3a13 100644 (file)
@@ -132,6 +132,7 @@ endif
 
 subdir('src')
 subdir('tests')
+subdir('utils')
 
 # Set configuration to install .ini
 ne_install_conf = configuration_data()
index c454a58..01faec8 100644 (file)
@@ -182,6 +182,15 @@ Example application package for NPU Engine, including UnitTests and AppTest with
 %{neexampledir}/unittests/*
 %{neexampledir}/apptests/*
 
+%package utils
+Summary:  NPU Engine Example Package
+%description utils
+This probides utility packages for NPU Engine, including metadata extraction of model files.
+%files utils
+%manifest npu-engine.manifest
+%defattr(-,root,root,-)
+%{neexampledir}/utils/*
+
 %package unittest-coverage
 Summary:  NPU Engine UnitTest Coverage Analysis Result
 %description unittest-coverage
diff --git a/utils/meson.build b/utils/meson.build
new file mode 100644 (file)
index 0000000..0f7d31b
--- /dev/null
@@ -0,0 +1,7 @@
+utils_model_inspect = executable('model-inspect',
+  ['model_inspect.cc'],
+  include_directories: [ne_host_inc, ne_common_inc],
+  install : true,
+  install_rpath : ne_libdir,
+  install_dir : join_paths(ne_bindir, 'utils')
+)
diff --git a/utils/model_inspect.cc b/utils/model_inspect.cc
new file mode 100644 (file)
index 0000000..4775a41
--- /dev/null
@@ -0,0 +1,347 @@
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file model-inspect.cc
+ * @date 20 Aug 2020
+ * @brief Utility to inspect trinity model files
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <libnpuhost.h>
+#include <npubinfmt.h>
+
+#include <iostream>
+#include <fstream>
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+class Inspector {
+  public:
+    Inspector ();
+    ~Inspector ();
+
+    int init (std::string model);
+    int run ();
+
+    void set_dump_meta () { dump_meta_ = true; }
+    void set_dump_program () { dump_program_ = true; }
+    void set_dump_weight () { dump_weight_ = true; }
+    void set_output_dir (std::string output) { dump_output_ = output; }
+
+  private:
+    void dump ();
+    int show ();
+
+    void show_common ();
+    void show_v1 ();
+    void show_v2 ();
+    void show_v3 ();
+
+    npubin_meta * meta_;
+    std::ifstream ifs_;
+
+    std::string dump_output_;
+
+    bool dump_meta_;
+    bool dump_program_;
+    bool dump_weight_;
+};
+
+Inspector::Inspector ()
+{
+  meta_ = nullptr;
+  dump_meta_ = false;
+  dump_program_ = false;
+  dump_weight_ = false;
+}
+
+Inspector::~Inspector ()
+{
+  if (meta_ != nullptr)
+    free (meta_);
+}
+
+int Inspector::init (std::string model)
+{
+  std::cerr << "Inspecting model binary: " << model << "\n\n";
+
+  ifs_.open (model, std::ios::binary);
+  if (ifs_.fail ()) {
+    std::cerr << strerror (errno) << "\n";
+    return -errno;
+  }
+
+  meta_ = (npubin_meta *) malloc (NPUBIN_META_SIZE);
+  if (meta_ == nullptr) {
+    std::cerr << strerror (errno) << "\n";
+    return -errno;
+  }
+
+  ifs_.read (reinterpret_cast<char*>(meta_), NPUBIN_META_SIZE);
+  if (!CHECK_NPUBIN (meta_->magiccode)) {
+    std::cerr << "Non-compatible binary format\n";
+    return -EINVAL;
+  }
+
+  if (dump_output_ == "")
+    dump_output_ = ".";
+
+  if (access (dump_output_.c_str (), W_OK) != 0) {
+    std::cerr << "The given output directory (" << dump_output_ << ") "
+              << "doesn't have write permission\n";
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+int Inspector::run ()
+{
+  int status = show ();
+
+  if (status == 0)
+    dump ();
+
+  return status;
+}
+
+int Inspector::show ()
+{
+  uint64_t version = NPUBIN_VERSION (meta_->magiccode);
+
+  switch (version) {
+    case 0:
+      // no-break;
+    case 1:
+      show_v1 ();
+      break;
+    case 2:
+      show_v2 ();
+      break;
+    case 3:
+      show_v3 ();
+      break;
+    default:
+      std::cerr << "Unsupported npubinfmt version: " << version << "\n";
+      return -EINVAL;
+  }
+
+  return 0;
+}
+
+void Inspector::show_common ()
+{
+  std::cout << "[common] " << "\n";
+  std::cout << "  model format: " << NPUBIN_VERSION (meta_->magiccode) << "\n";
+  std::cout << "  model size: " << meta_->size << "\n";
+  std::cout << "  - metadata size: " << NPUBIN_META_TOTAL_SIZE (meta_->magiccode) << "\n";
+  std::cout << "  - program size: " << meta_->program_size << "\n";
+  std::cout << "  - weight size: " << meta_->weight_size << "\n";
+  std::cout << "\n";
+  std::cout << std::hex;
+  std::cout << "  magiccode: 0x" << meta_->magiccode << "\n";
+  std::cout << "  npu_version: 0x" << meta_->npu_version << "\n";
+  std::cout << "  compiler_version: 0x" << meta_->compiler_version << "\n";
+  std::cout << "\n";
+}
+
+void Inspector::show_v1 ()
+{
+  show_common ();
+
+  std::cout << "[npubinfmt v1] " << "\n";
+  std::cout << std::dec;
+  std::cout << "  buffer_size: " << meta_->buffer_size << "\n";
+  std::cout << "  input_offset: " << meta_->input_offset << "\n";
+  std::cout << "  input_size: " << meta_->input_size << "\n";
+  std::cout << "  output_offset: " << meta_->output_offset << "\n";
+  std::cout << "  output_size: " << meta_->output_size << "\n";
+}
+
+void Inspector::show_v2 ()
+{
+  show_common ();
+
+  std::cout << "[npubinfmt v2] " << "\n";
+  std::cout << std::dec;
+  std::cout << "  input_num: " << meta_->input_num << "\n";
+  for (uint32_t i = 0; i < meta_->input_num; i++) {
+    std::cout << std::dec;
+    std::cout << "  input_offsets[" << i << "]: " << meta_->input_offsets[i] << "\n";
+    std::cout << "  input_elem_size[" << i << "]: " << meta_->input_elem_size[i] << "\n";
+    for (uint32_t j = 0; j < MAX_RANK; j++)
+      std::cout << "  input_dims[" << i << "][" << j << "]: " << meta_->input_dims[i][j] << "\n";
+    std::cout << "  input_emod_y[" << i << "]: " << meta_->input_emod_y[i] << "\n";
+    std::cout << "  input_emod_z[" << i << "]: " << meta_->input_emod_z[i] << "\n";
+    std::cout << "  input_quant_z[" << i << "]: " << meta_->input_quant_z[i] << "\n";
+    std::cout << std::fixed;
+    std::cout << "  input_quant_s[" << i << "]: " << meta_->input_quant_s[i] << "\n";
+  }
+  std::cout << std::dec << "\n";
+  std::cout << "  output_num: " << meta_->output_num << "\n";
+  for (uint32_t i = 0; i < meta_->output_num; i++) {
+    std::cout << std::dec;
+    std::cout << "  output_offsets[" << i << "]: " << meta_->output_offsets[i] << "\n";
+    std::cout << "  output_elem_size[" << i << "]: " << meta_->output_elem_size[i] << "\n";
+    for (uint32_t j = 0; j < MAX_RANK; j++)
+      std::cout << "  output_dims[" << i << "][" << j << "]: " << meta_->output_dims[i][j] << "\n";
+    std::cout << "  output_emod_y[" << i << "]: " << meta_->output_emod_y[i] << "\n";
+    std::cout << "  output_emod_z[" << i << "]: " << meta_->output_emod_z[i] << "\n";
+    std::cout << "  output_quant_z[" << i << "]: " << meta_->output_quant_z[i] << "\n";
+    std::cout << std::fixed;
+    std::cout << "  output_quant_s[" << i << "]: " << meta_->output_quant_s[i] << "\n";
+  }
+}
+
+void Inspector::show_v3 ()
+{
+  show_common ();
+
+  std::cout << "[npubinfmt v2] " << "\n";
+  std::cout << std::dec;
+  std::cout << "  segment_num: " << meta_->segment_num << "\n";
+  for (uint32_t i = 0; i < meta_->segment_num; i++) {
+    std::cout << "  segment_size[" << i << "]: " << meta_->segment_size[i] << "\n";
+  }
+  std::cout << "\n";
+  std::cout << "  weight_seg_idx: " << meta_->weight_seg_idx << "\n";
+  std::cout << "\n";
+  std::cout << "  input_seg_num: " << meta_->input_seg_num << "\n";
+  for (uint32_t i = 0; i < meta_->input_seg_num; i++) {
+    std::cout << std::dec;
+    std::cout << "  input_seg_idx[" << i << "]: " << meta_->input_seg_idx[i] << "\n";
+    std::cout << "  input_seg_off[" << i << "]: " << meta_->input_seg_off[i] << "\n";
+    for (uint32_t j = 0; j < MAX_RANK; j++)
+      std::cout << "  input_seg_dims[" << i << "][" << j << "]: " << meta_->input_seg_dims[i][j] << "\n";
+    std::cout << "  input_seg_emod_y[" << i << "]: " << meta_->input_seg_emod_y[i] << "\n";
+    std::cout << "  input_seg_emod_z[" << i << "]: " << meta_->input_seg_emod_z[i] << "\n";
+    std::cout << "  input_seg_quant_type[" << i << "]: " << meta_->input_seg_quant_type[i] << "\n";
+    std::cout << "  input_seg_quant_z[" << i << "]: " << meta_->input_seg_quant_z[i] << "\n";
+    std::cout << std::fixed;
+    std::cout << "  input_seg_quant_s[" << i << "]: " << meta_->input_seg_quant_s[i] << "\n";
+  }
+  std::cout << std::dec << "\n";
+  std::cout << "  output_seg_num: " << meta_->output_seg_num << "\n";
+  for (uint32_t i = 0; i < meta_->output_seg_num; i++) {
+    std::cout << std::dec;
+    std::cout << "  output_seg_idx[" << i << "]: " << meta_->output_seg_idx[i] << "\n";
+    std::cout << "  output_seg_off[" << i << "]: " << meta_->output_seg_off[i] << "\n";
+    for (uint32_t j = 0; j < MAX_RANK; j++)
+      std::cout << "  output_seg_dims[" << i << "][" << j << "]: " << meta_->output_seg_dims[i][j] << "\n";
+    std::cout << "  output_seg_emod_y[" << i << "]: " << meta_->output_seg_emod_y[i] << "\n";
+    std::cout << "  output_seg_emod_z[" << i << "]: " << meta_->output_seg_emod_z[i] << "\n";
+    std::cout << "  output_seg_quant_type[" << i << "]: " << meta_->output_seg_quant_type[i] << "\n";
+    std::cout << "  output_seg_quant_z[" << i << "]: " << meta_->output_seg_quant_z[i] << "\n";
+    std::cout << std::fixed;
+    std::cout << "  output_seg_quant_s[" << i << "]: " << meta_->output_seg_quant_s[i] << "\n";
+  }
+}
+
+void Inspector::dump ()
+{
+  size_t size_metadata = NPUBIN_META_TOTAL_SIZE (meta_->magiccode);
+
+  if (dump_meta_) {
+    std::ofstream ofs (dump_output_ + "/metadata.bin", std::ios::binary);
+    if (ofs.good ()) {
+      char * buf = new char [size_metadata];
+
+      ifs_.seekg (0);
+      ifs_.read (buf, size_metadata);
+      ofs.write (buf, size_metadata);
+
+      delete [] buf;
+    }
+  }
+
+  if (dump_program_) {
+    std::ofstream ofs (dump_output_ + "/program.bin", std::ios::binary);
+    if (ofs.good ()) {
+      char * buf = new char [meta_->program_size];
+
+      ifs_.seekg (size_metadata);
+      ifs_.read (buf, meta_->program_size);
+      ofs.write (buf, meta_->program_size);
+
+      delete [] buf;
+    }
+  }
+
+  if (dump_weight_) {
+    std::ofstream ofs (dump_output_ + "/weight.bin", std::ios::binary);
+    if (ofs.good ()) {
+      char * buf = new char [meta_->weight_size];
+
+      ifs_.seekg (size_metadata + meta_->program_size);
+      ifs_.read (buf, meta_->weight_size);
+      ofs.write (buf, meta_->weight_size);
+
+      delete [] buf;
+    }
+  }
+}
+
+static void
+print_usage (const char *prog_name)
+{
+  std::cerr << "Usage: " << prog_name << " [options] model_path\n";
+  std::cerr << "Options: \n";
+  std::cerr << "  -o <arg> \t Set output directory\n";
+  std::cerr << "  -m \t\t Extract metadata section\n";
+  std::cerr << "  -p \t\t Extract program section\n";
+  std::cerr << "  -w \t\t Extract weight section\n";
+}
+
+int main (int argc, char **argv)
+{
+  Inspector inspector;
+  int c, status = 0;
+
+  optind = 0;
+  opterr = 0;
+  while ((c = getopt (argc, argv, "mpwho:")) != -1) {
+    switch (c) {
+      case 'm':
+        inspector.set_dump_meta ();
+        break;
+      case 'p':
+        inspector.set_dump_program ();
+        break;
+      case 'w':
+        inspector.set_dump_weight ();
+        break;
+      case 'o':
+        inspector.set_output_dir (optarg);
+        break;
+      case '?':
+        if (optopt == 'o')
+          std::cerr << "Option -o requires an extra argument";
+        else
+          std::cerr << "Unknown flag: " << c;
+        std::cerr << std::endl;
+        status = -EINVAL;
+        // no-break
+      case 'h':
+        print_usage (argv[0]);
+        return status;
+    }
+  }
+
+  if (optind >= argc) {
+    std::cerr << "Please provide model binary path\n\n";
+    print_usage (argv[0]);
+    return -EINVAL;
+  }
+
+  status = inspector.init (argv[optind]);
+  if (status != 0)
+    return status;
+
+  return inspector.run ();
+}