[Android] cache method id
authorJaeyun <jy1210.jung@samsung.com>
Wed, 20 May 2020 11:49:51 +0000 (20:49 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 2 Jun 2020 12:19:44 +0000 (21:19 +0900)
1. get required method ids to improve performance when initializing the pipe info.
2. add internal method to handle arraylist.

Signed-off-by: Jaeyun <jy1210.jung@samsung.com>
api/android/api/src/main/java/org/nnsuite/nnstreamer/TensorsData.java
api/android/api/src/main/java/org/nnsuite/nnstreamer/TensorsInfo.java
api/android/api/src/main/jni/nnstreamer-native-api.c
api/android/api/src/main/jni/nnstreamer-native-customfilter.c
api/android/api/src/main/jni/nnstreamer-native-pipeline.c
api/android/api/src/main/jni/nnstreamer-native-singleshot.c
api/android/api/src/main/jni/nnstreamer-native.h

index cc97ca6..454243d 100644 (file)
@@ -170,6 +170,13 @@ public final class TensorsData implements AutoCloseable {
     }
 
     /**
+     * Internal method called from native to get the array of tensor data.
+     */
+    private Object[] getDataArray() {
+        return mDataList.toArray();
+    }
+
+    /**
      * Internal method to check the index.
      *
      * @throws IndexOutOfBoundsException if the given index is invalid
index 44820cb..5dfd83e 100644 (file)
@@ -212,52 +212,14 @@ public final class TensorsInfo implements AutoCloseable, Cloneable {
      * Internal method called from native to add new info.
      */
     private void appendInfo(String name, int type, int[] dimension) {
-        addTensorInfo(name, convertType(type), dimension);
+        addTensorInfo(name, TensorInfo.convertType(type), dimension);
     }
 
     /**
-     * Internal method to get the tensor type from int value.
+     * Internal method called from native to get the array of tensor info.
      */
-    private NNStreamer.TensorType convertType(int value) {
-        NNStreamer.TensorType type = NNStreamer.TensorType.UNKNOWN;
-
-        switch (value) {
-            case 0:
-                type = NNStreamer.TensorType.INT32;
-                break;
-            case 1:
-                type = NNStreamer.TensorType.UINT32;
-                break;
-            case 2:
-                type = NNStreamer.TensorType.INT16;
-                break;
-            case 3:
-                type = NNStreamer.TensorType.UINT16;
-                break;
-            case 4:
-                type = NNStreamer.TensorType.INT8;
-                break;
-            case 5:
-                type = NNStreamer.TensorType.UINT8;
-                break;
-            case 6:
-                type = NNStreamer.TensorType.FLOAT64;
-                break;
-            case 7:
-                type = NNStreamer.TensorType.FLOAT32;
-                break;
-            case 8:
-                type = NNStreamer.TensorType.INT64;
-                break;
-            case 9:
-                type = NNStreamer.TensorType.UINT64;
-                break;
-            default:
-                /* unknown type */
-                break;
-        }
-
-        return type;
+    private Object[] getInfoArray() {
+        return mInfoList.toArray();
     }
 
     /**
@@ -281,7 +243,7 @@ public final class TensorsInfo implements AutoCloseable, Cloneable {
      */
     private static class TensorInfo {
         private String name = null;
-        private NNStreamer.TensorType type = NNStreamer.TensorType.UNKNOWN;
+        private int type = NNStreamer.TensorType.UNKNOWN.ordinal();
         private int[] dimension = new int[NNStreamer.TENSOR_RANK_LIMIT];
 
         public TensorInfo(@Nullable String name, NNStreamer.TensorType type, @NonNull int[] dimension) {
@@ -303,15 +265,11 @@ public final class TensorsInfo implements AutoCloseable, Cloneable {
                 throw new IllegalArgumentException("Given tensor type is unknown or unsupported type");
             }
 
-            this.type = type;
+            this.type = type.ordinal();
         }
 
         public NNStreamer.TensorType getType() {
-            return this.type;
-        }
-
-        public int getTypeValue() {
-            return this.type.ordinal();
+            return convertType(this.type);
         }
 
         public void setDimension(@NonNull int[] dimension) {
@@ -344,22 +302,30 @@ public final class TensorsInfo implements AutoCloseable, Cloneable {
         }
 
         public int getSize() {
-            int size = 0;
-
-            if (type == NNStreamer.TensorType.INT32 ||
-                    type == NNStreamer.TensorType.UINT32 ||
-                    type == NNStreamer.TensorType.FLOAT32) {
-                size = 4;
-            } else if (type == NNStreamer.TensorType.INT16 ||
-                    type == NNStreamer.TensorType.UINT16) {
-                size = 2;
-            } else if (type == NNStreamer.TensorType.INT8 ||
-                    type == NNStreamer.TensorType.UINT8) {
-                size = 1;
-            } else if (type == NNStreamer.TensorType.FLOAT64 ||
-                    type == NNStreamer.TensorType.INT64 ||
-                    type == NNStreamer.TensorType.UINT64) {
-                size = 8;
+            int size;
+
+            switch (convertType(this.type)) {
+                case INT32:
+                case UINT32:
+                case FLOAT32:
+                    size = 4;
+                    break;
+                case INT16:
+                case UINT16:
+                    size = 2;
+                    break;
+                case INT8:
+                case UINT8:
+                    size = 1;
+                    break;
+                case INT64:
+                case UINT64:
+                case FLOAT64:
+                    size = 8;
+                    break;
+                default:
+                    /* unknown type */
+                    return 0;
             }
 
             for (int i = 0; i < NNStreamer.TENSOR_RANK_LIMIT; i++) {
@@ -368,5 +334,50 @@ public final class TensorsInfo implements AutoCloseable, Cloneable {
 
             return size;
         }
+
+        /**
+         * Gets the tensor type from int value.
+         */
+        public static NNStreamer.TensorType convertType(int value) {
+            NNStreamer.TensorType type = NNStreamer.TensorType.UNKNOWN;
+
+            switch (value) {
+                case 0:
+                    type = NNStreamer.TensorType.INT32;
+                    break;
+                case 1:
+                    type = NNStreamer.TensorType.UINT32;
+                    break;
+                case 2:
+                    type = NNStreamer.TensorType.INT16;
+                    break;
+                case 3:
+                    type = NNStreamer.TensorType.UINT16;
+                    break;
+                case 4:
+                    type = NNStreamer.TensorType.INT8;
+                    break;
+                case 5:
+                    type = NNStreamer.TensorType.UINT8;
+                    break;
+                case 6:
+                    type = NNStreamer.TensorType.FLOAT64;
+                    break;
+                case 7:
+                    type = NNStreamer.TensorType.FLOAT32;
+                    break;
+                case 8:
+                    type = NNStreamer.TensorType.INT64;
+                    break;
+                case 9:
+                    type = NNStreamer.TensorType.UINT64;
+                    break;
+                default:
+                    /* unknown type */
+                    break;
+            }
+
+            return type;
+        }
     }
 }
index 4728377..2a9135d 100644 (file)
@@ -142,6 +142,80 @@ nns_free_element_data (gpointer data)
 }
 
 /**
+ * @brief Construct TensorsData class info.
+ */
+static void
+nns_construct_tdata_class_info (JNIEnv * env, data_class_info_s * info)
+{
+  jclass cls;
+
+  cls = (*env)->FindClass (env, NNS_CLS_TDATA);
+  info->cls = (*env)->NewGlobalRef (env, cls);
+  (*env)->DeleteLocalRef (env, cls);
+
+  info->mid_init = (*env)->GetMethodID (env, info->cls, "<init>", "()V");
+  info->mid_add_data = (*env)->GetMethodID (env, info->cls, "addTensorData",
+      "([B)V");
+  info->mid_get_array = (*env)->GetMethodID (env, info->cls, "getDataArray",
+      "()[Ljava/lang/Object;");
+  info->mid_set_info = (*env)->GetMethodID (env, info->cls, "setTensorsInfo",
+      "(L" NNS_CLS_TINFO ";)V");
+  info->mid_get_info = (*env)->GetMethodID (env, info->cls, "getTensorsInfo",
+      "()L" NNS_CLS_TINFO ";");
+}
+
+/**
+ * @brief Destroy TensorsData class info.
+ */
+static void
+nns_destroy_tdata_class_info (JNIEnv * env, data_class_info_s * info)
+{
+  if (info->cls)
+    (*env)->DeleteGlobalRef (env, info->cls);
+}
+
+/**
+ * @brief Construct TensorsInfo class info.
+ */
+static void
+nns_construct_tinfo_class_info (JNIEnv * env, info_class_info_s * info)
+{
+  jclass cls;
+
+  cls = (*env)->FindClass (env, NNS_CLS_TINFO);
+  info->cls = (*env)->NewGlobalRef (env, cls);
+  (*env)->DeleteLocalRef (env, cls);
+
+  cls = (*env)->FindClass (env, NNS_CLS_TINFO "$TensorInfo");
+  info->cls_info = (*env)->NewGlobalRef (env, cls);
+  (*env)->DeleteLocalRef (env, cls);
+
+  info->mid_init = (*env)->GetMethodID (env, info->cls, "<init>", "()V");
+  info->mid_add_info = (*env)->GetMethodID (env, info->cls, "appendInfo",
+      "(Ljava/lang/String;I[I)V");
+  info->mid_get_array = (*env)->GetMethodID (env, info->cls, "getInfoArray",
+      "()[Ljava/lang/Object;");
+
+  info->fid_info_name = (*env)->GetFieldID (env, info->cls_info, "name",
+      "Ljava/lang/String;");
+  info->fid_info_type = (*env)->GetFieldID (env, info->cls_info, "type", "I");
+  info->fid_info_dim = (*env)->GetFieldID (env, info->cls_info, "dimension",
+      "[I");
+}
+
+/**
+ * @brief Destroy TensorsInfo class info.
+ */
+static void
+nns_destroy_tinfo_class_info (JNIEnv * env, info_class_info_s * info)
+{
+  if (info->cls_info)
+    (*env)->DeleteGlobalRef (env, info->cls_info);
+  if (info->cls)
+    (*env)->DeleteGlobalRef (env, info->cls);
+}
+
+/**
  * @brief Construct pipeline info.
  */
 gpointer
@@ -149,7 +223,7 @@ nns_construct_pipe_info (JNIEnv * env, jobject thiz, gpointer handle,
     nns_pipe_type_e type)
 {
   pipeline_info_s *pipe_info;
-  jclass cls_data, cls_info;
+  jclass cls;
 
   pipe_info = g_new0 (pipeline_info_s, 1);
   g_return_val_if_fail (pipe_info != NULL, NULL);
@@ -168,13 +242,12 @@ nns_construct_pipe_info (JNIEnv * env, jobject thiz, gpointer handle,
   pipe_info->version = (*env)->GetVersion (env);
   pipe_info->instance = (*env)->NewGlobalRef (env, thiz);
 
-  cls_data = (*env)->FindClass (env, "org/nnsuite/nnstreamer/TensorsData");
-  pipe_info->cls_tensors_data = (*env)->NewGlobalRef (env, cls_data);
-  (*env)->DeleteLocalRef (env, cls_data);
+  cls = (*env)->GetObjectClass (env, pipe_info->instance);
+  pipe_info->cls = (*env)->NewGlobalRef (env, cls);
+  (*env)->DeleteLocalRef (env, cls);
 
-  cls_info = (*env)->FindClass (env, "org/nnsuite/nnstreamer/TensorsInfo");
-  pipe_info->cls_tensors_info = (*env)->NewGlobalRef (env, cls_info);
-  (*env)->DeleteLocalRef (env, cls_info);
+  nns_construct_tdata_class_info (env, &pipe_info->data_cls_info);
+  nns_construct_tinfo_class_info (env, &pipe_info->info_cls_info);
 
   return pipe_info;
 }
@@ -188,6 +261,13 @@ nns_destroy_pipe_info (pipeline_info_s * pipe_info, JNIEnv * env)
   g_return_if_fail (pipe_info != NULL);
 
   g_mutex_lock (&pipe_info->lock);
+  if (pipe_info->priv_data) {
+    if (pipe_info->priv_destroy_func)
+      pipe_info->priv_destroy_func (pipe_info->priv_data, env);
+    else
+      g_free (pipe_info->priv_data);
+  }
+
   g_hash_table_destroy (pipe_info->element_handles);
   pipe_info->element_handles = NULL;
   g_mutex_unlock (&pipe_info->lock);
@@ -216,14 +296,30 @@ nns_destroy_pipe_info (pipeline_info_s * pipe_info, JNIEnv * env)
 
   g_mutex_clear (&pipe_info->lock);
 
+  nns_destroy_tdata_class_info (env, &pipe_info->data_cls_info);
+  nns_destroy_tinfo_class_info (env, &pipe_info->info_cls_info);
+  (*env)->DeleteGlobalRef (env, pipe_info->cls);
   (*env)->DeleteGlobalRef (env, pipe_info->instance);
-  (*env)->DeleteGlobalRef (env, pipe_info->cls_tensors_data);
-  (*env)->DeleteGlobalRef (env, pipe_info->cls_tensors_info);
 
   g_free (pipe_info);
 }
 
 /**
+ * @brief Set private data in pipeline info. If destroy_func is NULL, priv_data will be released using g_free().
+ */
+void
+nns_set_priv_data (pipeline_info_s * pipe_info, gpointer data,
+    nns_priv_destroy destroy_func)
+{
+  g_return_if_fail (pipe_info != NULL);
+
+  g_mutex_lock (&pipe_info->lock);
+  pipe_info->priv_data = data;
+  pipe_info->priv_destroy_func = destroy_func;
+  g_mutex_unlock (&pipe_info->lock);
+}
+
+/**
  * @brief Get element handle of given name.
  */
 gpointer
@@ -286,7 +382,7 @@ nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
     ml_tensors_data_h data_h, ml_tensors_info_h info_h, jobject * result)
 {
   guint i;
-  jmethodID mid_init, mid_add_data, mid_set_info;
+  data_class_info_s *dcls_info;
   jobject obj_data = NULL;
   ml_tensors_data_s *data;
 
@@ -295,19 +391,10 @@ nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
   g_return_val_if_fail (data_h, FALSE);
   g_return_val_if_fail (result, FALSE);
 
+  dcls_info = &pipe_info->data_cls_info;
   data = (ml_tensors_data_s *) data_h;
 
-  /* method to generate tensors data */
-  mid_init =
-      (*env)->GetMethodID (env, pipe_info->cls_tensors_data, "<init>", "()V");
-  mid_add_data =
-      (*env)->GetMethodID (env, pipe_info->cls_tensors_data, "addTensorData",
-      "([B)V");
-  mid_set_info =
-      (*env)->GetMethodID (env, pipe_info->cls_tensors_data, "setTensorsInfo",
-      "(Lorg/nnsuite/nnstreamer/TensorsInfo;)V");
-
-  obj_data = (*env)->NewObject (env, pipe_info->cls_tensors_data, mid_init);
+  obj_data = (*env)->NewObject (env, dcls_info->cls, dcls_info->mid_init);
   if (!obj_data) {
     nns_loge ("Failed to allocate object for tensors data.");
     goto done;
@@ -323,7 +410,7 @@ nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
       goto done;
     }
 
-    (*env)->CallVoidMethod (env, obj_data, mid_set_info, obj_info);
+    (*env)->CallVoidMethod (env, obj_data, dcls_info->mid_set_info, obj_info);
     (*env)->DeleteLocalRef (env, obj_info);
   }
 
@@ -334,7 +421,7 @@ nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
     (*env)->SetByteArrayRegion (env, buffer, 0, buffer_size,
         (jbyte *) data->tensors[i].tensor);
 
-    (*env)->CallVoidMethod (env, obj_data, mid_add_data, buffer);
+    (*env)->CallVoidMethod (env, obj_data, dcls_info->mid_add_data, buffer);
     (*env)->DeleteLocalRef (env, buffer);
   }
 
@@ -351,8 +438,9 @@ nns_parse_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
     jobject obj_data, ml_tensors_data_h * data_h, ml_tensors_info_h * info_h)
 {
   guint i;
+  data_class_info_s *dcls_info;
   ml_tensors_data_s *data;
-  ml_tensors_info_s *info;
+  jobjectArray data_arr;
   gboolean failed = FALSE;
 
   g_return_val_if_fail (pipe_info, FALSE);
@@ -365,39 +453,26 @@ nns_parse_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
     return FALSE;
   }
 
+  dcls_info = &pipe_info->data_cls_info;
   data = (ml_tensors_data_s *) (*data_h);
 
-  /* get field 'mDataList' */
-  jfieldID fid_arraylist =
-      (*env)->GetFieldID (env, pipe_info->cls_tensors_data, "mDataList",
-      "Ljava/util/ArrayList;");
-  jobject obj_arraylist = (*env)->GetObjectField (env, obj_data, fid_arraylist);
-
-  /* method to get tensors data */
-  jclass cls_arraylist = (*env)->GetObjectClass (env, obj_arraylist);
-  jmethodID mid_size = (*env)->GetMethodID (env, cls_arraylist, "size", "()I");
-  jmethodID mid_get =
-      (*env)->GetMethodID (env, cls_arraylist, "get", "(I)Ljava/lang/Object;");
+  data_arr = (*env)->CallObjectMethod (env, obj_data, dcls_info->mid_get_array);
 
   /* number of tensors data */
-  data->num_tensors =
-      (unsigned int) (*env)->CallIntMethod (env, obj_arraylist, mid_size);
+  data->num_tensors = (unsigned int) (*env)->GetArrayLength (env, data_arr);
 
   /* set tensor data */
   for (i = 0; i < data->num_tensors; i++) {
-    jobject tensor_data =
-        (*env)->CallObjectMethod (env, obj_arraylist, mid_get, i);
+    jobject tensor = (*env)->GetObjectArrayElement (env, data_arr, i);
 
-    if (tensor_data) {
-      size_t data_size =
-          (size_t) (*env)->GetDirectBufferCapacity (env, tensor_data);
-      gpointer data_ptr = (*env)->GetDirectBufferAddress (env, tensor_data);
+    if (tensor) {
+      gsize data_size = (gsize) (*env)->GetDirectBufferCapacity (env, tensor);
+      gpointer data_ptr = (*env)->GetDirectBufferAddress (env, tensor);
 
       data->tensors[i].tensor = g_malloc (data_size);
       if (data->tensors[i].tensor == NULL) {
-        nns_loge ("Failed to allocate memory %zd, data index %d.", data_size,
-            i);
-        (*env)->DeleteLocalRef (env, tensor_data);
+        nns_loge ("Failed to allocate memory %zd, index %d.", data_size, i);
+        (*env)->DeleteLocalRef (env, tensor);
         failed = TRUE;
         goto done;
       }
@@ -405,16 +480,14 @@ nns_parse_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
       memcpy (data->tensors[i].tensor, data_ptr, data_size);
       data->tensors[i].size = data_size;
 
-      (*env)->DeleteLocalRef (env, tensor_data);
+      (*env)->DeleteLocalRef (env, tensor);
     }
   }
 
   /* parse tensors info in data class */
   if (info_h) {
-    jmethodID mid_get_info =
-        (*env)->GetMethodID (env, pipe_info->cls_tensors_data,
-        "getTensorsInfo", "()Lorg/nnsuite/nnstreamer/TensorsInfo;");
-    jobject obj_info = (*env)->CallObjectMethod (env, obj_data, mid_get_info);
+    jobject obj_info =
+        (*env)->CallObjectMethod (env, obj_data, dcls_info->mid_get_info);
 
     if (obj_info) {
       nns_parse_tensors_info (pipe_info, env, obj_info, info_h);
@@ -423,8 +496,7 @@ nns_parse_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
   }
 
 done:
-  (*env)->DeleteLocalRef (env, cls_arraylist);
-  (*env)->DeleteLocalRef (env, obj_arraylist);
+  (*env)->DeleteLocalRef (env, data_arr);
 
   if (failed) {
     ml_tensors_data_destroy (*data_h);
@@ -441,9 +513,9 @@ gboolean
 nns_convert_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
     ml_tensors_info_h info_h, jobject * result)
 {
-  guint i, j;
+  guint i;
+  info_class_info_s *icls_info;
   ml_tensors_info_s *info;
-  jmethodID mid_init, mid_add;
   jobject obj_info = NULL;
 
   g_return_val_if_fail (pipe_info, FALSE);
@@ -451,16 +523,10 @@ nns_convert_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
   g_return_val_if_fail (info_h, FALSE);
   g_return_val_if_fail (result, FALSE);
 
+  icls_info = &pipe_info->info_cls_info;
   info = (ml_tensors_info_s *) info_h;
 
-  /* method to generate tensors info */
-  mid_init =
-      (*env)->GetMethodID (env, pipe_info->cls_tensors_info, "<init>", "()V");
-  mid_add =
-      (*env)->GetMethodID (env, pipe_info->cls_tensors_info, "appendInfo",
-      "(Ljava/lang/String;I[I)V");
-
-  obj_info = (*env)->NewObject (env, pipe_info->cls_tensors_info, mid_init);
+  obj_info = (*env)->NewObject (env, icls_info->cls, icls_info->mid_init);
   if (!obj_info) {
     nns_loge ("Failed to allocate object for tensors info.");
     goto done;
@@ -470,7 +536,6 @@ nns_convert_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
     jstring name = NULL;
     jint type;
     jintArray dimension;
-    jint *dim;
 
     if (info->info[i].name)
       name = (*env)->NewStringUTF (env, info->info[i].name);
@@ -478,14 +543,11 @@ nns_convert_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
     type = (jint) info->info[i].type;
 
     dimension = (*env)->NewIntArray (env, ML_TENSOR_RANK_LIMIT);
+    (*env)->SetIntArrayRegion (env, dimension, 0, ML_TENSOR_RANK_LIMIT,
+        (jint *) info->info[i].dimension);
 
-    dim = (*env)->GetIntArrayElements (env, dimension, NULL);
-    for (j = 0; j < ML_TENSOR_RANK_LIMIT; j++) {
-      dim[j] = (jint) info->info[i].dimension[j];
-    }
-    (*env)->ReleaseIntArrayElements (env, dimension, dim, 0);
-
-    (*env)->CallVoidMethod (env, obj_info, mid_add, name, type, dimension);
+    (*env)->CallVoidMethod (env, obj_info, icls_info->mid_add_info,
+        name, type, dimension);
 
     if (name)
       (*env)->DeleteLocalRef (env, name);
@@ -504,8 +566,10 @@ gboolean
 nns_parse_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
     jobject obj_info, ml_tensors_info_h * info_h)
 {
-  guint i, j;
+  guint i;
+  info_class_info_s *icls_info;
   ml_tensors_info_s *info;
+  jobjectArray info_arr;
 
   g_return_val_if_fail (pipe_info, FALSE);
   g_return_val_if_fail (env, FALSE);
@@ -517,38 +581,21 @@ nns_parse_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
     return FALSE;
   }
 
+  icls_info = &pipe_info->info_cls_info;
   info = (ml_tensors_info_s *) (*info_h);
 
-  /* get field 'mInfoList' */
-  jfieldID fid_arraylist =
-      (*env)->GetFieldID (env, pipe_info->cls_tensors_info, "mInfoList",
-      "Ljava/util/ArrayList;");
-  jobject obj_arraylist = (*env)->GetObjectField (env, obj_info, fid_arraylist);
-
-  /* method to get tensors info */
-  jclass cls_arraylist = (*env)->GetObjectClass (env, obj_arraylist);
-  jmethodID mid_size = (*env)->GetMethodID (env, cls_arraylist, "size", "()I");
-  jmethodID mid_get =
-      (*env)->GetMethodID (env, cls_arraylist, "get", "(I)Ljava/lang/Object;");
+  info_arr = (*env)->CallObjectMethod (env, obj_info, icls_info->mid_get_array);
 
   /* number of tensors info */
-  info->num_tensors =
-      (unsigned int) (*env)->CallIntMethod (env, obj_arraylist, mid_size);
+  info->num_tensors = (unsigned int) (*env)->GetArrayLength (env, info_arr);
 
   /* read tensor info */
   for (i = 0; i < info->num_tensors; i++) {
-    jobject item = (*env)->CallObjectMethod (env, obj_arraylist, mid_get, i);
-    jclass cls_info = (*env)->GetObjectClass (env, item);
-
-    jmethodID mid_name =
-        (*env)->GetMethodID (env, cls_info, "getName", "()Ljava/lang/String;");
-    jmethodID mid_type =
-        (*env)->GetMethodID (env, cls_info, "getTypeValue", "()I");
-    jmethodID mid_dimension =
-        (*env)->GetMethodID (env, cls_info, "getDimension", "()[I");
+    jobject item = (*env)->GetObjectArrayElement (env, info_arr, i);
 
     /* tensor name */
-    jstring name_str = (jstring) (*env)->CallObjectMethod (env, item, mid_name);
+    jstring name_str = (jstring) (*env)->GetObjectField (env, item,
+        icls_info->fid_info_name);
     if (name_str) {
       const gchar *name = (*env)->GetStringUTFChars (env, name_str, NULL);
 
@@ -558,29 +605,20 @@ nns_parse_tensors_info (pipeline_info_s * pipe_info, JNIEnv * env,
     }
 
     /* tensor type */
-    info->info[i].type =
-        (ml_tensor_type_e) (*env)->CallIntMethod (env, item, mid_type);
+    info->info[i].type = (ml_tensor_type_e) (*env)->GetIntField (env, item,
+        icls_info->fid_info_type);
 
     /* tensor dimension */
-    jintArray dim =
-        (jintArray) (*env)->CallObjectMethod (env, item, mid_dimension);
-    jsize length = (*env)->GetArrayLength (env, dim);
-    jint *dimension = (*env)->GetIntArrayElements (env, dim, NULL);
-
-    g_assert (length == ML_TENSOR_RANK_LIMIT);
-    for (j = 0; j < length; j++) {
-      info->info[i].dimension[j] = (unsigned int) dimension[j];
-    }
-
-    (*env)->ReleaseIntArrayElements (env, dim, dimension, 0);
-    (*env)->DeleteLocalRef (env, dim);
+    jintArray dimension = (jintArray) (*env)->GetObjectField (env, item,
+        icls_info->fid_info_dim);
+    (*env)->GetIntArrayRegion (env, dimension, 0, ML_TENSOR_RANK_LIMIT,
+        (jint *) info->info[i].dimension);
+    (*env)->DeleteLocalRef (env, dimension);
 
-    (*env)->DeleteLocalRef (env, cls_info);
     (*env)->DeleteLocalRef (env, item);
   }
 
-  (*env)->DeleteLocalRef (env, cls_arraylist);
-  (*env)->DeleteLocalRef (env, obj_arraylist);
+  (*env)->DeleteLocalRef (env, info_arr);
   return TRUE;
 }
 
index 4561635..655a096 100644 (file)
 #include "nnstreamer-native.h"
 
 /**
+ * @brief Private data for CustomFilter class.
+ */
+typedef struct
+{
+  jmethodID mid_invoke;
+  jmethodID mid_info;
+} customfilter_priv_data_s;
+
+/**
  * @brief Table to handle custom-filter.
  */
 static GHashTable *g_customfilters = NULL;
 
 /**
+ * @brief Release private data in custom filter.
+ */
+static void
+nns_customfilter_priv_free (gpointer data, JNIEnv * env)
+{
+  customfilter_priv_data_s *priv = (customfilter_priv_data_s *) data;
+
+  /* nothing to free */
+  g_free (priv);
+}
+
+/**
  * @brief The mandatory callback for GstTensorFilterFramework.
  * @param prop The property of tensor_filter instance
  * @param private_data Sub-plugin's private data
@@ -42,12 +63,11 @@ nns_customfilter_invoke (const GstTensorFilterProperties * prop,
     GstTensorMemory * output)
 {
   pipeline_info_s *pipe_info = NULL;
+  customfilter_priv_data_s *priv;
   ml_tensors_data_h in_data, out_data;
   ml_tensors_info_h in_info;
   ml_tensors_data_s *_data;
   JNIEnv *env;
-  jclass cls_custom;
-  jmethodID mid_invoke;
   jobject obj_in_data, obj_out_data;
   guint i;
   int ret = -1;
@@ -62,6 +82,7 @@ nns_customfilter_invoke (const GstTensorFilterProperties * prop,
   in_data = out_data = NULL;
   in_info = NULL;
   obj_in_data = obj_out_data = NULL;
+  priv = (customfilter_priv_data_s *) pipe_info->priv_data;
 
   if (ml_tensors_data_create_no_alloc (NULL, &in_data) != ML_ERROR_NONE) {
     nns_loge ("Failed to create handle for input tensors data.");
@@ -73,11 +94,6 @@ nns_customfilter_invoke (const GstTensorFilterProperties * prop,
     goto done;
   }
 
-  cls_custom = (*env)->GetObjectClass (env, pipe_info->instance);
-  mid_invoke = (*env)->GetMethodID (env, cls_custom, "invoke",
-      "(Lorg/nnsuite/nnstreamer/TensorsData;)"
-      "Lorg/nnsuite/nnstreamer/TensorsData;");
-
   /* convert to c-api data type */
   _data = (ml_tensors_data_s *) in_data;
   _data->num_tensors = prop->input_meta.num_tensors;
@@ -88,16 +104,22 @@ nns_customfilter_invoke (const GstTensorFilterProperties * prop,
 
   ml_tensors_info_copy_from_gst (in_info, &prop->input_meta);
 
-  /* call invoke callback */
+  /* convert to data object */
   if (!nns_convert_tensors_data (pipe_info, env, in_data, in_info,
           &obj_in_data)) {
     nns_loge ("Failed to convert input data to data-object.");
     goto done;
   }
 
-  obj_out_data =
-      (*env)->CallObjectMethod (env, pipe_info->instance, mid_invoke,
-      obj_in_data);
+  /* call invoke callback */
+  obj_out_data = (*env)->CallObjectMethod (env, pipe_info->instance,
+      priv->mid_invoke, obj_in_data);
+
+  if ((*env)->ExceptionCheck (env)) {
+    nns_loge ("Failed to call the custom-invoke callback.");
+    (*env)->ExceptionClear (env);
+    goto done;
+  }
 
   if (!nns_parse_tensors_data (pipe_info, env, obj_out_data, &out_data, NULL)) {
     nns_loge ("Failed to parse output data.");
@@ -124,7 +146,6 @@ done:
     (*env)->DeleteLocalRef (env, obj_in_data);
   if (obj_out_data)
     (*env)->DeleteLocalRef (env, obj_out_data);
-  (*env)->DeleteLocalRef (env, cls_custom);
 
   g_free (in_data);
   g_free (out_data);
@@ -146,11 +167,10 @@ nns_customfilter_set_dimension (const GstTensorFilterProperties * prop,
     GstTensorsInfo * out_info)
 {
   pipeline_info_s *pipe_info = NULL;
+  customfilter_priv_data_s *priv;
   ml_tensors_info_h in, out;
   jobject obj_in_info, obj_out_info;
   JNIEnv *env;
-  jclass cls_custom;
-  jmethodID mid_info;
   int ret = -1;
 
   /* get pipe info and init */
@@ -162,29 +182,30 @@ nns_customfilter_set_dimension (const GstTensorFilterProperties * prop,
 
   in = out = NULL;
   obj_in_info = obj_out_info = NULL;
+  priv = (customfilter_priv_data_s *) pipe_info->priv_data;
 
   if (ml_tensors_info_create (&in) != ML_ERROR_NONE) {
     nns_loge ("Failed to create handle for input tensors info.");
     goto done;
   }
 
-  cls_custom = (*env)->GetObjectClass (env, pipe_info->instance);
-  mid_info = (*env)->GetMethodID (env, cls_custom, "getOutputInfo",
-      "(Lorg/nnsuite/nnstreamer/TensorsInfo;)"
-      "Lorg/nnsuite/nnstreamer/TensorsInfo;");
-
   /* convert to c-api data type */
   ml_tensors_info_copy_from_gst (in, in_info);
 
-  /* call output info callback */
   if (!nns_convert_tensors_info (pipe_info, env, in, &obj_in_info)) {
     nns_loge ("Failed to convert input tensors info to data object.");
     goto done;
   }
 
-  obj_out_info =
-      (*env)->CallObjectMethod (env, pipe_info->instance, mid_info,
-      obj_in_info);
+  /* call output info callback */
+  obj_out_info = (*env)->CallObjectMethod (env, pipe_info->instance,
+      priv->mid_info, obj_in_info);
+
+  if ((*env)->ExceptionCheck (env)) {
+    nns_loge ("Failed to call the custom-info callback.");
+    (*env)->ExceptionClear (env);
+    goto done;
+  }
 
   if (!nns_parse_tensors_info (pipe_info, env, obj_out_info, &out)) {
     nns_loge ("Failed to parse output info.");
@@ -202,7 +223,6 @@ done:
     (*env)->DeleteLocalRef (env, obj_in_info);
   if (obj_out_info)
     (*env)->DeleteLocalRef (env, obj_out_info);
-  (*env)->DeleteLocalRef (env, cls_custom);
 
   ml_tensors_info_destroy (in);
   ml_tensors_info_destroy (out);
@@ -217,6 +237,7 @@ Java_org_nnsuite_nnstreamer_CustomFilter_nativeInitialize (JNIEnv * env,
     jobject thiz, jstring name)
 {
   pipeline_info_s *pipe_info = NULL;
+  customfilter_priv_data_s *priv;
   GstTensorFilterFramework *fw = NULL;
   const char *filter_name = (*env)->GetStringUTFChars (env, name, NULL);
 
@@ -271,6 +292,14 @@ Java_org_nnsuite_nnstreamer_CustomFilter_nativeInitialize (JNIEnv * env,
 
   g_mutex_unlock (&pipe_info->lock);
 
+  priv = g_new0 (customfilter_priv_data_s, 1);
+  priv->mid_invoke = (*env)->GetMethodID (env, pipe_info->cls, "invoke",
+      "(L" NNS_CLS_TDATA ";)L" NNS_CLS_TDATA ";");
+  priv->mid_info = (*env)->GetMethodID (env, pipe_info->cls, "getOutputInfo",
+      "(L" NNS_CLS_TINFO ";)L" NNS_CLS_TINFO ";");
+
+  nns_set_priv_data (pipe_info, priv, nns_customfilter_priv_free);
+
 done:
   (*env)->ReleaseStringUTFChars (env, name, filter_name);
   return CAST_TO_LONG (pipe_info);
index eada3d3..8f03d4d 100644 (file)
 #include "nnstreamer-native.h"
 
 /**
+ * @brief Private data for Pipeline class.
+ */
+typedef struct
+{
+  jmethodID mid_state_cb;
+  jmethodID mid_sink_cb;
+} pipeline_priv_data_s;
+
+/**
+ * @brief Release private data in pipeline info.
+ */
+static void
+nns_pipeline_priv_free (gpointer data, JNIEnv * env)
+{
+  pipeline_priv_data_s *priv = (pipeline_priv_data_s *) data;
+
+  /* nothing to free */
+  g_free (priv);
+}
+
+/**
  * @brief Pipeline state change callback.
  */
 static void
 nns_pipeline_state_cb (ml_pipeline_state_e state, void *user_data)
 {
   pipeline_info_s *pipe_info;
+  pipeline_priv_data_s *priv;
+  jint new_state = (jint) state;
+  JNIEnv *env;
 
   pipe_info = (pipeline_info_s *) user_data;
+  priv = (pipeline_priv_data_s *) pipe_info->priv_data;
 
-  JNIEnv *env = nns_get_jni_env (pipe_info);
-  if (env == NULL) {
+  if ((env = nns_get_jni_env (pipe_info)) == NULL) {
     nns_logw ("Cannot get jni env in the state callback.");
     return;
   }
 
-  jclass cls_pipeline = (*env)->GetObjectClass (env, pipe_info->instance);
-  jmethodID mid_callback =
-      (*env)->GetMethodID (env, cls_pipeline, "stateChanged", "(I)V");
-  jint new_state = (jint) state;
-
-  (*env)->CallVoidMethod (env, pipe_info->instance, mid_callback, new_state);
+  (*env)->CallVoidMethod (env, pipe_info->instance, priv->mid_state_cb,
+      new_state);
 
   if ((*env)->ExceptionCheck (env)) {
     nns_loge ("Failed to call the callback method.");
     (*env)->ExceptionClear (env);
   }
-
-  (*env)->DeleteLocalRef (env, cls_pipeline);
 }
 
 /**
@@ -63,11 +81,13 @@ nns_sink_data_cb (const ml_tensors_data_h data, const ml_tensors_info_h info,
 {
   element_data_s *cb_data;
   pipeline_info_s *pipe_info;
+  pipeline_priv_data_s *priv;
   jobject obj_data = NULL;
   JNIEnv *env;
 
   cb_data = (element_data_s *) user_data;
   pipe_info = cb_data->pipe_info;
+  priv = (pipeline_priv_data_s *) pipe_info->priv_data;
 
   if ((env = nns_get_jni_env (pipe_info)) == NULL) {
     nns_logw ("Cannot get jni env in the sink callback.");
@@ -75,15 +95,10 @@ nns_sink_data_cb (const ml_tensors_data_h data, const ml_tensors_info_h info,
   }
 
   if (nns_convert_tensors_data (pipe_info, env, data, info, &obj_data)) {
-    /* method for sink callback */
-    jclass cls_pipeline = (*env)->GetObjectClass (env, pipe_info->instance);
-    jmethodID mid_callback =
-        (*env)->GetMethodID (env, cls_pipeline, "newDataReceived",
-        "(Ljava/lang/String;Lorg/nnsuite/nnstreamer/TensorsData;)V");
     jstring sink_name = (*env)->NewStringUTF (env, cb_data->name);
 
-    (*env)->CallVoidMethod (env, pipe_info->instance, mid_callback, sink_name,
-        obj_data);
+    (*env)->CallVoidMethod (env, pipe_info->instance, priv->mid_sink_cb,
+        sink_name, obj_data);
 
     if ((*env)->ExceptionCheck (env)) {
       nns_loge ("Failed to call the callback method.");
@@ -91,7 +106,6 @@ nns_sink_data_cb (const ml_tensors_data_h data, const ml_tensors_info_h info,
     }
 
     (*env)->DeleteLocalRef (env, sink_name);
-    (*env)->DeleteLocalRef (env, cls_pipeline);
     (*env)->DeleteLocalRef (env, obj_data);
   } else {
     nns_loge ("Failed to convert the result to data object.");
@@ -121,9 +135,8 @@ nns_get_sink_handle (pipeline_info_s * pipe_info, const gchar * element_name)
       return NULL;
     }
 
-    status =
-        ml_pipeline_sink_register (pipe, element_name, nns_sink_data_cb, item,
-        &handle);
+    status = ml_pipeline_sink_register (pipe, element_name, nns_sink_data_cb,
+        item, &handle);
     if (status != ML_ERROR_NONE) {
       nns_loge ("Failed to get sink node %s.", element_name);
       g_free (item);
@@ -207,8 +220,7 @@ nns_get_switch_handle (pipeline_info_s * pipe_info, const gchar * element_name)
       (ml_pipeline_switch_h) nns_get_element_handle (pipe_info, element_name);
   if (handle == NULL) {
     /* get switch handle and register to table */
-    status =
-        ml_pipeline_switch_get_handle (pipe, element_name, &switch_type,
+    status = ml_pipeline_switch_get_handle (pipe, element_name, &switch_type,
         &handle);
     if (status != ML_ERROR_NONE) {
       nns_loge ("Failed to get switch %s.", element_name);
@@ -293,6 +305,7 @@ Java_org_nnsuite_nnstreamer_Pipeline_nativeConstruct (JNIEnv * env,
     jobject thiz, jstring description, jboolean add_state_cb)
 {
   pipeline_info_s *pipe_info = NULL;
+  pipeline_priv_data_s *priv;
   ml_pipeline_h pipe;
   int status;
   const char *pipeline = (*env)->GetStringUTFChars (env, description, NULL);
@@ -303,9 +316,17 @@ Java_org_nnsuite_nnstreamer_Pipeline_nativeConstruct (JNIEnv * env,
     goto done;
   }
 
+  priv = g_new0 (pipeline_priv_data_s, 1);
+  priv->mid_state_cb =
+      (*env)->GetMethodID (env, pipe_info->cls, "stateChanged", "(I)V");
+  priv->mid_sink_cb =
+      (*env)->GetMethodID (env, pipe_info->cls, "newDataReceived",
+      "(Ljava/lang/String;L" NNS_CLS_TDATA ";)V");
+
+  nns_set_priv_data (pipe_info, priv, nns_pipeline_priv_free);
+
   if (add_state_cb)
-    status =
-        ml_pipeline_construct (pipeline, nns_pipeline_state_cb, pipe_info,
+    status = ml_pipeline_construct (pipeline, nns_pipeline_state_cb, pipe_info,
         &pipe);
   else
     status = ml_pipeline_construct (pipeline, NULL, NULL, &pipe);
@@ -459,7 +480,7 @@ Java_org_nnsuite_nnstreamer_Pipeline_nativeGetSwitchPads (JNIEnv * env,
   int status;
   const char *element_name = (*env)->GetStringUTFChars (env, name, NULL);
   char **pad_list = NULL;
-  guint i, total = 0;
+  guint i, total;
   jobjectArray result = NULL;
 
   pipe_info = CAST_TO_TYPE (handle, pipeline_info_s *);
@@ -475,16 +496,13 @@ Java_org_nnsuite_nnstreamer_Pipeline_nativeGetSwitchPads (JNIEnv * env,
     goto done;
   }
 
+  total = g_strv_length (pad_list);
+
   /* set string array */
-  if (pad_list) {
+  if (total > 0) {
     jclass cls_string = (*env)->FindClass (env, "java/lang/String");
 
-    while (pad_list[total] != NULL)
-      total++;
-
-    result =
-        (*env)->NewObjectArray (env, total, cls_string,
-        (*env)->NewStringUTF (env, ""));
+    result = (*env)->NewObjectArray (env, total, cls_string, NULL);
     if (result == NULL) {
       nns_loge ("Failed to allocate string array.");
       (*env)->DeleteLocalRef (env, cls_string);
@@ -492,27 +510,17 @@ Java_org_nnsuite_nnstreamer_Pipeline_nativeGetSwitchPads (JNIEnv * env,
     }
 
     for (i = 0; i < total; i++) {
-      (*env)->SetObjectArrayElement (env, result, i, (*env)->NewStringUTF (env,
-              pad_list[i]));
-      g_free (pad_list[i]);
-    }
+      jstring pad = (*env)->NewStringUTF (env, pad_list[i]);
 
-    g_free (pad_list);
-    pad_list = NULL;
+      (*env)->SetObjectArrayElement (env, result, i, pad);
+      (*env)->DeleteLocalRef (env, pad);
+    }
 
     (*env)->DeleteLocalRef (env, cls_string);
   }
 
 done:
-  /* free pad list */
-  if (pad_list) {
-    i = 0;
-    while (pad_list[i] != NULL) {
-      g_free (pad_list[i]);
-    }
-    g_free (pad_list);
-  }
-
+  g_strfreev (pad_list);
   (*env)->ReleaseStringUTFChars (env, name, element_name);
   return result;
 }
index 9a9f894..e898a0c 100644 (file)
@@ -73,16 +73,16 @@ Java_org_nnsuite_nnstreamer_SingleShot_nativeOpen (JNIEnv * env, jobject thiz,
     models_count = (*env)->GetArrayLength (env, models);
 
     for (i = 0; i < models_count; i++) {
-      jstring model_obj =
-          (jstring) (*env)->GetObjectArrayElement (env, models, i);
-      const char *model_path = (*env)->GetStringUTFChars (env, model_obj, NULL);
+      jstring model = (jstring) (*env)->GetObjectArrayElement (env, models, i);
+      const char *model_path = (*env)->GetStringUTFChars (env, model, NULL);
 
       g_string_append (model_str, model_path);
       if (i < models_count - 1) {
         g_string_append (model_str, ",");
       }
 
-      (*env)->ReleaseStringUTFChars (env, model_obj, model_path);
+      (*env)->ReleaseStringUTFChars (env, model, model_path);
+      (*env)->DeleteLocalRef (env, model);
     }
 
     info.models = g_string_free (model_str, FALSE);
index 7c03775..8bf70da 100644 (file)
 #endif
 
 /**
+ * @brief NNStreamer package name.
+ */
+#define NNS_PKG "org/nnsuite/nnstreamer"
+#define NNS_CLS_TDATA NNS_PKG "/TensorsData"
+#define NNS_CLS_TINFO NNS_PKG "/TensorsInfo"
+
+/**
+ * @brief Callback to destroy private data in pipe info.
+ */
+typedef void (*nns_priv_destroy)(gpointer data, JNIEnv * env);
+
+/**
  * @brief Pipeline type in native pipe info.
  */
 typedef enum
@@ -70,6 +82,35 @@ typedef enum
 } nns_element_type_e;
 
 /**
+ * @brief Struct for TensorsData class info.
+ */
+typedef struct
+{
+  jclass cls;
+  jmethodID mid_init;
+  jmethodID mid_add_data;
+  jmethodID mid_get_array;
+  jmethodID mid_set_info;
+  jmethodID mid_get_info;
+} data_class_info_s;
+
+/**
+ * @brief Struct for TensorsInfo class info.
+ */
+typedef struct
+{
+  jclass cls;
+  jmethodID mid_init;
+  jmethodID mid_add_info;
+  jmethodID mid_get_array;
+
+  jclass cls_info;
+  jfieldID fid_info_name;
+  jfieldID fid_info_type;
+  jfieldID fid_info_dim;
+} info_class_info_s;
+
+/**
  * @brief Struct for constructed pipeline.
  */
 typedef struct
@@ -84,8 +125,12 @@ typedef struct
   pthread_key_t jni_env;
 
   jobject instance;
-  jclass cls_tensors_data;
-  jclass cls_tensors_info;
+  jclass cls;
+  data_class_info_s data_cls_info;
+  info_class_info_s info_cls_info;
+
+  gpointer priv_data;
+  nns_priv_destroy priv_destroy_func;
 } pipeline_info_s;
 
 /**
@@ -124,6 +169,12 @@ extern void
 nns_destroy_pipe_info (pipeline_info_s * pipe_info, JNIEnv * env);
 
 /**
+ * @brief Set private data in pipeline info.
+ */
+extern void
+nns_set_priv_data (pipeline_info_s * pipe_info, gpointer data, nns_priv_destroy destroy_func);
+
+/**
  * @brief Get element handle of given name.
  */
 extern gpointer