This is an automated email from the ASF dual-hosted git repository.

junrushao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new a1c1ccafa1 [SUPPORT] Fix RingBuffer ReadWithCallback (#14743)
a1c1ccafa1 is described below

commit a1c1ccafa16cfdc155519fa38f9a5b782a1a5571
Author: Tianqi Chen <[email protected]>
AuthorDate: Wed May 10 12:29:34 2023 -0400

    [SUPPORT] Fix RingBuffer ReadWithCallback (#14743)
    
    This PR bugfixes ring buffer ReadWithCallback when
    the callback send function read part of the data.
    Also backported one robustness fix from unity.
    
    Testcases are added
---
 src/support/ring_buffer.h             | 15 ++++++--
 tests/cpp/support/ring_buffer_test.cc | 68 +++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/src/support/ring_buffer.h b/src/support/ring_buffer.h
index 1c6a6f8b43..866c9c4424 100644
--- a/src/support/ring_buffer.h
+++ b/src/support/ring_buffer.h
@@ -24,6 +24,8 @@
 #ifndef TVM_SUPPORT_RING_BUFFER_H_
 #define TVM_SUPPORT_RING_BUFFER_H_
 
+#include <tvm/runtime/logging.h>
+
 #include <algorithm>
 #include <cstring>
 #include <vector>
@@ -61,6 +63,9 @@ class RingBuffer {
       if (head_ptr_ + bytes_available_ > old_size) {
         // copy the ring overflow part into the tail.
         size_t ncopy = head_ptr_ + bytes_available_ - old_size;
+        if (old_size + ncopy > ring_.size()) {
+          ring_.resize(old_size + ncopy);
+        }
         memcpy(&ring_[0] + old_size, &ring_[0], ncopy);
       }
     } else if (ring_.size() > n * 8 && ring_.size() > kInitCapacity) {
@@ -101,6 +106,9 @@ class RingBuffer {
     }
     head_ptr_ = (head_ptr_ + size) % ring_.size();
     bytes_available_ -= size;
+    if (bytes_available_ == 0) {
+      head_ptr_ = 0;
+    }
   }
   /*!
    * \brief Read data from buffer with and put them to non-blocking send 
function.
@@ -115,12 +123,15 @@ class RingBuffer {
     ICHECK_NE(size, 0U);
     size_t ncopy = std::min(size, ring_.size() - head_ptr_);
     size_t nsend = fsend(&ring_[0] + head_ptr_, ncopy);
-    bytes_available_ -= nsend;
     if (ncopy == nsend && ncopy < size) {
       size_t nsend2 = fsend(&ring_[0], size - ncopy);
-      bytes_available_ -= nsend2;
       nsend += nsend2;
     }
+    head_ptr_ = (head_ptr_ + nsend) % ring_.size();
+    bytes_available_ -= nsend;
+    if (bytes_available_ == 0) {
+      head_ptr_ = 0;
+    }
     return nsend;
   }
   /*!
diff --git a/tests/cpp/support/ring_buffer_test.cc 
b/tests/cpp/support/ring_buffer_test.cc
new file mode 100644
index 0000000000..9b78b27677
--- /dev/null
+++ b/tests/cpp/support/ring_buffer_test.cc
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "../../../src/support/ring_buffer.h"
+
+#include <gtest/gtest.h>
+
+namespace tvm {
+namespace support {
+namespace {
+
+TEST(RingBuffer, ReadWrite) {
+  RingBuffer buffer;
+  std::vector<int> data = {1, 2, 3, 4};
+  std::vector<int> output;
+
+  buffer.Write(data.data(), data.size() * 4);
+  ASSERT_EQ(buffer.bytes_available(), data.size() * 4);
+
+  output.resize(4);
+  buffer.Read(output.data(), data.size() * 4);
+
+  for (size_t i = 0; i < output.size(); ++i) {
+    ASSERT_EQ(output[i], data[i]);
+  }
+}
+
+TEST(RingBuffer, ReadWithCallback) {
+  RingBuffer buffer;
+  std::vector<int> data = {1, 2, 3, 4};
+  std::vector<int> output;
+
+  buffer.Write(data.data(), data.size() * 4);
+
+  auto callback0 = [](const char* data, size_t size) -> size_t {
+    const int* iptr = reinterpret_cast<const int*>(data);
+    ICHECK_EQ(iptr[0], 1);
+    ICHECK_EQ(iptr[1], 2);
+    return size;
+  };
+  buffer.ReadWithCallback(callback0, 2 * sizeof(int));
+  auto callback1 = [](const char* data, size_t size) -> size_t {
+    const int* iptr = reinterpret_cast<const int*>(data);
+    ICHECK_EQ(iptr[0], 3);
+    ICHECK_EQ(iptr[1], 4);
+    return size;
+  };
+  buffer.ReadWithCallback(callback1, 2 * sizeof(int));
+}
+}  // namespace
+}  // namespace support
+}  // namespace tvm

Reply via email to