[N71] Split the compaction algorithm into two-step one
authorDongju Chae <dongju.chae@samsung.com>
Wed, 17 Jul 2019 08:10:20 +0000 (17:10 +0900)
committer함명주/On-Device Lab(SR)/Principal Engineer/삼성전자 <myungjoo.ham@samsung.com>
Thu, 18 Jul 2019 10:49:01 +0000 (19:49 +0900)
This commit splits the compaction algorithm into two-step one.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
core/npu-engine/src/ne-mem.c

index 0a8204b..a825016 100644 (file)
@@ -453,11 +453,20 @@ chunk_compact_try (uint64_t *offset_dst)
 {
   chunk *target = NULL;
 
+  /**
+   * For chunk compaction, we use two-stage compactions, depending on the status of free chunks.
+   * At first, we can move used chunks to free chunks if there're enough large free chunks.
+   * In most cases, it would be enough. Otherwise, we need to re-arrange free chunks
+   * by shifting them to the bottom. It's heavy-weight and requires more memory copies.
+   */
+
+  /* we first try to perform 1st stage (light-weight) */
+
   /* find a target chunk starting at top */
   list_for_each_entry_reverse (target, mpriv.used_chunks, list) {
     /* should be not busy (i.e., no processing here) and other conditions (TBD)? */
     if (chunk_set_state (target, CHUNK_STATE_MODIFIED, false) == 0) {
-      chunk *next_chunk, *free_chunk = NULL;
+      chunk *free_chunk = NULL;
 
       /* find a free chunk starting at bottom */
       list_for_each_entry (free_chunk, mpriv.free_chunks, list) {
@@ -465,7 +474,7 @@ chunk_compact_try (uint64_t *offset_dst)
         if (free_chunk->offset > target->offset)
           break;
 
-        /* case 1) there is a free slot where this chunk moves */
+        /* there is a free slot where this chunk moves */
         if (free_chunk->size >= target->size) {
           *offset_dst = free_chunk->offset;
 
@@ -483,11 +492,29 @@ chunk_compact_try (uint64_t *offset_dst)
           list_del (&mpriv.used_chunks, &target->list);
 
           return target;
-        } else
-        /* case 2) this chunk is directly attached to the free chunk */
+        }
+      }
+
+      /* failure */
+      assert (target->state == CHUNK_STATE_MODIFIED);
+      target->state = CHUNK_STATE_FREE;
+    }
+  }
+
+  /* If there is no avaialble free chunk, let's go to 2nd stage (heavy-weight) */
+
+  /* we shift a used chunk to its left free chunk, starting at bottom */
+  list_for_each_entry (target, mpriv.used_chunks, list) {
+    if (chunk_set_state (target, CHUNK_STATE_MODIFIED, false) == 0) {
+      chunk *free_chunk = NULL;
+
+      /* find a free chunk starting at bottom */
+      list_for_each_entry (free_chunk, mpriv.free_chunks, list) {
+        /* this chunk is directly attached to the free chunk */
         if (free_chunk->offset + free_chunk->size == target->offset) {
-          *offset_dst = target->offset - free_chunk->size;
+          chunk *next_chunk;
 
+          *offset_dst = target->offset - free_chunk->size;
           free_chunk->offset += target->size;
 
           /* check merge */
@@ -720,7 +747,7 @@ buffer_change_state (buffer_priv *priv, buffer_state state)
     case BUFFER_STATE_EMPTY:
       /* when the output buffer was returned */
       if (priv->state == BUFFER_STATE_OUTPUT_RETURN ||
-      /* when the previous input need to be discarded (e.g., NPU processing is too slow) */
+          /* when the previous input need to be discarded (e.g., NPU processing is too slow) */
           priv->state == BUFFER_STATE_INPUT_READY)
         state_changed = true;
       break;
@@ -783,7 +810,7 @@ mem_init (uint64_t size_in, uint64_t *size_out)
   uint32_t handle;
   int fd;
 
-  if (size_in % MEM_BASE_SIZE != 0 || size_in > UINT32_MAX) {
+  if (size_in == 0 || size_in % MEM_BASE_SIZE != 0 || size_in > UINT32_MAX) {
     logerr(MEM_TAG, "Invalid memory size: 0x%lx\n", size_in);
     return -EINVAL;
   }