[Debug] Add a naive validator to the optimized planner
authorJihoon Lee <jhoon.it.lee@samsung.com>
Thu, 13 Jan 2022 15:25:50 +0000 (00:25 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Wed, 19 Jan 2022 10:51:43 +0000 (19:51 +0900)
This patch add a naive validator to the optimized planner. This doubles
the memory consumption. So kept commented but when time comes, this
function can be enabled.

**Self evaluation:**
1. Build test: [X]Passed [ ]Failed [ ]Skipped
2. Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: Jihoon Lee <jhoon.it.lee@samsung.com>
nntrainer/tensor/optimized_v1_planner.cpp

index 8dfff2f..f297e61 100644 (file)
@@ -12,6 +12,9 @@
  */
 
 #include <algorithm>
+#include <memory>
+#include <nntrainer_error.h>
+#include <stdexcept>
 #include <vector>
 
 #include <optimized_v1_planner.h>
@@ -43,6 +46,69 @@ struct MemoryRequest {
 };
 
 /**
+ * @brief check if validate interval is overlapping in a very naive way.
+ *
+ * @param memory_validity validity
+ * @param memory_size  size
+ * @param memory_offset  offset
+ * @param memory_req  request
+ */
+[[maybe_unused]] static void validateIntervalOverlap(
+  const std::vector<std::pair<unsigned int, unsigned int>> &memory_validity,
+  const std::vector<size_t> &memory_size,
+  const std::vector<size_t> &memory_offset, size_t memory_req) {
+  auto bits = std::make_unique<bool[]>(memory_req);
+
+  for (size_t i = 0; i < memory_req; ++i) {
+    bits[i] = 0;
+  }
+
+  auto exec_start =
+    std::min_element(memory_validity.begin(), memory_validity.end(),
+                     [](auto &a, auto &b) { return a.first < b.first; });
+
+  auto exec_end =
+    std::max_element(memory_validity.begin(), memory_validity.end(),
+                     [](auto &a, auto &b) { return a.second < b.second; });
+
+  auto set = [&](int offset, size_t size, int idx) {
+    for (unsigned int i = offset; i < size; ++i) {
+      NNTR_THROW_IF(bits[i], std::invalid_argument)
+        << " bits taken at i: " << i << " offset: " << offset
+        << " size: " << size << " idx: " << idx;
+      bits[i] = 1;
+    }
+  };
+
+  auto unset = [&](int offset, size_t size, int idx) {
+    for (unsigned int i = offset; i < size; ++i) {
+      NNTR_THROW_IF(!bits[i], std::invalid_argument)
+        << "double freeing bits at i: " << i << " offset: " << offset
+        << " size: " << size << " idx: " << idx;
+      bits[i] = 0;
+    }
+  };
+
+  for (unsigned int exec = exec_start->first; exec <= exec_end->second;
+       ++exec) {
+
+    for (unsigned int idx = 0; idx < memory_validity.size(); ++idx) {
+      auto &validity = memory_validity.at(idx);
+      auto &sz = memory_size.at(idx);
+      auto &offset = memory_offset.at(idx);
+      if (validity.first == exec) {
+        set(offset, sz, idx);
+      }
+      if (validity.second == exec) {
+        unset(offset, sz, idx);
+      }
+    }
+  }
+  // check if there is any dangling memory
+  set(0, memory_req, memory_validity.size());
+}
+
+/**
  * @copydoc MemoryPlanner::planLayout(
  * const std::vector<size_t> &memory_size,
  * const std::vector<std::pair<unsigned int, unsigned int>> &memory_validity,
@@ -126,6 +192,9 @@ size_t OptimizedV1Planner::planLayout(
     sorted_req.push_back(&req);
   }
 
+  //   validateIntervalOverlap(memory_validity, memory_size, memory_offset,
+  //   memory_req);
+
   return memory_req;
 }