[VD/NPUMGR] Implement network execute APIs
authorDongju Chae <dongju.chae@samsung.com>
Tue, 25 May 2021 06:04:58 +0000 (15:04 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Wed, 26 May 2021 03:46:38 +0000 (12:46 +0900)
This patch implements network execute APIs of VD NPUMGR.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
packaging/npu-engine.spec
tests/apptests/npumgr/meson.build
tests/apptests/npumgr/npumgr.cc
tests/apptests/npumgr/npumgr_api.cc
tests/apptests/npumgr/npumgr_test.cc
tests/apptests/npumgr/npumgr_triv2.cc
tests/apptests/npumgr/sr.odl.NPUManager.conf [new file with mode: 0644]

index dd2526a..9600d27 100644 (file)
@@ -51,7 +51,8 @@ cp %{SOURCE1001} .
 %build
 
 meson --buildtype=plain --bindir=%{neexampledir} --prefix=%{_prefix} \
-      --sysconfdir=%{_sysconfdir} --libdir=%{_libdir} --includedir=%{_includedir} \
+      --libdir=%{_libdir} --includedir=%{_includedir} \
+      --datadir=%{_datadir} --sysconfdir=%{_sysconfdir} \
       -Denable_tizen=true -Denable_data_manip=true %{enable_npu_emul} \
       build
 ninja -C build %{?_smp_mflags}
@@ -91,6 +92,7 @@ Example application package for NPU Engine, including UnitTests and AppTest with
 %{neexampledir}/unittests/*
 %{neexampledir}/apptests/*
 %{_libdir}/libnpumgr*.so
+%{_datadir}/dbus-1/system.d/*
 
 %package utils
 Requires:      npu-engine = %{version}-%{release}
index 7bc7edd..5bc39b1 100644 (file)
@@ -35,7 +35,7 @@ if glib_dep.found() and giounix_dep.found()
 
   executable ('apptest_npumgr',
     'npumgr_test.cc',
-    dependencies : glib_dep,
+    dependencies : [glib_dep, ne_test_utils_common_dep],
     link_with : npumgr_lib,
     install : true,
     install_rpath : ne_libdir,
@@ -49,4 +49,8 @@ if glib_dep.found() and giounix_dep.found()
     install_rpath : ne_libdir,
     install_dir : join_paths(ne_bindir, 'apptests', 'npumgr')
   )
+
+  install_data ('sr.odl.NPUManager.conf',
+    install_dir: join_paths(get_option('datadir'), 'dbus-1', 'system.d')
+  )
 endif
index 34c8d27..298e6ff 100644 (file)
@@ -136,6 +136,18 @@ static const gchar introspection_xml[] =
     "       <arg type='i' name='index' direction='in'/>"
     "       <arg type='v' name='data' direction='out'/>"
     "     </method>"
+    "     <method name='ExecuteTrigger'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='t' name='nw_handle' direction='in'/>"
+    "     </method>"
+    "     <method name='ExecuteWait'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='t' name='nw_handle' direction='in'/>"
+    "     </method>"
+    "     <method name='ExecuteRun'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='t' name='nw_handle' direction='in'/>"
+    "     </method>"
     "   </interface>"
     " </node>";
 
@@ -335,7 +347,7 @@ handle_method_call (GDBusConnection *connection, const gchar *sender,
       if (context == NULL) {
         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                G_DBUS_ERROR_FAILED,
-                                               "Unable to add network");
+                                               "Unable to find context");
         return;
       }
       NpumgrDevice *device = context->device;
@@ -786,6 +798,99 @@ handle_method_call (GDBusConnection *connection, const gchar *sender,
                                              G_DBUS_ERROR_INVALID_ARGS,
                                              "Invalid arguments detected");
     }
+  } else if (g_strcmp0 (method_name, "ExecuteTrigger") == 0) {
+    npumgr_context ctx_handle = 0;
+    npumgr_network nw_handle = 0;
+
+    g_variant_get (parameters, "(tt)", (guint64 *) &ctx_handle,
+                   (guint64 *) &nw_handle);
+    if (ctx_handle > 0 && nw_handle > 0) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_status_e status;
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->execute_trigger (
+            device, ctx_handle, nw_handle);
+        if (status == NPUMGR_STATUS_SUCCESS) {
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        } else {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_FAILED,
+                                                 "Unable to execute network");
+        }
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
+  } else if (g_strcmp0 (method_name, "ExecuteWait") == 0) {
+    npumgr_context ctx_handle = 0;
+    npumgr_network nw_handle = 0;
+
+    g_variant_get (parameters, "(tt)", (guint64 *) &ctx_handle,
+                   (guint64 *) &nw_handle);
+    if (ctx_handle > 0 && nw_handle > 0) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_status_e status;
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->execute_wait (
+            device, ctx_handle, nw_handle);
+        if (status == NPUMGR_STATUS_SUCCESS) {
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        } else {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_FAILED,
+                                                 "Unable to finish execution");
+        }
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
+  } else if (g_strcmp0 (method_name, "ExecuteRun") == 0) {
+    npumgr_context ctx_handle = 0;
+    npumgr_network nw_handle = 0;
+
+    g_variant_get (parameters, "(tt)", (guint64 *) &ctx_handle,
+                   (guint64 *) &nw_handle);
+    if (ctx_handle > 0 && nw_handle > 0) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_status_e status;
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->execute_run (
+            device, ctx_handle, nw_handle);
+        if (status == NPUMGR_STATUS_SUCCESS) {
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        } else {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_FAILED,
+                                                 "Unable to execute network");
+        }
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
   }
 }
 
index 55d36dc..61eb2cc 100644 (file)
@@ -848,8 +848,41 @@ out:
  */
 npumgr_status_e
 npumgr_execute_trigger (npumgr_context ctx, npumgr_network nw_handle) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "ExecuteTrigger");
