Skip to content

Commit 0995390

Browse files
committed
feat(counters): track DICTIONARY_PAGES/BYTES for SBTable allocations
StringDictionaryBuffer now maintains DICTIONARY_PAGES and DICTIONARY_BYTES counters alongside the existing DICTIONARY_KEYS/KEYS_BYTES metrics: - initCounters(offset): called by StringDictionary ctor for each buffer; counts the root SBTable that was already allocated at construction time. - insert_with_id: increments on CAS-winning overflow SBTable allocation. - clear(): decrements by the number of overflow nodes freed (root stays). This restores the memory-footprint observability that Dictionary provided via Counters::increment(DICTIONARY_PAGES/BYTES) without changing StringDictionary's correctness or signal-safety properties.
1 parent 2a8c230 commit 0995390

1 file changed

Lines changed: 34 additions & 6 deletions

File tree

ddprof-lib/src/main/cpp/stringDictionary.h

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class StringDictionaryBuffer {
153153
SBTable* _table;
154154
std::atomic<int> _size{0};
155155
StringArena _arena;
156+
int _counter_offset{0}; // 0 = no page/byte tracking
156157

157158
static unsigned int hash(const char* key, size_t length) {
158159
unsigned int h = 2166136261U;
@@ -165,22 +166,24 @@ class StringDictionaryBuffer {
165166
}
166167

167168
// Free only overflow SBTable chain nodes (not key strings — arena-owned).
168-
// Same DFS traversal as the old freeTable but without the per-key free.
169-
static void freeOverflowNodes(SBTable* table) {
169+
// Returns the number of overflow nodes freed (excludes the root table).
170+
static int freeOverflowNodes(SBTable* table) {
170171
struct Frame { SBTable* t; int row; };
171172
Frame stk[34];
172173
int top = 0;
174+
int freed = 0;
173175
stk[top++] = {table, 0};
174176
while (top > 0) {
175177
Frame& f = stk[top - 1];
176178
if (f.row >= ROWS) {
177-
if (f.t != table) free(f.t);
179+
if (f.t != table) { free(f.t); freed++; }
178180
--top;
179181
continue;
180182
}
181183
SBRow* row = &f.t->rows[f.row++];
182184
if (row->next && top < 34) stk[top++] = {row->next, 0};
183185
}
186+
return freed;
184187
}
185188

186189
static void collectTable(const SBTable* table,
@@ -223,6 +226,16 @@ class StringDictionaryBuffer {
223226
StringDictionaryBuffer(StringDictionaryBuffer&&) = delete;
224227
StringDictionaryBuffer& operator=(StringDictionaryBuffer&&) = delete;
225228

229+
// Enable DICTIONARY_PAGES / DICTIONARY_BYTES tracking for this buffer.
230+
// Called by StringDictionary after construction; counts the root SBTable.
231+
void initCounters(int offset) {
232+
_counter_offset = offset;
233+
if (_table != nullptr) {
234+
Counters::increment(DICTIONARY_PAGES, 1, offset);
235+
Counters::increment(DICTIONARY_BYTES, (long long)sizeof(SBTable), offset);
236+
}
237+
}
238+
226239
// Signal-safe read-only probe. Returns 0 on miss.
227240
u32 lookup(const char* key, size_t len) const {
228241
const SBTable* table = _table;
@@ -274,7 +287,12 @@ class StringDictionaryBuffer {
274287
if (!row->next) {
275288
SBTable* nt = static_cast<SBTable*>(calloc(1, sizeof(SBTable)));
276289
if (nt == nullptr) return 0;
277-
if (!__sync_bool_compare_and_swap(&row->next, nullptr, nt)) free(nt);
290+
if (!__sync_bool_compare_and_swap(&row->next, nullptr, nt)) {
291+
free(nt);
292+
} else if (_counter_offset != 0) {
293+
Counters::increment(DICTIONARY_PAGES, 1, _counter_offset);
294+
Counters::increment(DICTIONARY_BYTES, (long long)sizeof(SBTable), _counter_offset);
295+
}
278296
}
279297
table = __atomic_load_n(&row->next, __ATOMIC_ACQUIRE);
280298
h = (h >> ROW_BITS) | (h << (32 - ROW_BITS));
@@ -300,10 +318,14 @@ class StringDictionaryBuffer {
300318
// Call only with no concurrent accessors.
301319
void clear() {
302320
if (_table == nullptr) { _size.store(0, std::memory_order_relaxed); return; }
303-
freeOverflowNodes(_table);
321+
int freed = freeOverflowNodes(_table);
304322
memset(_table, 0, sizeof(SBTable));
305323
_arena.reset();
306324
_size.store(0, std::memory_order_relaxed);
325+
if (_counter_offset != 0 && freed > 0) {
326+
Counters::decrement(DICTIONARY_PAGES, freed, _counter_offset);
327+
Counters::decrement(DICTIONARY_BYTES, (long long)(freed * sizeof(SBTable)), _counter_offset);
328+
}
307329
}
308330

309331
int size() const { return _size.load(std::memory_order_relaxed); }
@@ -355,7 +377,13 @@ class StringDictionary {
355377

356378
public:
357379
explicit StringDictionary(int counter_offset = 0)
358-
: _rot(&_a, &_b, &_c), _counter_offset(counter_offset) {}
380+
: _rot(&_a, &_b, &_c), _counter_offset(counter_offset) {
381+
if (counter_offset != 0) {
382+
_a.initCounters(counter_offset);
383+
_b.initCounters(counter_offset);
384+
_c.initCounters(counter_offset);
385+
}
386+
}
359387

360388
// Insert into active buffer; returns globally stable id. NOT signal-safe.
361389
u32 lookup(const char* key, size_t len) {

0 commit comments

Comments
 (0)