pw_result: Add some size reports
This adds some simple size reports to the result module to provide some
data on how it compares to traditional function prototypes.
Change-Id: I711fa5d04ff5720ed3184b6250f3993606bd34ec
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/17162
Commit-Queue: Alexei Frolov <frolv@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
diff --git a/pw_preprocessor/public/pw_preprocessor/compiler.h b/pw_preprocessor/public/pw_preprocessor/compiler.h
index 8f87dbd..9d7d03d 100644
--- a/pw_preprocessor/public/pw_preprocessor/compiler.h
+++ b/pw_preprocessor/public/pw_preprocessor/compiler.h
@@ -74,6 +74,9 @@
//
#define PW_NO_RETURN __attribute__((noreturn))
+// Prevents the compiler from inlining a fuction.
+#define PW_NO_INLINE __attribute__((noinline))
+
// Indicate to the compiler that the given section of code will not be reached.
// Example:
//
diff --git a/pw_result/BUILD.gn b/pw_result/BUILD.gn
index b839de8..db338ae 100644
--- a/pw_result/BUILD.gn
+++ b/pw_result/BUILD.gn
@@ -15,6 +15,7 @@
# gn-format disable
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")
@@ -42,4 +43,27 @@
pw_doc_group("docs") {
sources = [ "docs.rst" ]
+ report_deps = [ ":result_size" ]
+}
+
+pw_size_report("result_size") {
+ title = "pw::Result vs. pw::Status and out pointer"
+
+ binaries = [
+ {
+ target = "size_report:result_simple"
+ base = "size_report:pointer_simple"
+ label = "Simple function"
+ },
+ {
+ target = "size_report:result_noinline"
+ base = "size_report:pointer_noinline"
+ label = "Simple function without inlining"
+ },
+ {
+ target = "size_report:result_read"
+ base = "size_report:pointer_read"
+ label = "Returning a larger object (std::span)"
+ },
+ ]
}
diff --git a/pw_result/docs.rst b/pw_result/docs.rst
index 5671d8a..02d6854 100644
--- a/pw_result/docs.rst
+++ b/pw_result/docs.rst
@@ -24,3 +24,15 @@
Compatibility
=============
Works with C++11, but some features require C++17.
+
+Size report
+===========
+The table below showcases the difference in size between functions returning a
+Status with an output pointer, and functions returning a Result, in various
+situations.
+
+Note that these are simplified examples which do not necessarily reflect the
+usage of Result in real code. Make sure to always run your own size reports to
+check if Result is suitable for you.
+
+.. include:: result_size
diff --git a/pw_result/size_report/BUILD b/pw_result/size_report/BUILD
new file mode 100644
index 0000000..1a67937
--- /dev/null
+++ b/pw_result/size_report/BUILD
@@ -0,0 +1,78 @@
+# 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.
+
+load(
+ "//pw_build:pigweed.bzl",
+ "pw_cc_binary",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache License 2.0
+
+pw_cc_binary(
+ name = "pointer_simple",
+ srcs = ["pointer_simple.cc"],
+ deps = [
+ "//pw_result",
+ "//pw_log",
+ ],
+)
+
+pw_cc_binary(
+ name = "result_simple",
+ srcs = ["result_simple.cc"],
+ deps = [
+ "//pw_result",
+ "//pw_log",
+ ],
+)
+
+pw_cc_binary(
+ name = "pointer_noinline",
+ srcs = ["pointer_noinline.cc"],
+ deps = [
+ "//pw_result",
+ "//pw_log",
+ ],
+)
+
+pw_cc_binary(
+ name = "result_noinline",
+ srcs = ["result_noinline.cc"],
+ deps = [
+ "//pw_result",
+ "//pw_log",
+ ],
+)
+
+pw_cc_binary(
+ name = "pointer_read",
+ srcs = ["pointer_read.cc"],
+ deps = [
+ "//pw_result",
+ "//pw_log",
+ "//pw_span",
+ ],
+)
+
+pw_cc_binary(
+ name = "result_read",
+ srcs = ["result_read.cc"],
+ deps = [
+ "//pw_result",
+ "//pw_log",
+ "//pw_span",
+ ],
+)
diff --git a/pw_result/size_report/BUILD.gn b/pw_result/size_report/BUILD.gn
new file mode 100644
index 0000000..34556d3
--- /dev/null
+++ b/pw_result/size_report/BUILD.gn
@@ -0,0 +1,73 @@
+# 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.
+
+# gn-format disable
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+pw_executable("pointer_simple") {
+ sources = [ "pointer_simple.cc" ]
+ deps = [
+ "..",
+ dir_pw_log,
+ ]
+}
+
+pw_executable("result_simple") {
+ sources = [ "result_simple.cc" ]
+ deps = [
+ "..",
+ dir_pw_log,
+ ]
+}
+
+pw_executable("pointer_noinline") {
+ sources = [ "pointer_noinline.cc" ]
+ deps = [
+ "..",
+ dir_pw_log,
+ dir_pw_preprocessor,
+ ]
+}
+
+pw_executable("result_noinline") {
+ sources = [ "result_noinline.cc" ]
+ deps = [
+ "..",
+ dir_pw_log,
+ dir_pw_preprocessor,
+ ]
+}
+
+pw_executable("pointer_read") {
+ sources = [ "pointer_read.cc" ]
+ deps = [
+ "..",
+ dir_pw_bytes,
+ dir_pw_log,
+ dir_pw_preprocessor,
+ dir_pw_span,
+ ]
+}
+
+pw_executable("result_read") {
+ sources = [ "result_read.cc" ]
+ deps = [
+ "..",
+ dir_pw_bytes,
+ dir_pw_log,
+ dir_pw_preprocessor,
+ dir_pw_span,
+ ]
+}
diff --git a/pw_result/size_report/pointer_noinline.cc b/pw_result/size_report/pointer_noinline.cc
new file mode 100644
index 0000000..7c77de6
--- /dev/null
+++ b/pw_result/size_report/pointer_noinline.cc
@@ -0,0 +1,37 @@
+// 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.
+
+#include "pw_log/log.h"
+#include "pw_preprocessor/compiler.h"
+#include "pw_status/status.h"
+
+PW_NO_INLINE pw::Status Divide(float a, float b, float* out) {
+ if (b == 0) {
+ return pw::Status::INVALID_ARGUMENT;
+ }
+ *out = a / b;
+ return pw::Status::OK;
+}
+
+int volatile* unoptimizable;
+
+int main() {
+ float f;
+ if (Divide(*unoptimizable, *unoptimizable, &f).ok()) {
+ PW_LOG_INFO("result is %f", f);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/pw_result/size_report/pointer_read.cc b/pw_result/size_report/pointer_read.cc
new file mode 100644
index 0000000..e346452
--- /dev/null
+++ b/pw_result/size_report/pointer_read.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include <cstring>
+#include <span>
+
+#include "pw_bytes/array.h"
+#include "pw_log/log.h"
+#include "pw_preprocessor/compiler.h"
+#include "pw_status/status.h"
+
+namespace {
+
+// clang-format off
+constexpr auto kArray = pw::bytes::Array<
+ 0x0a, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x96, 0x00,
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x12, 0x08,
+ 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01>();
+// clang-format on
+
+PW_NO_INLINE pw::Status Read(size_t offset,
+ size_t size,
+ std::span<const std::byte>* out) {
+ if (offset + size >= std::size(kArray)) {
+ return pw::Status::OUT_OF_RANGE;
+ }
+
+ *out = std::span<const std::byte>(std::data(kArray) + offset, size);
+ return pw::Status::OK;
+}
+
+} // namespace
+
+size_t volatile* unoptimizable;
+
+int main() {
+ std::span<const std::byte> data;
+ pw::Status status = Read(*unoptimizable, *unoptimizable, &data);
+ if (!status.ok()) {
+ return 1;
+ }
+
+ PW_LOG_INFO("Read %u bytes", static_cast<unsigned>(data.size()));
+ return 0;
+}
diff --git a/pw_result/size_report/pointer_simple.cc b/pw_result/size_report/pointer_simple.cc
new file mode 100644
index 0000000..eb536d4
--- /dev/null
+++ b/pw_result/size_report/pointer_simple.cc
@@ -0,0 +1,36 @@
+// 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.
+
+#include "pw_log/log.h"
+#include "pw_status/status.h"
+
+pw::Status Divide(float a, float b, float* out) {
+ if (b == 0) {
+ return pw::Status::INVALID_ARGUMENT;
+ }
+ *out = a / b;
+ return pw::Status::OK;
+}
+
+int volatile* unoptimizable;
+
+int main() {
+ float f;
+ if (Divide(*unoptimizable, *unoptimizable, &f).ok()) {
+ PW_LOG_INFO("result is %f", f);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/pw_result/size_report/result_noinline.cc b/pw_result/size_report/result_noinline.cc
new file mode 100644
index 0000000..c099dc5
--- /dev/null
+++ b/pw_result/size_report/result_noinline.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "pw_log/log.h"
+#include "pw_preprocessor/compiler.h"
+#include "pw_result/result.h"
+
+PW_NO_INLINE pw::Result<float> Divide(float a, float b) {
+ if (b == 0) {
+ return pw::Status::INVALID_ARGUMENT;
+ }
+ return a / b;
+}
+
+float volatile* unoptimizable;
+
+int main() {
+ if (pw::Result result = Divide(*unoptimizable, *unoptimizable); result.ok()) {
+ PW_LOG_INFO("result is %f", result.value());
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/pw_result/size_report/result_read.cc b/pw_result/size_report/result_read.cc
new file mode 100644
index 0000000..9bc9ffd
--- /dev/null
+++ b/pw_result/size_report/result_read.cc
@@ -0,0 +1,54 @@
+// 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.
+
+#include <cstring>
+#include <span>
+
+#include "pw_bytes/array.h"
+#include "pw_log/log.h"
+#include "pw_preprocessor/compiler.h"
+#include "pw_result/result.h"
+
+namespace {
+
+// clang-format off
+constexpr auto kArray = pw::bytes::Array<
+ 0x0a, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x96, 0x00,
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x12, 0x08,
+ 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01>();
+// clang-format on
+
+PW_NO_INLINE pw::Result<std::span<const std::byte>> Read(size_t offset,
+ size_t size) {
+ if (offset + size >= std::size(kArray)) {
+ return pw::Status::OUT_OF_RANGE;
+ }
+
+ return std::span<const std::byte>(std::data(kArray) + offset, size);
+}
+
+} // namespace
+
+size_t volatile* unoptimizable;
+
+int main() {
+ pw::Result result = Read(*unoptimizable, *unoptimizable);
+ if (!result.ok()) {
+ return 1;
+ }
+
+ PW_LOG_INFO("Read %u bytes", static_cast<unsigned>(result.value().size()));
+ return 0;
+}
diff --git a/pw_result/size_report/result_simple.cc b/pw_result/size_report/result_simple.cc
new file mode 100644
index 0000000..91772b9
--- /dev/null
+++ b/pw_result/size_report/result_simple.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "pw_log/log.h"
+#include "pw_result/result.h"
+
+pw::Result<float> Divide(float a, float b) {
+ if (b == 0) {
+ return pw::Status::INVALID_ARGUMENT;
+ }
+ return a / b;
+}
+
+float volatile* unoptimizable;
+
+int main() {
+ if (pw::Result result = Divide(*unoptimizable, *unoptimizable); result.ok()) {
+ PW_LOG_INFO("result is %f", result.value());
+ return 0;
+ }
+
+ return 1;
+}