[ASR] make ASR use a dummy model
authorDongju Chae <dongju.chae@samsung.com>
Fri, 29 Nov 2019 05:53:58 +0000 (14:53 +0900)
committer송욱/On-Device Lab(SR)/Staff Engineer/삼성전자 <wook16.song@samsung.com>
Tue, 17 Dec 2019 06:22:50 +0000 (15:22 +0900)
This commit makes ASR use a dummy model to utilize existing codes.

In ASR device, registerModel() is not required. But, we can utilize
existing codes using a dummy model.
Also, as ASR can't resize I/O buffers on model registeration, new API
.resize_buffers() is required.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
include/common/typedef.h
src/core/ip/plugin-comm-ip.c
src/core/ne-comm.h
src/core/ne-handler.c
src/core/ne-host-input-service.c

index b8a2107..cc9181d 100644 (file)
@@ -58,6 +58,7 @@ typedef enum {
   SMODEL_OPS_ARM = 1, /**< ARM model */
   SMODEL_OPS_INTERNAL_CAM = 2, /**< Internal Camera model */
   SMODEL_OPS_I2S_MIC = 3,  /**< Internal Mic model */
+  SMODEL_OPS_NPU_ASR = 4, /** NPU-ASR model (used only internally) */
   SMODEL_OPS_END,
 } model_opmode;
 
index bcd3e66..77529f7 100644 (file)
@@ -57,6 +57,8 @@
 
 #define MAX_NUM_MODELS 1
 
+#define IS_ASR_DEVICE(npu_dev) ((npu_dev)->device_type & DEVICETYPE_ASR)
+
 /** @brief Locking macros */
 #define DEVICE_LOCK() pthread_mutex_lock(&npu_dev->mutex)
 #define DEVICE_UNLOCK() pthread_mutex_unlock(&npu_dev->mutex)
@@ -152,7 +154,7 @@ static int model_dev_validity_check (npudev_h dev, uint32_t modelid)
   }
 
   npu_dev = dev;
