Skip to content

Commit 299e9b8

Browse files
committedOct 28, 2018
[XRay] Refcount backing store for buffers
Summary: This change implements the ref-counting for backing stores associated with generational buffer management. We do this as an implementation detail of the buffer queue, instead of exposing this to the interface. This change allows us to keep the buffer queue interface and usage model the same. Depends on D53551. Reviewers: mboerger, eizan Subscribers: jfb, llvm-commits Differential Revision: https://reviews.llvm.org/D53560 llvm-svn: 345471
1 parent 704247c commit 299e9b8

File tree

2 files changed

+67
-8
lines changed

2 files changed

+67
-8
lines changed
 

‎compiler-rt/lib/xray/xray_buffer_queue.cc

+56-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515
#include "xray_buffer_queue.h"
16+
#include "sanitizer_common/sanitizer_atomic.h"
1617
#include "sanitizer_common/sanitizer_common.h"
1718
#include "sanitizer_common/sanitizer_libc.h"
1819
#include "sanitizer_common/sanitizer_posix.h"
@@ -24,23 +25,45 @@
2425
using namespace __xray;
2526
using namespace __sanitizer;
2627

28+
namespace {
29+
30+
void decRefCount(unsigned char *ControlBlock, size_t Size, size_t Count) {
31+
if (ControlBlock == nullptr)
32+
return;
33+
auto *RefCount = reinterpret_cast<atomic_uint64_t *>(ControlBlock);
34+
if (atomic_fetch_sub(RefCount, 1, memory_order_acq_rel) == 1)
35+
deallocateBuffer(ControlBlock, (Size * Count) + kCacheLineSize);
36+
}
37+
38+
void incRefCount(unsigned char *ControlBlock) {
39+
if (ControlBlock == nullptr)
40+
return;
41+
auto *RefCount = reinterpret_cast<atomic_uint64_t *>(ControlBlock);
42+
atomic_fetch_add(RefCount, 1, memory_order_acq_rel);
43+
}
44+
45+
} // namespace
46+
2747
BufferQueue::ErrorCode BufferQueue::init(size_t BS, size_t BC) {
2848
SpinMutexLock Guard(&Mutex);
2949

3050
if (!finalizing())
3151
return BufferQueue::ErrorCode::AlreadyInitialized;
3252

53+
cleanupBuffers();
54+
3355
bool Success = false;
3456
BufferSize = BS;
3557
BufferCount = BC;
36-
BackingStore = allocateBuffer(BufferSize * BufferCount);
58+
BackingStore = allocateBuffer((BufferSize * BufferCount) + kCacheLineSize);
3759
if (BackingStore == nullptr)
3860
return BufferQueue::ErrorCode::NotEnoughMemory;
3961

4062
auto CleanupBackingStore = __sanitizer::at_scope_exit([&, this] {
4163
if (Success)
4264
return;
43-
deallocateBuffer(BackingStore, BufferSize * BufferCount);
65+
deallocateBuffer(BackingStore, (BufferSize * BufferCount) + kCacheLineSize);
66+
BackingStore = nullptr;
4467
});
4568

4669
Buffers = initArray<BufferRep>(BufferCount);
@@ -52,13 +75,21 @@ BufferQueue::ErrorCode BufferQueue::init(size_t BS, size_t BC) {
5275
atomic_fetch_add(&Generation, 1, memory_order_acq_rel);
5376

5477
Success = true;
78+
79+
// First, we initialize the refcount in the RefCountedBackingStore, which we
80+
// treat as being at the start of the BackingStore pointer.
81+
auto ControlBlock = reinterpret_cast<atomic_uint64_t *>(BackingStore);
82+
atomic_store(ControlBlock, 1, memory_order_release);
83+
5584
for (size_t i = 0; i < BufferCount; ++i) {
5685
auto &T = Buffers[i];
5786
auto &Buf = T.Buff;
5887
atomic_store(&Buf.Extents, 0, memory_order_release);
5988
Buf.Generation = generation();
60-
Buf.Data = reinterpret_cast<char *>(BackingStore) + (BufferSize * i);
89+
Buf.Data = BackingStore + kCacheLineSize + (BufferSize * i);
6190
Buf.Size = BufferSize;
91+
Buf.BackingStore = BackingStore;
92+
Buf.Count = BufferCount;
6293
T.Used = false;
6394
}
6495

@@ -99,9 +130,12 @@ BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) {
99130
++LiveBuffers;
100131
}
101132

133+
incRefCount(BackingStore);
102134
Buf.Data = B->Buff.Data;
103135
Buf.Generation = generation();
104136
Buf.Size = B->Buff.Size;
137+
Buf.BackingStore = BackingStore;
138+
Buf.Count = BufferCount;
105139
B->Used = true;
106140
return ErrorCode::Ok;
107141
}
@@ -116,18 +150,24 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {
116150
Buf.Data > reinterpret_cast<char *>(BackingStore) +
117151
(BufferCount * BufferSize)) {
118152
if (Buf.Generation != generation()) {
153+
decRefCount(Buf.BackingStore, Buf.Size, Buf.Count);
119154
Buf.Data = nullptr;
120155
Buf.Size = 0;
121156
Buf.Generation = 0;
157+
Buf.Count = 0;
158+
Buf.BackingStore = nullptr;
122159
return BufferQueue::ErrorCode::Ok;
123160
}
124161
return BufferQueue::ErrorCode::UnrecognizedBuffer;
125162
}
126163

