Skip to content

Commit c7141d4

Browse files
jbachorikclaude
andcommitted
Fix calltrace_storage counters accumulating across rotations
clearTableOnly() was freeing memory without decrementing the global CALLTRACE_STORAGE_BYTES/TRACES counters, causing them to grow monotonically (cumulative total ever allocated, not current live size). Add a decrement pass in clearTableOnly() using the same table iteration as collect(), computed after waitForAllRefCountsToClear() ensures no concurrent writers. Both the direct clear() path and the deferred-free processTraces() path go through clearTableOnly(), so a single fix covers both. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent f3e00b1 commit c7141d4

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

ddprof-lib/src/main/cpp/callTraceHashTable.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,29 @@ ChunkList CallTraceHashTable::clearTableOnly() {
106106
// Wait for all refcount guards to clear before detaching chunks
107107
RefCountGuard::waitForAllRefCountsToClear();
108108

109+
// Compute and decrement the global counters for everything in this table.
110+
// After waitForAllRefCountsToClear() there are no concurrent writers, so
111+
// plain iteration (same pattern as collect()) is safe.
112+
const size_t header_size = sizeof(CallTrace) - sizeof(ASGCT_CallFrame);
113+
long long freed_bytes = 0;
114+
long long freed_traces = 0;
115+
for (LongHashTable *t = _table; t != nullptr; t = t->prev()) {
116+
u64 *keys = t->keys();
117+
CallTraceSample *values = t->values();
118+
u32 capacity = t->capacity();
119+
for (u32 slot = 0; slot < capacity; slot++) {
120+
if (keys[slot] != 0) {
121+
CallTrace *trace = values[slot].acquireTrace();
122+
if (trace != nullptr && trace != CallTraceSample::PREPARING) {
123+
freed_bytes += header_size + trace->num_frames * sizeof(ASGCT_CallFrame);
124+
freed_traces++;
125+
}
126+
}
127+
}
128+
}
129+
Counters::increment(CALLTRACE_STORAGE_BYTES, -freed_bytes);
130+
Counters::increment(CALLTRACE_STORAGE_TRACES, -freed_traces);
131+
109132
// Clear previous chain pointers to prevent traversal during deallocation
110133
for (LongHashTable *table = _table; table != nullptr; table = table->prev()) {
111134
LongHashTable *prev_table = table->prev();
@@ -424,7 +447,7 @@ void CallTraceHashTable::putWithExistingId(CallTrace* source_trace, u64 weight)
424447
table->values()[slot].setTrace(copied_trace);
425448
Counters::increment(CALLTRACE_STORAGE_BYTES, total_size);
426449
Counters::increment(CALLTRACE_STORAGE_TRACES);
427-
450+
428451
// Increment table size
429452
u32 new_size = table->incSize();
430453
probe.updateCapacity(new_size);

0 commit comments

Comments
 (0)