-  if (npu_dev->device_type & DEVICETYPE_ASR) {
+  if (IS_ASR_DEVICE(npu_dev)) {
      if (npu_dev != libnpupriv.asr_dev)
       return -EINVAL;
 
@@ -293,6 +295,75 @@ int getNPUdevice(npudev_h *dev, uint32_t id)
 }
 
 /**
+ * @brief Send the NN model to NPU.
+ * @param[in] dev The NPU device handle
+ * @param[in] model_mem The NPU NN model loaded into hwmem
+ * @param[out] modelid The modelid allocated for this instance of NN model.
+ * @return @c 0 if no error. otherwise a negative error value
+ *
+ * @detail This version does not support multimodel. Thus, dev should be
+ *         emptied with unregister function before registering another.
+ *         This may incur some latency with memory compatcion.
+ * @todo Add a variation: in-memory model register.
+ */
+static int registerNPUmodelmem(npudev_h dev, hwmem *model_mem, uint32_t *modelid)
+{
+  npu_device *npu_dev = (npu_device *) dev;
+  model_private *priv_model = NULL;
+  uint32_t id;
+  int err;
+
+  if (npu_dev == NULL || modelid == NULL) {
+    return -EINVAL;
+  }
+
+  if (!((npu_dev == libnpupriv.npu_dev && model_mem) ||
+        (npu_dev == libnpupriv.asr_dev && !model_mem))) {
+    return -EINVAL;
+  }
+
+  if (npu_dev->num_models == 0) {
+    pthread_mutex_init (&npu_dev->mutex, NULL);
+    pthread_cond_init (&npu_dev->cond, NULL);
+  } else if (npu_dev->num_models == MAX_NUM_MODELS) {
+    return -ENOMEM;
+  }
+
+  /** assign temporary number (but one of candidates) to id */
+  id = npu_dev->num_models;
+
+  priv_model = (model_private *) malloc (sizeof (*priv_model));
+  if (!priv_model) {
+    err = -ENOMEM;
+    goto error;
+  }
+
+  /** copy model to a created hwmem */
+  err = libnpupriv.host_handle->registerModel (model_mem,
+      &(priv_model->model_id), &(priv_model->model_version));
+  if (err < 0) {
+    logerr (TAG, "Registering model has failed, errno: %d\n", err);
+    free (priv_model);
+    goto error;
+  }
+
+  /* update variables to be set */
+  npu_dev->models[id] = priv_model;
+  npu_dev->num_models += 1;
+  *modelid = id;
+
+  return 0;
+
+error:
+  if (npu_dev->num_models == 0) {
+    pthread_cond_destroy (&npu_dev->cond);
+    pthread_mutex_destroy (&npu_dev->mutex);
+  }
+
+  return err;
+}
+
+/**
  * @brief Returns the handle of the chosen ASR devices.
  * @param[out] dev The ASR device handle
  * @param[in] id The ASR id to get the handle. 0 <= id < getnumASRdevice().
@@ -321,16 +392,30 @@ int getASRdevice(npudev_h *dev, uint32_t id)
       return -EINVAL;
     }
   } else {
+    uint32_t modelid;
+    int err;
+
     asr_dev = (npu_device *) malloc (sizeof (npu_device));
     if (asr_dev == NULL) {
       return -errno;
     }
+
     asr_dev->device_id = id;
+    asr_dev->num_models = 0;
     asr_dev->sequence_in = 0;
     asr_dev->sequence_out = 0;
+    asr_dev->activated_model_id = -1;
     asr_dev->device_type = NPUCOND_ASR_CONN_SOCIP;
 
     libnpupriv.asr_dev = asr_dev;
+
+    /** assume that model[0] is always registered */
+    if ((err = registerNPUmodelmem((npudev_h) asr_dev, NULL, &modelid)) < 0) {
+      logerr (TAG, "Failed to register NPU model, errno: %d\n", err);
+      free (asr_dev);
+      return err;
+    }
+
     *dev = (npudev_h) libnpupriv.asr_dev;
   }
 