127164
if (LiveBuffers == 0) {
165+
decRefCount(Buf.BackingStore, Buf.Size, Buf.Count);
128166
Buf.Data = nullptr;
129167
Buf.Size = Buf.Size;
130168
Buf.Generation = 0;
169+
Buf.BackingStore = nullptr;
170+
Buf.Count = 0;
131171
return ErrorCode::Ok;
132172
}
133173

@@ -141,13 +181,18 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {
141181
B->Buff.Data = Buf.Data;
142182
B->Buff.Size = Buf.Size;
143183
B->Buff.Generation = Buf.Generation;
184+
B->Buff.BackingStore = Buf.BackingStore;
185+
B->Buff.Count = Buf.Count;
144186
B->Used = true;
187+
decRefCount(Buf.BackingStore, Buf.Size, Buf.Count);
145188
atomic_store(&B->Buff.Extents,
146189
atomic_load(&Buf.Extents, memory_order_acquire),
147190
memory_order_release);
148191
Buf.Data = nullptr;
149192
Buf.Size = 0;
150193
Buf.Generation = 0;
194+
Buf.BackingStore = nullptr;
195+
Buf.Count = 0;
151196
return ErrorCode::Ok;
152197
}
153198

@@ -157,9 +202,15 @@ BufferQueue::ErrorCode BufferQueue::finalize() {
157202
return ErrorCode::Ok;
158203
}
159204

160-
BufferQueue::~BufferQueue() {
205+
void BufferQueue::cleanupBuffers() {
161206
for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B)
162207
B->~BufferRep();
163208
deallocateBuffer(Buffers, BufferCount);
164-
deallocateBuffer(BackingStore, BufferSize * BufferCount);
209+
decRefCount(BackingStore, BufferSize, BufferCount);
210+
BackingStore = nullptr;
211+
Buffers = nullptr;
212+
BufferCount = 0;
213+
BufferSize = 0;
165214
}
215+
216+
BufferQueue::~BufferQueue() { cleanupBuffers(); }

‎compiler-rt/lib/xray/xray_buffer_queue.h

+11-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
namespace __xray {
2626

2727
/// BufferQueue implements a circular queue of fixed sized buffers (much like a
28-
/// freelist) but is concerned mostly with making it really quick to initialise,
29-
/// finalise, and get/return buffers to the queue. This is one key component of
30-
/// the "flight data recorder" (FDR) mode to support ongoing XRay function call
28+
/// freelist) but is concerned with making it quick to initialise, finalise, and
29+
/// get from or return buffers to the queue. This is one key component of the
30+
/// "flight data recorder" (FDR) mode to support ongoing XRay function call
3131
/// trace collection.
3232
class BufferQueue {
3333
public:
@@ -36,6 +36,11 @@ class BufferQueue {
3636
uint64_t Generation{0};
3737
void *Data = nullptr;
3838
size_t Size = 0;
39+
40+
private:
41+
friend class BufferQueue;
42+
unsigned char *BackingStore = nullptr;
43+
size_t Count = 0;
3944
};
4045

4146
struct BufferRep {
@@ -135,6 +140,9 @@ class BufferQueue {
135140
// associated with.
136141
atomic_uint64_t Generation;
137142

143+
/// Releases references to the buffers backed by the current buffer queue.
144+
void cleanupBuffers();
145+
138146
public:
139147
enum class ErrorCode : unsigned {
140148
Ok,

0 commit comments

Comments
 (0)
Please sign in to comment.