pw_ring_buffer: Add bloat reporting
Adds single-reader and multi-reader implementations for bloat testing.
Compares single-reader w/base, multi-reader w/base, and single-reader
vs. multi-reader implementations.
Change-Id: I27b501ce2d72f3ad504693579f9ee2c9a61b1cd3
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/32584
Reviewed-by: David Rogers <davidrogers@google.com>
Commit-Queue: Prashanth Swaminathan <prashanthsw@google.com>
diff --git a/pw_ring_buffer/BUILD.gn b/pw_ring_buffer/BUILD.gn
index f5ac741..8871caa 100644
--- a/pw_ring_buffer/BUILD.gn
+++ b/pw_ring_buffer/BUILD.gn
@@ -14,6 +14,7 @@
import("//build_overrides/pigweed.gni")
+import("$dir_pw_bloat/bloat.gni")
import("$dir_pw_build/target_types.gni")
import("$dir_pw_docgen/docs.gni")
import("$dir_pw_unit_test/test.gni")
@@ -50,4 +51,27 @@
pw_doc_group("docs") {
sources = [ "docs.rst" ]
+ report_deps = [ ":ring_buffer_size" ]
+}
+
+pw_size_report("ring_buffer_size") {
+ title = "pw::ring_buffer::PrefixedEntryRingBuffer"
+
+ binaries = [
+ {
+ target = "size_report:ring_buffer_simple"
+ base = "$dir_pw_bloat:bloat_base"
+ label = "Initialize single-reader ring buffer"
+ },
+ {
+ target = "size_report:ring_buffer_multi"
+ base = "$dir_pw_bloat:bloat_base"
+ label = "Initialize multi-reader ring buffer"
+ },
+ {
+ target = "size_report:ring_buffer_multi"
+ base = "size_report:ring_buffer_simple"
+ label = "Initialized multi-reader vs. single-reader"
+ },
+ ]
}
diff --git a/pw_ring_buffer/size_report/BUILD b/pw_ring_buffer/size_report/BUILD
new file mode 100644
index 0000000..8339bc5
--- /dev/null
+++ b/pw_ring_buffer/size_report/BUILD
@@ -0,0 +1,32 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed 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
+#
+# https://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.
+
+load(
+ "//pw_build:pigweed.bzl",
+ "pw_cc_binary",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache License 2.0
+
+pw_cc_binary(
+ name = "ring_buffer_simple",
+ srcs = ["ring_buffer_simple.cc"],
+)
+
+pw_cc_binary(
+ name = "ring_buffer_multi",
+ srcs = ["ring_buffer_multi.cc"],
+)
diff --git a/pw_ring_buffer/size_report/BUILD.gn b/pw_ring_buffer/size_report/BUILD.gn
new file mode 100644
index 0000000..25159db8
--- /dev/null
+++ b/pw_ring_buffer/size_report/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed 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
+#
+# https://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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+
+pw_executable("ring_buffer_simple") {
+ sources = [ "ring_buffer_simple.cc" ]
+ deps = [ ".." ]
+}
+
+pw_executable("ring_buffer_multi") {
+ sources = [ "ring_buffer_multi.cc" ]
+ deps = [ ".." ]
+}
diff --git a/pw_ring_buffer/size_report/ring_buffer_multi.cc b/pw_ring_buffer/size_report/ring_buffer_multi.cc
new file mode 100644
index 0000000..564e8f8
--- /dev/null
+++ b/pw_ring_buffer/size_report/ring_buffer_multi.cc
@@ -0,0 +1,96 @@
+// Copyright 2021 The Pigweed Authors
+//
+// Licensed 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
+//
+// https://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 "pw_ring_buffer/prefixed_entry_ring_buffer.h"
+#include "pw_status/status.h"
+
+constexpr size_t kRingBufferSize = 1024;
+constexpr size_t kReaderCount = 4;
+constexpr std::byte kValue = (std::byte)0xFF;
+constexpr std::byte kData[1] = {kValue};
+
+int main() {
+ pw::ring_buffer::PrefixedEntryRingBufferMulti ring(true /* user_preamble */);
+ std::byte buffer[kRingBufferSize];
+
+ pw::Status status = ring.SetBuffer(buffer);
+ if (!status.ok()) {
+ return 1;
+ }
+
+ // Attach readers.
+ pw::ring_buffer::PrefixedEntryRingBufferMulti::Reader readers[kReaderCount];
+ for (auto& reader : readers) {
+ ring.AttachReader(reader);
+ }
+
+ // Push entries until the buffer is full.
+ size_t total_entries = 0;
+ while (true) {
+ status = ring.TryPushBack(kData);
+ if (status == pw::Status::ResourceExhausted()) {
+ break;
+ } else if (!status.ok()) {
+ return 2;
+ }
+ total_entries++;
+ }
+
+ // Forcefully push an entry.
+ status = ring.PushBack(kData);
+ if (!status.ok()) {
+ return 3;
+ }
+
+ // Dering the buffer.
+ status = ring.Dering();
+ if (!status.ok()) {
+ return 4;
+ }
+
+ // Peek and pop all entries.
+ __attribute__((unused)) std::byte value[1];
+ __attribute__((unused)) size_t value_size;
+ for (size_t i = 0; i < total_entries; ++i) {
+ for (auto& reader : readers) {
+ status = reader.PeekFront(value, &value_size);
+ if (!status.ok()) {
+ return 5;
+ }
+ status = reader.PeekFrontWithPreamble(value, &value_size);
+ if (!status.ok()) {
+ return 6;
+ }
+ if (reader.FrontEntryDataSizeBytes() == 0) {
+ return 7;
+ }
+ if (reader.FrontEntryTotalSizeBytes() == 0) {
+ return 8;
+ }
+ if (reader.EntryCount() == 0) {
+ return 9;
+ }
+ status = reader.PopFront();
+ if (!status.ok()) {
+ return 10;
+ }
+ }
+ }
+
+ for (auto& reader : readers) {
+ ring.DetachReader(reader);
+ }
+ ring.Clear();
+ return 0;
+}
diff --git a/pw_ring_buffer/size_report/ring_buffer_simple.cc b/pw_ring_buffer/size_report/ring_buffer_simple.cc
new file mode 100644
index 0000000..0be77ba
--- /dev/null
+++ b/pw_ring_buffer/size_report/ring_buffer_simple.cc
@@ -0,0 +1,83 @@
+// Copyright 2021 The Pigweed Authors
+//
+// Licensed 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
+//
+// https://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 "pw_ring_buffer/prefixed_entry_ring_buffer.h"
+#include "pw_status/status.h"
+
+constexpr size_t kRingBufferSize = 1024;
+constexpr std::byte kValue = (std::byte)0xFF;
+constexpr std::byte kData[1] = {kValue};
+
+int main() {
+ pw::ring_buffer::PrefixedEntryRingBuffer ring(true /* user_preamble */);
+ std::byte buffer[kRingBufferSize];
+
+ pw::Status status = ring.SetBuffer(buffer);
+ if (!status.ok()) {
+ return 1;
+ }
+
+ // Push entries until the buffer is full.
+ size_t total_entries = 0;
+ while (true) {
+ status = ring.TryPushBack(kData);
+ if (status == pw::Status::ResourceExhausted()) {
+ break;
+ } else if (!status.ok()) {
+ return 2;
+ }
+ total_entries++;
+ }
+
+ // Forcefully push an entry.
+ status = ring.PushBack(kData);
+ if (!status.ok()) {
+ return 3;
+ }
+
+ // Dering the buffer.
+ status = ring.Dering();
+ if (!status.ok()) {
+ return 4;
+ }
+
+ // Peek and pop all entries.
+ __attribute__((unused)) std::byte value[1];
+ __attribute__((unused)) size_t value_size;
+ for (size_t i = 0; i < total_entries; ++i) {
+ status = ring.PeekFront(value, &value_size);
+ if (!status.ok()) {
+ return 5;
+ }
+ status = ring.PeekFrontWithPreamble(value, &value_size);
+ if (!status.ok()) {
+ return 6;
+ }
+ if (ring.FrontEntryDataSizeBytes() == 0) {
+ return 7;
+ }
+ if (ring.FrontEntryTotalSizeBytes() == 0) {
+ return 8;
+ }
+ if (ring.EntryCount() == 0) {
+ return 9;
+ }
+ status = ring.PopFront();
+ if (!status.ok()) {
+ return 10;
+ }
+ }
+ ring.Clear();
+ return 0;
+}