mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 20:14:23 +08:00
Search more aggressively for open slots in absl::internal_stacktrace::BorrowedFixupBuffer
This lets us avoid heap allocations in more situations than before. PiperOrigin-RevId: 841851984 Change-Id: Ibd16b0b87c250c504c8d1119d9b9eb4031067c28
This commit is contained in:
committed by
Copybara-Service
parent
f17f9070d2
commit
88c48235c8
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
@@ -46,28 +47,27 @@ ABSL_CONST_INIT BorrowedFixupBuffer::FixupStackBuffer
|
||||
|
||||
BorrowedFixupBuffer::~BorrowedFixupBuffer() {
|
||||
if (borrowed_) {
|
||||
Unlock();
|
||||
std::move(*this).Unlock();
|
||||
} else {
|
||||
base_internal::LowLevelAlloc::Free(frames_);
|
||||
}
|
||||
}
|
||||
|
||||
BorrowedFixupBuffer::BorrowedFixupBuffer(size_t length) {
|
||||
FixupStackBuffer* fixup_buffer =
|
||||
0 < length && length <= FixupStackBuffer::kMaxStackElements ? TryLock()
|
||||
: nullptr;
|
||||
borrowed_ = fixup_buffer != nullptr;
|
||||
BorrowedFixupBuffer::BorrowedFixupBuffer(size_t length)
|
||||
: borrowed_(0 < length && length <= FixupStackBuffer::kMaxStackElements
|
||||
? TryLock()
|
||||
: nullptr) {
|
||||
if (borrowed_) {
|
||||
InitViaBorrow(fixup_buffer);
|
||||
InitViaBorrow();
|
||||
} else {
|
||||
InitViaAllocation(length);
|
||||
}
|
||||
}
|
||||
|
||||
void BorrowedFixupBuffer::InitViaBorrow(FixupStackBuffer* borrowed_buffer) {
|
||||
void BorrowedFixupBuffer::InitViaBorrow() {
|
||||
assert(borrowed_);
|
||||
frames_ = borrowed_buffer->frames;
|
||||
sizes_ = borrowed_buffer->sizes;
|
||||
frames_ = borrowed_->frames;
|
||||
sizes_ = borrowed_->sizes;
|
||||
}
|
||||
|
||||
void BorrowedFixupBuffer::InitViaAllocation(size_t length) {
|
||||
@@ -92,25 +92,25 @@ void BorrowedFixupBuffer::InitViaAllocation(size_t length) {
|
||||
length * sizeof(*frames_))) int[length];
|
||||
}
|
||||
|
||||
BorrowedFixupBuffer::FixupStackBuffer* BorrowedFixupBuffer::Find() {
|
||||
size_t i = absl::Hash<const void*>()(this) %
|
||||
std::size(FixupStackBuffer::g_instances);
|
||||
return &FixupStackBuffer::g_instances[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] BorrowedFixupBuffer::FixupStackBuffer*
|
||||
BorrowedFixupBuffer::TryLock() {
|
||||
FixupStackBuffer* instance = Find();
|
||||
// Use memory_order_acquire to ensure that no reads and writes on the borrowed
|
||||
// buffer are reordered before the borrowing.
|
||||
return !instance->in_use.test_and_set(std::memory_order_acquire) ? instance
|
||||
: nullptr;
|
||||
constexpr size_t kNumSlots = std::size(FixupStackBuffer::g_instances);
|
||||
const size_t i = absl::Hash<const void*>()(this) % kNumSlots;
|
||||
for (size_t k = 0; k < kNumSlots; ++k) {
|
||||
auto* instance = &FixupStackBuffer::g_instances[(i + k) % kNumSlots];
|
||||
// Use memory_order_acquire to ensure that no reads and writes on the
|
||||
// borrowed buffer are reordered before the borrowing.
|
||||
if (!instance->in_use.test_and_set(std::memory_order_acquire)) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BorrowedFixupBuffer::Unlock() {
|
||||
void BorrowedFixupBuffer::Unlock() && {
|
||||
// Use memory_order_release to ensure that no reads and writes on the borrowed
|
||||
// buffer are reordered after the borrowing.
|
||||
Find()->in_use.clear(std::memory_order_release);
|
||||
borrowed_->in_use.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
} // namespace internal_stacktrace
|
||||
|
||||
@@ -42,26 +42,23 @@ class BorrowedFixupBuffer {
|
||||
int* sizes() const { return sizes_; }
|
||||
|
||||
private:
|
||||
struct FixupStackBuffer;
|
||||
|
||||
uintptr_t* frames_;
|
||||
int* sizes_;
|
||||
|
||||
// Have we borrowed a pre-existing buffer (vs. allocated our own)?
|
||||
bool borrowed_;
|
||||
// The borrowed pre-existing buffer, if any (if we haven't allocated our own)
|
||||
FixupStackBuffer* const borrowed_;
|
||||
|
||||
struct FixupStackBuffer;
|
||||
|
||||
void InitViaBorrow(FixupStackBuffer* borrowed_buffer);
|
||||
void InitViaBorrow();
|
||||
void InitViaAllocation(size_t length);
|
||||
|
||||
// Returns a non-null pointer to a buffer that could be potentially borrowed.
|
||||
FixupStackBuffer* Find();
|
||||
|
||||
// Attempts to opportunistically borrow a small buffer in a thread- and
|
||||
// signal-safe manner. Returns nullptr on failure.
|
||||
[[nodiscard]] FixupStackBuffer* TryLock();
|
||||
|
||||
// Returns the borrowed buffer.
|
||||
void Unlock();
|
||||
void Unlock() &&;
|
||||
|
||||
BorrowedFixupBuffer(const BorrowedFixupBuffer&) = delete;
|
||||
BorrowedFixupBuffer& operator=(const BorrowedFixupBuffer&) = delete;
|
||||
|
||||
Reference in New Issue
Block a user