+  g_dbus_message_set_body (method_call, g_variant_new ("(tt)", ctx, nw_handle));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -857,8 +890,41 @@ npumgr_execute_trigger (npumgr_context ctx, npumgr_network nw_handle) {
  */
 npumgr_status_e
 npumgr_execute_wait (npumgr_context ctx, npumgr_network nw_handle) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "ExecuteWait");
+  g_dbus_message_set_body (method_call, g_variant_new ("(tt)", ctx, nw_handle));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -866,8 +932,41 @@ npumgr_execute_wait (npumgr_context ctx, npumgr_network nw_handle) {
  */
 npumgr_status_e
 npumgr_execute_run (npumgr_context ctx, npumgr_network nw_handle) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "ExecuteRun");
+  g_dbus_message_set_body (method_call, g_variant_new ("(tt)", ctx, nw_handle));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
index 30b59aa..ab68896 100644 (file)
 #include <unistd.h>
 
 #include <glib.h>
+#include <ne_test_utils_common.h>
 
 #include "npumgr_api.h"
+#include "npumgr_common.h"
 
-int
-main (int argc, char **argv) {
-  npumgr_context context;
-  npumgr_network network;
+using namespace std;
+
+static int
+start_npumgr_test (int fd, const string &dir) {
   npumgr_devices_id list;
   npumgr_status_e status;
-  int fd, ret = -EINVAL;
 
-  if (argc != 2) {
-    std::cerr << "Please provide network file name (.tvn)\n";
-    return ret;
-  }
+  npumgr_context context;
+  npumgr_network network;
 
-  if (!g_str_has_suffix (argv[1], ".tvn")) {
-    std::cerr << "Invalid model path: " << argv[1] << "\n";
-    return ret;
-  }
+  npumgr_buffer *input_bufs = NULL;
+  npumgr_buffer *output_bufs = NULL;
+  npumgr_query_inout_num inout_num = {0};
+
+  npumgr_network_defn input_files[] = {{NPUMGR_NETWORK_FILE_TVN, fd}};
+  const char *input_tensor_names[] = {"input"};
+  const char *output_tensor_names[] = {"output"};
+  npumgr_query_tensor_attr attr;
 
   status = npumgr_device_get_available_list (&list);
   if (status != NPUMGR_STATUS_SUCCESS) {
-    std::cerr << "Unable to get available device list, " << status << "\n";
-    return ret;
+    cerr << "Unable to get available device list, " << status << "\n";
+    return status;
   }
 
   /* TODO: find the first NPU device */
@@ -57,87 +60,232 @@ main (int argc, char **argv) {
   }
 
   if (!found) {
-    std::cerr << "No available device\n";
-    return ret;
+    cerr << "No available device\n";
+    return NPUMGR_STATUS_ERR_DEVICE_UNAVAILABLE;
   }
 
   status = npumgr_context_create (id, NPUMGR_FLAG_PRIORITY_DEFAULT, &context);
   if (status != NPUMGR_STATUS_SUCCESS) {
-    std::cerr << "Unable to create a npumgr context, " << status << "\n";
-    return ret;
-  }
-
-  fd = open (argv[1], O_RDONLY);
-  if (fd >= 0) {
-    npumgr_network_defn input_files[] = {{NPUMGR_NETWORK_FILE_TVN, fd}};
-    const char *input_tensor_names[] = {"input"};
-    const char *output_tensor_names[] = {"output"};
-    npumgr_query_inout_num inout_num;
-    npumgr_query_tensor_attr *input_attr;
-    npumgr_query_tensor_attr *output_attr;
-
-    status = npumgr_network_create (
-        context, 1, input_files, NPUMGR_BUF_TYPE_DRIVER, 1, input_tensor_names,
-        NPUMGR_BUF_TYPE_DRIVER, 1, output_tensor_names, &network);
+    cerr << "Unable to create a npumgr context, " << status << "\n";
+    return NPUMGR_STATUS_ERR_FAIL;
+  }
+
+  status = npumgr_network_create (
+      context, 1, input_files, NPUMGR_BUF_TYPE_DRIVER, 1, input_tensor_names,
+      NPUMGR_BUF_TYPE_DRIVER, 1, output_tensor_names, &network);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to create a npumgr network, " << status << "\n";
+    goto destroy_ctx;
+  }
+
+  status = npumgr_query_network (context, network, &inout_num);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to query network info, " << status << "\n";
+    goto destroy_nw;
+  }
+
+  input_bufs = g_new0 (npumgr_buffer, inout_num.n_input);
+  output_bufs = g_new0 (npumgr_buffer, inout_num.n_output);
+
+  for (int i = 0; i < inout_num.n_input; i++) {
+    string file_path = dir + "/input_fmap_" + to_string (i) + ".bin";
+    FILE *f = fopen (file_path.c_str (), "rb");
+    void *data = NULL;
+
+    if (f == NULL) {
+      cerr << "Unable to find input file, " << file_path << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    status = npumgr_query_input (context, network, i, &attr);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to query input info, " << status << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    /** TODO: currently, support TRIV2 (NHWC-based) format */
+    if (attr.fmt != NPUMGR_TENSOR_FMT_TRIV2) {
+      cerr << "Other format is not supported yet, " << attr.fmt << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    status = npumgr_buffer_create (context, &attr, &input_bufs[i]);
     if (status != NPUMGR_STATUS_SUCCESS) {
-      std::cerr << "Unable to create a npumgr network, " << status << "\n";
-      goto out;
+      cerr << "Unable to create input buffer, " << status << "\n";
+      fclose (f);
+      goto destroy_all;
     }
 
-    status = npumgr_query_network (context, network, &inout_num);
+    status = npumgr_buffer_map (context, &input_bufs[i], (uint8_t **) &data);
     if (status != NPUMGR_STATUS_SUCCESS) {
-      std::cerr << "Unable to query network info, " << status << "\n";
-      goto out;
+      cerr << "Unable to map input buffer, " << status << "\n";
+      fclose (f);
+      goto destroy_all;
     }
 
-    input_attr = g_new0 (npumgr_query_tensor_attr, inout_num.n_input);
-    output_attr = g_new0 (npumgr_query_tensor_attr, inout_num.n_input);
+    size_t read_bytes = fread (data, 1, input_bufs[i].buf_size, f);
+    if (read_bytes != input_bufs[i].buf_size) {
+      cerr << "Unable to read input data, " << read_bytes << " vs. "
+           << input_bufs[i].buf_size << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+    fclose (f);
 
-    for (uint32_t i = 0; i < inout_num.n_input; i++) {
-      status = npumgr_query_input (context, network, i, &input_attr[i]);
-      if (status != NPUMGR_STATUS_SUCCESS) {
-        std::cerr << "Unable to query input info, " << status << "\n";
-        g_free (input_attr);
-        g_free (output_attr);
-        goto out;
-      }
+    /** TODO: How unmap works? */
+#if 0
+    status = npumgr_buffer_unmap (context, &input_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to unmap buffer, " << status << "\n";
+      goto destroy_all;
     }
+#else
+    munmap (data, ALIGNED_SIZE (input_bufs[i].buf_size));
+#endif
 
-    for (uint32_t i = 0; i < inout_num.n_output; i++) {
-      status = npumgr_query_output (context, network, i, &output_attr[i]);
-      if (status != NPUMGR_STATUS_SUCCESS) {
-        std::cerr << "Unable to query output info, " << status << "\n";
-        g_free (input_attr);
-        g_free (output_attr);
-        goto out;
-      }
+    status = npumgr_network_set_input (context, network, i, &input_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to set input, " << status << "\n";
+      goto destroy_all;
     }
+  }
 
-    /* NYI: DO SOMETHING */
+  for (int i = 0; i < inout_num.n_output; i++) {
+    status = npumgr_query_output (context, network, i, &attr);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to query output info, " << status << "\n";
+      goto destroy_all;
+    }
 
-    g_free (input_attr);
-    g_free (output_attr);
+    /** TODO: currently, support TRIV2 (NHWC-based) format */
+    if (attr.fmt != NPUMGR_TENSOR_FMT_TRIV2) {
+      cerr << "Other format is not supported yet, " << attr.fmt << "\n";
+      goto destroy_all;
+    }
 
-    status = npumgr_network_destroy (context, network);
+    status = npumgr_buffer_create (context, &attr, &output_bufs[i]);
     if (status != NPUMGR_STATUS_SUCCESS) {
-      std::cerr << "Unable to destroy the npumgr network, " << status << "\n";
-      goto out;
+      cerr << "Unable to create output buffer, " << status << "\n";
+      goto destroy_all;
     }
 
-    ret = 0;
-  } else {
-    std::cerr << "Unable to open file " << argv[1] << "\n";
+    status = npumgr_network_set_output (context, network, i, &output_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to set output, " << status << "\n";
+      goto destroy_all;
+    }
   }
 
-out:
-  if (fd >= 0)
-    close (fd);
+  status = npumgr_network_prepare (context, network);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    goto destroy_all;
+  }
 
-  status = npumgr_context_destroy (context);
+  status = npumgr_execute_run (context, network);
   if (status != NPUMGR_STATUS_SUCCESS) {
-    std::cerr << "Unable to destroy the npumgr context, " << status << "\n";
-    return ret;
+    cerr << "Unable to execute the network, " << status << "\n";
+    goto destroy_all;
+  }
+
+  for (int i = 0; i < inout_num.n_output; i++) {
+    string file_path = string (dir) + "/output_fmap_" + to_string (i) + ".bin";
+    void *data = NULL;
+
+    status = npumgr_buffer_map (context, &output_bufs[i], (uint8_t **) &data);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to map output buffer, " << status << "\n";
+      goto destroy_all;
+    }
+
+    if (compare_data (file_path.c_str (), (const char *) data,
+                      output_bufs[i].buf_size) != 0) {
+      cerr << "Failed to get valid output data\n";
+      goto destroy_all;
+    }
+
+    /** TODO: How unmap works? */
+#if 0
+    status = npumgr_buffer_unmap (context, &output_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to unmap output buffer, " << status << "\n";
+      goto destroy_all;
+    }
+#else
+    munmap (data, ALIGNED_SIZE (output_bufs[i].buf_size));
+#endif
+  }
+
+destroy_all:
+  if (input_bufs) {
+    for (int i = 0; i < inout_num.n_input; i++) {
+      if (input_bufs[i].buf_handle == 0)
+        continue;
+
+      status = npumgr_buffer_destroy (context, &input_bufs[i]);
+      if (status != NPUMGR_STATUS_SUCCESS)
+        cerr << "Unable to destroy the buffer, " << status << "\n";
+    }
+  }
+
+  if (output_bufs) {
+    for (int i = 0; i < inout_num.n_output; i++) {
+      if (output_bufs[i].buf_handle == 0)
+        continue;
+
+      status = npumgr_buffer_destroy (context, &output_bufs[i]);
+      if (status != NPUMGR_STATUS_SUCCESS)
+        cerr << "Unable to destroy the buffer, " << status << "\n";
+    }
   }
 
+destroy_nw:
+  status = npumgr_network_destroy (context, network);
+  if (status != NPUMGR_STATUS_SUCCESS)
+    cerr << "Unable to destroy the npumgr network, " << status << "\n";
+
+destroy_ctx:
+  status = npumgr_context_destroy (context);
+  if (status != NPUMGR_STATUS_SUCCESS)
+    cerr << "Unable to destroy the npumgr context, " << status << "\n";
+
+  return status;
+}
+
+int
+main (int argc, char **argv) {
+  int fd, ret = -EINVAL;
+
+  if (argc != 2) {
+    cerr << "Please provide model datapath (i.e., including .tvn and .bin)\n";
+    cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+    return 0;
+  }
+
+  string dir (argv[1]);
+  string model_path = dir + "/model.tvn";
+
+  if (!g_file_test (dir.c_str (), G_FILE_TEST_IS_DIR)) {
+    cerr << "Invalid model datapath: " << dir << "\n";
+    goto out;
+  }
+
+  fd = open (model_path.c_str (), O_RDONLY);
+  if (fd < 0) {
+    cerr << "Unable to open file " << dir << "\n";
+    goto out;
+  }
+
+  ret = start_npumgr_test (fd, dir);
+  close (fd);
+
+out:
+  if (ret == 0)
+    cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
+  else
+    cerr << "[APPTEST] " << argv[0] << ": FAILED (" << ret << ")\n";
+
   return ret;
 }
index d9a3ba3..644b332 100644 (file)
@@ -24,6 +24,23 @@ extern "C" {
 NpumgrDevice *npumgr_device_triv2_new (void);
 }
 
+typedef struct {
+  GMutex mutex;
+  GCond cond;
+  gboolean done;
+} async_cb_priv;
+
+void
+async_cb (output_buffers *output, int req_id, void *data) {
+  async_cb_priv *priv = (async_cb_priv *) data;
+
+  g_mutex_lock (&priv->mutex);
+  /* as output is dmabuf, don't need to perform memcpy */
+  priv->done = TRUE;
+  g_cond_broadcast (&priv->cond);
+  g_mutex_unlock (&priv->mutex);
+}
+
 /**
  * @brief Class for triv2 npumgr buffer
  */
@@ -128,7 +145,8 @@ class NpumgrNetworkTriv2 {
         in_buffer_type_ (NPUMGR_BUF_TYPE_MAX),
         out_buffer_type_ (NPUMGR_BUF_TYPE_MAX),
         in_tensor_names_ (NULL),
-        out_tensor_names_ (NULL) {
+        out_tensor_names_ (NULL),
+        async_ (FALSE) {
     handle_ = g_atomic_int_add (&g_nw_handle, 1);
     meta_ = (npubin_meta *) g_new0 (npubin_meta, 1);
     model_file_ = model_file;
@@ -137,6 +155,11 @@ class NpumgrNetworkTriv2 {
 
     memset (&in_info_, '\x00', sizeof (in_info_));
     memset (&out_info_, '\x00', sizeof (out_info_));
+
+    timeout_ = default_timeout;
+    g_mutex_init (&async_priv_.mutex);
+    g_cond_init (&async_priv_.cond);
+    async_priv_.done = FALSE;
   }
   ~NpumgrNetworkTriv2 () {
     if (model_id_ > 0)
@@ -262,10 +285,47 @@ class NpumgrNetworkTriv2 {
     return TRUE;
   }
 
+  void setAsync (gboolean async) { async_ = async; }
+  gboolean isAsync () const { return async_; }
+
   gboolean prepare () {
     return (setNPU_dataInfo (dev_, model_id_, &in_info_, &out_info_) == 0);
   }
 
+  gboolean execute () {
+    int req_id;
+
+    if (isAsync ()) {
+      async_priv_.done = FALSE;
+      req_id =
+          runNPU_model (dev_, model_id_, NPU_INFER_NON_BLOCKING, &in_buffers_,
+                        &out_buffers_, async_cb, &async_priv_);
+    } else {
+      req_id = runNPU_model (dev_, model_id_, NPU_INFER_BLOCKING, &in_buffers_,
+                             &out_buffers_, NULL, NULL);
+    }
+
+    return (req_id > 0);
+  }
+
+  gboolean wait () {
+    gint64 end_time;
+    gboolean result = TRUE;
+
+    end_time = g_get_monotonic_time () + timeout_ * G_TIME_SPAN_MILLISECOND;
+
+    g_mutex_lock (&async_priv_.mutex);
+    while (async_priv_.done != TRUE) {
+      if (!g_cond_wait_until (&async_priv_.cond, &async_priv_.mutex,
+                              end_time)) {
+        result = FALSE;
+        break;
+      }
+    }
+    g_mutex_unlock (&async_priv_.mutex);
+    return result;
+  }
+
  private:
   static volatile guint g_nw_handle;
 
@@ -288,6 +348,10 @@ class NpumgrNetworkTriv2 {
 
   tensors_data_info in_info_;
   tensors_data_info out_info_;
+
+  gint64 timeout_;
+  gboolean async_;
+  async_cb_priv async_priv_;
 };
 
 static void
@@ -336,6 +400,25 @@ class NpumgrContextTriv2 {
         nw_table_, GSIZE_TO_POINTER (handle));
   }
 
+  gboolean executeNetwork (npumgr_network handle, gboolean async = FALSE) {
+    NpumgrNetworkTriv2 *nw = findNetwork (handle);
+
+    g_return_val_if_fail (nw != NULL, FALSE);
+
+    nw->setAsync (async);
+    return nw->execute ();
+  }
+
+  /* only after calling async execution */
+  gboolean waitNetwork (npumgr_network handle) {
+    NpumgrNetworkTriv2 *nw = findNetwork (handle);
+
+    g_return_val_if_fail (nw != NULL, FALSE);
+    g_return_val_if_fail (nw->isAsync (), FALSE);
+
+    return nw->wait ();
+  }
+
   NpumgrBufferTriv2 *findBuffer (npumgr_buffer_h handle) {
     return (NpumgrBufferTriv2 *) g_hash_table_lookup (
         buf_table_, GSIZE_TO_POINTER (handle));
@@ -473,6 +556,7 @@ static npumgr_status_e triv2_buffer_map (NpumgrDevice *device,
 static npumgr_status_e triv2_buffer_unmap (NpumgrDevice *device,
                                            npumgr_context ctx,
                                            npumgr_buffer *buf);
+
 static npumgr_status_e triv2_query_network (NpumgrDevice *device,
                                             npumgr_context ctx,
                                             npumgr_network nw_handle,
@@ -485,6 +569,28 @@ static npumgr_status_e triv2_query_output (NpumgrDevice *device,
                                            npumgr_context ctx,
                                            npumgr_network nw_handle, int index,
                                            npumgr_query_tensor_attr *data);
+static npumgr_status_e triv2_execute_trigger (NpumgrDevice *device,
+                                              npumgr_context ctx,
+                                              npumgr_network nw_handle);
+static npumgr_status_e triv2_execute_wait (NpumgrDevice *device,
+                                           npumgr_context ctx,
+                                           npumgr_network nw_handle);
+static npumgr_status_e triv2_execute_run (NpumgrDevice *device,
+                                          npumgr_context ctx,
+                                          npumgr_network nw_handle);
+
+static npumgr_status_e triv2_execute_realtime (NpumgrDevice *device,
+                                               npumgr_context ctx,
+                                               npumgr_network nw_handle,
+                                               uint32_t task_handle,
+                                               uint32_t subtask_id);
+static npumgr_status_e triv2_execute_wait_realtime (NpumgrDevice *device,
+                                                    npumgr_context ctx,
+                                                    npumgr_network nw_handle,
+                                                    uint32_t *golden_val,
+                                                    uint32_t **golden_addr);
+static npumgr_status_e triv2_execute_completed_realtime (
+    NpumgrDevice *device, npumgr_context ctx, npumgr_network nw_handle);
 
 extern NpumgrDevice *
 npumgr_device_triv2_new (void) {
@@ -516,6 +622,15 @@ npumgr_device_triv2_class_init (NpumgrDeviceTriv2Class *klass) {
   npumgr_device_class->query_network = triv2_query_network;
   npumgr_device_class->query_input = triv2_query_input;
   npumgr_device_class->query_output = triv2_query_output;
+
+  npumgr_device_class->execute_trigger = triv2_execute_trigger;
+  npumgr_device_class->execute_wait = triv2_execute_wait;
+  npumgr_device_class->execute_run = triv2_execute_run;
+  npumgr_device_class->execute_realtime = triv2_execute_realtime;
+  npumgr_device_class->execute_wait_realtime = triv2_execute_wait_realtime;
+  npumgr_device_class->execute_completed_realtime =
+      triv2_execute_completed_realtime;
+
   /* NYI */
 }
 
@@ -533,10 +648,8 @@ npumgr_device_triv2_init (NpumgrDeviceTriv2 *self) {
   status = getNPUdeviceByTypeAny (&priv->dev, NPUCOND_TRIV2_CONN_SOCIP, 2);
   if (status != 0) {
     g_critical ("Unable to find/open 2-TOPS TRIV2 device\n");
-    priv->dev = NULL;
     return;
   }
-  /* NYI */
 }
 
 static void
@@ -624,11 +737,10 @@ triv2_context_create (NpumgrDevice *device, int device_id, int priority,
   NpumgrContextTriv2 *context = new NpumgrContextTriv2 (priv->dev, priority);
   *ctx_handle = context->getHandle ();
 
-  if (insert_context (priv, context->getHandle (), context)) {
-    return NPUMGR_STATUS_SUCCESS;
-  } else {
+  if (!insert_context (priv, context->getHandle (), context))
     return NPUMGR_STATUS_ERR_FAIL;
-  }
+
+  return NPUMGR_STATUS_SUCCESS;
 }
 
 static npumgr_status_e
@@ -639,10 +751,10 @@ triv2_context_destroy (NpumgrDevice *device, npumgr_context ctx_handle) {
   NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
   NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
 
-  if (remove_context (priv, ctx_handle))
-    return NPUMGR_STATUS_SUCCESS;
-  else
+  if (!remove_context (priv, ctx_handle))
     return NPUMGR_STATUS_ERR_CTX_INVALID;
+
+  return NPUMGR_STATUS_SUCCESS;
 }
 
 static npumgr_status_e
@@ -787,11 +899,10 @@ triv2_network_destroy (NpumgrDevice *device, npumgr_context ctx_handle,
 
   g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
 
-  if (context->removeNetwork (nw_handle)) {
-    return NPUMGR_STATUS_SUCCESS;
-  } else {
+  if (!context->removeNetwork (nw_handle))
     return NPUMGR_STATUS_ERR_FAIL;
-  }
+
+  return NPUMGR_STATUS_SUCCESS;
 }
 
 static npumgr_status_e
@@ -915,7 +1026,7 @@ triv2_query_input (NpumgrDevice *device, npumgr_context ctx_handle,
   attr->plane = 3;
 
   attr->size = network->getInTensorSize (index);
-  attr->fmt = NPUMGR_TENSOR_FMT_NHWC;
+  attr->fmt = NPUMGR_TENSOR_FMT_TRIV2;
   attr->type = NPUMGR_TENSOR_DATA_UINT8;
 
   attr->quant_type = NPUMGR_TENSOR_QNT_AFFINE_ASYMM;
@@ -955,7 +1066,7 @@ triv2_query_output (NpumgrDevice *device, npumgr_context ctx_handle,
   attr->plane = 3;
 
   attr->size = network->getOutTensorSize (index);
-  attr->fmt = NPUMGR_TENSOR_FMT_NHWC;
+  attr->fmt = NPUMGR_TENSOR_FMT_TRIV2;
   attr->type = NPUMGR_TENSOR_DATA_UINT8;
 
   attr->quant_type = NPUMGR_TENSOR_QNT_AFFINE_ASYMM;
@@ -964,3 +1075,84 @@ triv2_query_output (NpumgrDevice *device, npumgr_context ctx_handle,
 
   return NPUMGR_STATUS_SUCCESS;
 }
+
+static npumgr_status_e
+triv2_execute_trigger (NpumgrDevice *device, npumgr_context ctx_handle,
+                       npumgr_network nw_handle) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (nw_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  if (!context->executeNetwork (nw_handle, TRUE))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_execute_wait (NpumgrDevice *device, npumgr_context ctx_handle,
+                    npumgr_network nw_handle) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (nw_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  if (!context->waitNetwork (nw_handle))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_execute_run (NpumgrDevice *device, npumgr_context ctx_handle,
+                   npumgr_network nw_handle) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (nw_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  if (!context->executeNetwork (nw_handle))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_execute_realtime (NpumgrDevice *device, npumgr_context ctx_handle,
+                        npumgr_network nw_handle, uint32_t task_handle,
+                        uint32_t subtask_id) {
+  /* NYI */
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_execute_wait_realtime (NpumgrDevice *device, npumgr_context ctx_handle,
+                             npumgr_network nw_handle, uint32_t *golden_val,
+                             uint32_t **golden_addr) {
+  /* NYI */
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_execute_completed_realtime (NpumgrDevice *device,
+                                  npumgr_context ctx_handle,
+                                  npumgr_network nw_handle) {
+  /* NYI */
+  return NPUMGR_STATUS_SUCCESS;
+}
diff --git a/tests/apptests/npumgr/sr.odl.NPUManager.conf b/tests/apptests/npumgr/sr.odl.NPUManager.conf
new file mode 100644 (file)
index 0000000..c8a5675
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!--
+  This is a sample D-Bus configuration to test VD NPUMGR dummy module.
+       Please locate this file to your D-Bus system bus policy directory.
+  (e.g., /usr/share/dbus-1/system.d/sr.odl.NPUManager.conf)
+
+  Example command line for testing:
+  $ /usr/lib64/npu-engine/bin/apptests/npumgr/dummy_npumgr
+  $ /usr/lib64/npu-engine/bin/apptests/npumgr/apptest_npumgr \
+    /usr/share/npu-engine/testdata/TRIV235_2TOPS/MOBILENET_V1
+-->
+
+<busconfig>
+        <policy user="root">
+                <allow own="sr.odl.NPUManager.API"/>
+        </policy>
+        <policy context="default">
+                <allow send_path="/sr/org/NPUManager/APIObject"/>
+                <allow send_destination="sr.odl.NPUManager.API"/>
+                <allow receive_sender="sr.odl.NPUManager.API"/>
+        </policy>
+</busconfig>