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

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


The following commit(s) were added to refs/heads/main by this push:
     new 9a18992678 GH-47774: [C++] Force-inline Status::~Status() to improve 
reading performance (#50749)
9a18992678 is described below

commit 9a18992678f86f140c6c76f427678031aee7d493
Author: Zhou Hongfeng <[email protected]>
AuthorDate: Tue Oct 27 20:43:33 2026 +0800

    GH-47774: [C++] Force-inline Status::~Status() to improve reading 
performance (#50749)
    
    ### Rationale for this change
    
    `Status` is returned by nearly every API on hot paths (e.g. IPC/Parquet 
reading), so its destructor runs extremely frequently. The destructor body is 
already optimized for the common success case: it only checks `state_ != NULL` 
(with `ARROW_PREDICT_FALSE`) and returns immediately for an OK status, 
delegating the rare error cleanup to the out-of-line `DeleteState()`.
    
    However, without an explicit inlining hint, some compilers/optimization 
levels may not inline this destructor, turning the trivial `state_ == NULL` 
fast path into a real function call at every call site. Forcing it inline 
removes this call overhead on hot read paths and improves read throughput.
    
    In our perf test (reads a parquet file of 6.7GB), `Status::~Status` cost 
about 20 seconds, as the following flamegraph shows:
    <img width="1381" height="254" alt="image" 
src="https://github.com/user-attachments/assets/c62601b8-6d1f-455a-9ee5-9edc4ea57852";
 />
    
    After inlining `Status::~Status`, the hotspot disappeared. End-to-end 
latency was also reduced by 20 seconds, as expected.
    
    <img width="1367" height="263" alt="image" 
src="https://github.com/user-attachments/assets/78ec8f84-f9b7-4d74-b767-9046c1d40eaf";
 />
    
    ### What changes are included in this PR?
    
    - Annotate `Status::~Status()` in `cpp/src/arrow/status.h` with 
`ARROW_FORCE_INLINE` (`__attribute__((always_inline)) inline` on GCC/Clang, 
`__forceinline` on MSVC), so the cheap null-check fast path is always inlined 
while the cold error path still goes through the non-inlined `DeleteState()`.
    
    ### Are these changes tested?
    
    Yes, by existing tests. This change does not alter any behavior of 
`Status`; the existing `Status` unit tests and the full C++ test suite cover 
it. The performance improvement can be observed with the existing read-path 
benchmarks.
    
    ### Are there any user-facing changes?
    
    No. This is an internal performance optimization with no API or behavior 
change.
    
    * GitHub Issue: #47774
    
    Lead-authored-by: Antoine Pitrou <[email protected]>
    Co-authored-by: zhouhongfeng <[email protected]>
    Co-authored-by: Antoine Pitrou <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 cpp/src/arrow/status.cc |  4 +---
 cpp/src/arrow/status.h  | 17 +++++++++--------
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/cpp/src/arrow/status.cc b/cpp/src/arrow/status.cc
index 50eb001c3a..5e54c267fb 100644
--- a/cpp/src/arrow/status.cc
+++ b/cpp/src/arrow/status.cc
@@ -32,9 +32,7 @@ Status::Status(StatusCode code, std::string msg, 
std::shared_ptr<StatusDetail> d
 
 void Status::CopyFrom(const Status& s) {
   if (ARROW_PREDICT_FALSE(state_ != NULL)) {
-    if (!state_->is_constant) {
-      DeleteState();
-    }
+    DeleteState();
   }
   if (s.state_ == nullptr) {
     state_ = nullptr;
diff --git a/cpp/src/arrow/status.h b/cpp/src/arrow/status.h
index 5757440cee..39f31141e8 100644
--- a/cpp/src/arrow/status.h
+++ b/cpp/src/arrow/status.h
@@ -148,11 +148,12 @@ class ARROW_EXPORT [[nodiscard]] Status : public 
util::EqualityComparable<Status
  public:
   // Create a success status.
   constexpr Status() noexcept : state_(NULLPTR) {}
-  ~Status() noexcept {
+
+  // GH-47774: force-inline the Status destructor's hot path
+  // and keep it as lean as possible.
+  ARROW_FORCE_INLINE ~Status() noexcept {
     if (ARROW_PREDICT_FALSE(state_ != NULL)) {
-      if (!state_->is_constant) {
-        DeleteState();
-      }
+      DeleteState();
     }
   }
 
@@ -409,7 +410,9 @@ class ARROW_EXPORT [[nodiscard]] Status : public 
util::EqualityComparable<Status
   void DeleteState() noexcept {
     // ARROW-2400: On certain compilers, splitting off the slow path improves
     // performance significantly.
-    delete state_;
+    if (!state_->is_constant) {
+      delete state_;
+    }
   }
   void CopyFrom(const Status& s);
   inline void MoveFrom(Status& s);
@@ -419,9 +422,7 @@ class ARROW_EXPORT [[nodiscard]] Status : public 
util::EqualityComparable<Status
 
 void Status::MoveFrom(Status& s) {
   if (ARROW_PREDICT_FALSE(state_ != NULL)) {
-    if (!state_->is_constant) {
-      DeleteState();
-    }
+    DeleteState();
   }
   state_ = s.state_;
   s.state_ = NULLPTR;

Reply via email to