@@ -432,71 +517,6 @@ out:
 /**
  * @brief Send the NN model to NPU.
  * @param[in] dev The NPU device handle
- * @param[in] model_mem The NPU NN model loaded into hwmem
- * @param[out] modelid The modelid allocated for this instance of NN model.
- * @return @c 0 if no error. otherwise a negative error value
- *
- * @detail This version does not support multimodel. Thus, dev should be
- *         emptied with unregister function before registering another.
- *         This may incur some latency with memory compatcion.
- * @todo Add a variation: in-memory model register.
- */
-static int registerNPUmodelmem(npudev_h dev, hwmem *model_mem, uint32_t *modelid)
-{
-  npu_device *npu_dev = (npu_device *) dev;
-  model_private *priv_model = NULL;
-  uint32_t id;
-  int err;
-
-  if (npu_dev == NULL || model_mem == NULL || modelid == NULL ||
-      npu_dev != libnpupriv.npu_dev) {
-    return -EINVAL;
-  }
-
-  if (npu_dev->num_models == 0) {
-    pthread_mutex_init (&npu_dev->mutex, NULL);
-    pthread_cond_init (&npu_dev->cond, NULL);
-  } else if (npu_dev->num_models == MAX_NUM_MODELS) {
-    return -ENOMEM;
-  }
-
-  /** assign temporary number (but one of candidates) to id */
-  id = npu_dev->num_models;
-
-  priv_model = (model_private *) malloc (sizeof (*priv_model));
-  if (!priv_model) {
-    err = -ENOMEM;
-    goto error;
-  }
-
-  /** copy model to a created hwmem */
-  err = libnpupriv.host_handle->registerModel (model_mem,
-      &(priv_model->model_id), &(priv_model->model_version));
-  if (err < 0) {
-    logerr (TAG, "Registering model has failed, errno: %d\n", err);
-    free (priv_model);
-    goto error;
-  }
-
-  /* update variables to be set */
-  npu_dev->models[id] = priv_model;
-  npu_dev->num_models += 1;
-  *modelid = id;
-
-  return 0;
-
-error:
-  if (npu_dev->num_models == 0) {
-    pthread_cond_destroy (&npu_dev->cond);
-    pthread_mutex_destroy (&npu_dev->mutex);
-  }
-
-  return err;
-}
-
-/**
- * @brief Send the NN model to NPU.
- * @param[in] dev The NPU device handle
  * @param[in] model The generic buffer for the compiled NPU NN model.
  * @param[out] modelid The modelid allocated for this instance of NN model.
  * @return @c 0 if no error. otherwise a negative error value
@@ -512,6 +532,10 @@ int registerNPUmodel(npudev_h dev, generic_buffer *model, uint32_t *modelid)
   int err;
   hwmem *hwmem_ptr;
 
+  if (IS_ASR_DEVICE((npu_device*) dev)) {
+    return 0;
+  }
+
   /** check the file */
   if (model == NULL) {
     return -EINVAL;
@@ -584,6 +608,10 @@ int unregisterNPUmodel(npudev_h dev, uint32_t modelid)
   /** first stop the model, and then unregister */
 
   npu_dev = dev;
+  if (IS_ASR_DEVICE(npu_dev)) {
+    return 0;
+  }
+
   DEVICE_LOCK();
 
   if (npu_dev->activated_model_id == modelid) {
@@ -821,6 +849,10 @@ static int activateNPUmodel(npudev_h dev, uint32_t modelid, npuOutputNotify cb,
   }
 
   npu_dev = dev;
+  if (IS_ASR_DEVICE(npu_dev)) {
+    /** ASR doesn't have explit models; always set modelid to zero */
+    modelid = 0;
+  }
   if (npu_dev->activated_model_id == modelid) {
     /** already activated */
     return 0;
@@ -870,7 +902,18 @@ static int runNPU_async_util(npudev_h dev, uint32_t modelid, const input_buffers
     return err;
   }
 
+  /** TODO: handle more than 1 input buffer at once */
+  in_buf = &input->bufs[0];
+
   npu_dev = dev;
+  if (IS_ASR_DEVICE(npu_dev)) {
+    /** @todo we don't have a specific decision for buffer sizes. fix this later. */
+    err = libnpupriv.host_handle->resizeBuffers (in_buf->size);
+    if (err < 0) {
+      logerr (TAG, "Fail to resize buffers\n");
+      goto out;
+    }
+  }
 
   /** This has to be get a new/existing buf, depending on buffering type */
   buffer_ptr = libnpupriv.host_handle->getCurrentInputBuffer(mode, &err);
@@ -878,7 +921,7 @@ static int runNPU_async_util(npudev_h dev, uint32_t modelid, const input_buffers
     logwarn (TAG, "New buffer dropped by QoS\n");
     goto out;
   } else if (err < 0 || buffer_ptr == NULL) {
-    logerr (TAG, "Error getting bufferm, errno: %d\n", err);
+    logerr (TAG, "Error getting buffer, errno: %d\n", err);
     goto out;
   }
 
@@ -888,9 +931,6 @@ static int runNPU_async_util(npudev_h dev, uint32_t modelid, const input_buffers
     goto out_unlock;
   }
 
-  /** TODO: handle more than 1 input buffer at once */
-  in_buf = &input->bufs[0];
-
   if (in_buf->type != BUFFER_DMABUF) {
     if ((err = buffer_set_dmabuf (buffer_ptr, 0)) < 0) {
       logerr (TAG, "Error disabling dmabuf sharing\n");
@@ -1014,7 +1054,7 @@ int runNPU_sync(npudev_h dev, uint32_t modelid, const input_buffers *input,
     return err;
   }
 
-  loginfo (TAG, "Running input with sequence %d synchronously\n", sequence);
+  loginfo (TAG, "Running input with sequence %ld synchronously\n", sequence);
 
   /** wait until the internal callback is finished */
   DEVICE_LOCK();
@@ -1057,7 +1097,7 @@ int runNPU_async(npudev_h dev, uint32_t modelid, const input_buffers *input,
     return err;
   }
 
-  loginfo (TAG, "Running input with sequence %d asynchronously\n", sequence);
+  loginfo (TAG, "Running input with sequence %ld asynchronously\n", *sequence);
 
   return 0;
 }
index 7f8de07..e472546 100644 (file)
@@ -47,6 +47,14 @@ typedef struct {
    */
   uint32_t (*getNumRegisteredModels) ();
 
+  /**
+   * brief resize I/O buffers by force
+   * param[in] size the buffer size; a zero size means free
+   * return 0 if no error, otherwise a negative errno
+   * note this should be called only for ASR inferences.
+   */
+  int (*resizeBuffers) (uint64_t size);
+
 /* Operators: N1 calls N2 with these callbacks registred. */
   /**
    * @brief Host tells us to register a model
index 690b35f..b5a6bc6 100644 (file)
@@ -171,6 +171,29 @@ handler_get_num_registered_models (void)
 }
 
 /**
+ * @brief resize I/O buffers by force
+ * @param[in] size the buffer size; a zero size means free
+ * @return 0 if no error, otherwise a negative errno
+ * @note this should be called only for ASR inferences.
+ */
+static int
+handler_resize_buffers (uint64_t size)
+{
+  int err = 0;
+
+  HANDLER_LOCK ();
+
+  if (hpriv.buffer_size < size || hpriv.num_models == 0) {
+    err = GET_MEM()->resize_buffers (size);
+    hpriv.buffer_size = size;
+  }
+
+  HANDLER_UNLOCK ();
+
+  return err;
+}
+
+/**
  * @brief create and register model with hwmem
  * @param[in] mem The hwmem block/chunk with the model from the host.
  * @param[in] id ID of the model registered
@@ -197,32 +220,51 @@ handler_register_model (hwmem *hwmem, uint64_t *id, uint64_t *version)
 
   /** TODO: add a check that the same model has not been registered before */
 
-  /* activate hwmem; it means that it's not compacted until unregistration */
-  if ((err = hwmem_activate (hwmem)) < 0)
-    goto err_free;
+  new_model = &mpriv->model;
+  new_model->inputSequence = 0;
+  new_model->meta = &mpriv->meta;
 
-  if ((err = hwmem_get_data (hwmem, &ptr)) < 0)
-    goto err_deactivate;
+  if (hwmem) {
+    /* activate hwmem; it means that it's not compacted until unregistration */
+    if ((err = hwmem_activate (hwmem)) < 0)
+      goto err_free;
 
-  if ((err = parse_model_meta (mpriv, ptr)) < 0)
-    goto err_deactivate;
+    if ((err = hwmem_get_data (hwmem, &ptr)) < 0)
+      goto err_deactivate;
 
-  if (hpriv.buffer_size < mpriv->meta.buffer_size) {
-    /* need to increase buffer size! */
-    if (GET_MEM()->resize_buffers (mpriv->meta.buffer_size) != 0) {
-      /* fail to resize... */
-      err = -ENOMEM;
-      goto err_free;
+    if ((err = parse_model_meta (mpriv, ptr)) < 0)
+      goto err_deactivate;
+
+    if (hpriv.buffer_size < mpriv->meta.buffer_size) {
+      /* need to increase buffer size! */
+      if (GET_MEM()->resize_buffers (mpriv->meta.buffer_size) != 0) {
+        /* fail to resize... */
+        err = -ENOMEM;
+        goto err_free;
+      }
+      hpriv.buffer_size = mpriv->meta.buffer_size;
     }
-  }
 
-  new_model = &mpriv->model;
-  new_model->meta = &mpriv->meta;
-  new_model->memblock = hwmem;
-  new_model->model_size = hwmem->size;
-  new_model->inputSequence = 0;
+    new_model->memblock = hwmem;
+    new_model->model_size = hwmem->size;
+
+    hpriv.model_size += hwmem->size;
+  } else {
+    /* set dummy metadata */
+    mpriv->meta.type = SMODEL_OPS_NPU_ASR;
+    mpriv->meta.size = 0;
+    mpriv->meta.buffer_size = 4096;
+    mpriv->meta.input_offset = 0;
+    mpriv->meta.input_size = 4096;
+    mpriv->meta.output_offset = 0;
+    mpriv->meta.output_size = 4096;
+    mpriv->meta.model_id = 0;
+    mpriv->meta.model_version = 0;
+
+    new_model->memblock = NULL;
+    new_model->model_size = 0;
+  }
 
-  hpriv.model_size += hwmem->size;
   hpriv.num_models++;
 
   list_add (&hpriv.model_priv_list, &mpriv->list);
@@ -258,7 +300,7 @@ handler_unregister_model (uint64_t id, uint64_t version)
   model *model;
   model_priv *mpriv;
   int err = 0;
-  uint64_t size;
+  uint64_t model_size, buffer_size;
 
   HANDLER_LOCK ();
 
@@ -272,24 +314,30 @@ handler_unregister_model (uint64_t id, uint64_t version)
 
   mpriv = GET_MODEL_PRIVATE (model);
 
-  if ((err = hwmem_deactivate (mpriv->hwmem)) < 0)
-    goto err_unlock;
+  if (mpriv->hwmem) {
+    if ((err = hwmem_deactivate (mpriv->hwmem)) < 0)
+      goto err_unlock;
 
-  size = mpriv->hwmem->size;
-  if ((err = GET_MEM()->dealloc (mpriv->hwmem)) < 0)
-    goto err_activate;
+    model_size = mpriv->hwmem->size;
+    if ((err = GET_MEM()->dealloc (mpriv->hwmem)) < 0)
+      goto err_activate;
+  } else {
+    model_size = 0;
+  }
 
   list_del (&hpriv.model_priv_list, &mpriv->list);
 
   /* resizing should be successful because buffer is resized to equal or smaller size */
-  assert (GET_MEM()->resize_buffers (get_maximum_buffer_size ()) == 0);
+  buffer_size = get_maximum_buffer_size ();
+  assert (GET_MEM()->resize_buffers (buffer_size) == 0);
 
   free (mpriv);
 
   assert (hpriv.num_models > 0);
 
   hpriv.num_models--;
-  hpriv.model_size -= size;
+  hpriv.model_size -= model_size;
+  hpriv.buffer_size = buffer_size;
 
   HANDLER_UNLOCK ();
 
@@ -403,6 +451,7 @@ handler_validate_buffer (buffer *buffer)
  * @brief the instance of host handler. Its callbacks are called in N1.
  */
 static hostHandlerInfo handler = {
+  .resizeBuffers = handler_resize_buffers,
   .getSizeModels = handler_get_size_models,
   .getSizeBuffers = handler_get_size_buffers,
   .getNumRegisteredModels = handler_get_num_registered_models,
index 47f26a2..40a3142 100644 (file)
@@ -711,6 +711,10 @@ void fini_host_inputservice (void)
      */
     pthread_mutex_lock(&npriv->proc_thread.mutex);
     while (npriv->proc_thread.state != IDLE && npriv->proc_thread.state != ERROR) {
+      /** the destructor invocation may drop the current processing */
+      npriv->haltmode = HALT_NOW;
+      npriv->proc_thread.state = HALT_REQUESTED;
+      pthread_cond_broadcast(&npriv->proc_thread.cond);
       pthread_cond_wait(&npriv->proc_thread.cond, &npriv->proc_thread.mutex);
     }
     pthread_mutex_unlock(&npriv->proc_thread.mutex);