Skip to content

Commit 949e242

Browse files
Tidy up implementation.
1 parent d50a0ba commit 949e242

File tree

4 files changed

+95
-109
lines changed

4 files changed

+95
-109
lines changed

ext/memory/profiler/allocations.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,30 @@
66
#include "ruby.h"
77
#include "ruby/st.h"
88

9-
// Per-class allocation tracking record
9+
// Per-class allocation tracking record:
1010
struct Memory_Profiler_Capture_Allocations {
11-
VALUE callback; // Optional Ruby proc/lambda to call on allocation
12-
size_t new_count; // Total allocations seen since tracking started
13-
size_t free_count; // Total frees seen since tracking started
14-
// Live count = new_count - free_count
11+
// Optional Ruby proc/lambda to call on allocation.
12+
VALUE callback;
13+
14+
// Total allocations seen since tracking started.
15+
size_t new_count;
16+
// // Total frees seen since tracking started.
17+
size_t free_count;
18+
// Live count = new_count - free_count.
1519

16-
// For detailed tracking: map object (VALUE) => state (VALUE)
17-
// State is returned from callback on :newobj and passed back on :freeobj
20+
// For detailed tracking: map object (VALUE) => state (VALUE).
21+
// State is returned from callback on `newobj` and passed back on `freeobj`.
1822
st_table *object_states;
1923
};
2024

21-
// Wrap an allocations record in a VALUE
25+
// Wrap an allocations record in a VALUE.
2226
VALUE Memory_Profiler_Allocations_wrap(struct Memory_Profiler_Capture_Allocations *record);
2327

24-
// Get allocations record from wrapper VALUE
28+
// Get allocations record from wrapper VALUE.
2529
struct Memory_Profiler_Capture_Allocations* Memory_Profiler_Allocations_get(VALUE self);
2630

27-
// Clear/reset allocation counts and state for a record
31+
// Clear/reset allocation counts and state for a record.
2832
void Memory_Profiler_Allocations_clear(VALUE allocations);
2933

30-
// Initialize the Allocations class
34+
// Initialize the Allocations class.
3135
void Init_Memory_Profiler_Allocations(VALUE Memory_Profiler);

ext/memory/profiler/capture.c

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,34 @@ enum {
1818

1919
static VALUE Memory_Profiler_Capture = Qnil;
2020

21-
// Event symbols
22-
static VALUE sym_newobj;
23-
static VALUE sym_freeobj;
21+
// Event symbols:
22+
static VALUE sym_newobj, sym_freeobj;
2423

25-
// Main capture state (per-instance)
24+
// Main capture state (per-instance).
2625
struct Memory_Profiler_Capture {
27-
// class => VALUE (wrapped Memory_Profiler_Capture_Allocations).
26+
// Tracked classes: class => VALUE (wrapped Memory_Profiler_Capture_Allocations).
2827
st_table *tracked_classes;
2928

30-
// Master switch - is tracking active? (set by start/stop)
29+
// Master switch - is tracking active? (set by start/stop).
3130
int running;
3231

33-
// Internal - should we queue callbacks? (temporarily disabled during queue processing)
32+
// Should we queue callbacks? (temporarily disabled during queue processing).
3433
int enabled;
3534
};
3635

37-
// GC mark callback for tracked_classes table
36+
// GC mark callback for tracked_classes table.
3837
static int Memory_Profiler_Capture_tracked_classes_mark(st_data_t key, st_data_t value, st_data_t arg) {
39-
// Mark class as un-movable as we don't want it moving in freeobj.
38+
// Mark class as un-movable:
4039
VALUE klass = (VALUE)key;
4140
rb_gc_mark(klass);
4241

43-
// Mark the wrapped Allocations VALUE (its own mark function will handle internal refs)
42+
// Mark the wrapped Allocations VALUE:
4443
VALUE allocations = (VALUE)value;
4544
rb_gc_mark_movable(allocations);
4645

4746
return ST_CONTINUE;
4847
}
4948

50-
// GC mark function
5149
static void Memory_Profiler_Capture_mark(void *ptr) {
5250
struct Memory_Profiler_Capture *capture = ptr;
5351

@@ -56,7 +54,6 @@ static void Memory_Profiler_Capture_mark(void *ptr) {
5654
}
5755
}
5856

59-
// GC free function
6057
static void Memory_Profiler_Capture_free(void *ptr) {
6158
struct Memory_Profiler_Capture *capture = ptr;
6259

@@ -67,7 +64,6 @@ static void Memory_Profiler_Capture_free(void *ptr) {
6764
xfree(capture);
6865
}
6966

70-
// GC memsize function
7167
static size_t Memory_Profiler_Capture_memsize(const void *ptr) {
7268
const struct Memory_Profiler_Capture *capture = ptr;
7369
size_t size = sizeof(struct Memory_Profiler_Capture);
@@ -79,22 +75,21 @@ static size_t Memory_Profiler_Capture_memsize(const void *ptr) {
7975
return size;
8076
}
8177

82-
// Foreach callback for st_foreach_with_replace (iteration logic)
78+
// Foreach callback for st_foreach_with_replace (iteration logic).
8379
static int Memory_Profiler_Capture_tracked_classes_foreach(st_data_t key, st_data_t value, st_data_t argp, int error) {
84-
// Return ST_REPLACE to trigger the replace callback for each entry
8580
return ST_REPLACE;
8681
}
8782

88-
// Replace callback for st_foreach_with_replace (update logic)
83+
// Replace callback for st_foreach_with_replace (update logic).
8984
static int Memory_Profiler_Capture_tracked_classes_update(st_data_t *key, st_data_t *value, st_data_t argp, int existing) {
90-
// Update class key if it moved
85+
// Update class key if it moved:
9186
VALUE old_klass = (VALUE)*key;
9287
VALUE new_klass = rb_gc_location(old_klass);
9388
if (old_klass != new_klass) {
9489
*key = (st_data_t)new_klass;
9590
}
9691

97-
// Update wrapped Allocations VALUE if it moved (its own compact function handles internal refs)
92+
// Update wrapped Allocations VALUE if it moved:
9893
VALUE old_allocations = (VALUE)*value;
9994
VALUE new_allocations = rb_gc_location(old_allocations);
10095
if (old_allocations != new_allocations) {
@@ -104,18 +99,15 @@ static int Memory_Profiler_Capture_tracked_classes_update(st_data_t *key, st_dat
10499
return ST_CONTINUE;
105100
}
106101

107-
// GC compact function
108102
static void Memory_Profiler_Capture_compact(void *ptr) {
109103
struct Memory_Profiler_Capture *capture = ptr;
110104

111-
// Update tracked_classes keys and allocations values in-place
105+
// Update tracked_classes keys and allocations values in-place:
112106
if (capture->tracked_classes && capture->tracked_classes->num_entries > 0) {
113107
if (st_foreach_with_replace(capture->tracked_classes, Memory_Profiler_Capture_tracked_classes_foreach, Memory_Profiler_Capture_tracked_classes_update, 0)) {
114108
rb_raise(rb_eRuntimeError, "tracked_classes modified during GC compaction");
115109
}
116110
}
117-
118-
// Global event queue is automatically compacted via its pinned TypedData object
119111
}
120112

121113
static const rb_data_type_t Memory_Profiler_Capture_type = {
@@ -147,24 +139,22 @@ const char *event_flag_name(rb_event_flag_t event_flag) {
147139
}
148140
}
149141

150-
// Internal: Process a NEWOBJ event
151-
// Handles both callback and non-callback cases, stores appropriate state
142+
// Process a NEWOBJ event. Handles both callback and non-callback cases, stores appropriate state.
152143
static void Memory_Profiler_Capture_process_newobj(VALUE capture_value, VALUE klass, VALUE allocations, VALUE object) {
153144
struct Memory_Profiler_Capture *capture;
154145
TypedData_Get_Struct(capture_value, struct Memory_Profiler_Capture, &Memory_Profiler_Capture_type, capture);
155146

156147
struct Memory_Profiler_Capture_Allocations *record = Memory_Profiler_Allocations_get(allocations);
157148

158-
// Ensure object_states table exists
149+
// Ensure object_states table exists:
159150
if (!record->object_states) {
160151
record->object_states = st_init_numtable();
161152
}
162153

163154
VALUE state;
164155

165156
if (!NIL_P(record->callback)) {
166-
// Call callback and store returned state
167-
// Temporarily disable queueing to prevent infinite loop if callback allocates
157+
// Temporarily disable queueing to prevent infinite loop:
168158
int was_enabled = capture->enabled;
169159
capture->enabled = 0;
170160

@@ -174,38 +164,35 @@ static void Memory_Profiler_Capture_process_newobj(VALUE capture_value, VALUE kl
174164

175165
if (DEBUG_STATE) fprintf(stderr, "Storing callback state for object: %p\n", (void *)object);
176166
} else {
177-
// No callback: store sentinel
178-
// Qnil = "tracked but no callback data"
167+
// No callback, store sentinel (Qnil):
179168
state = Qnil;
180169

181170
if (DEBUG_STATE) fprintf(stderr, "Storing sentinel (Qnil) for object: %p\n", (void *)object);
182171
}
183172

184-
// Always store something to maintain NEWOBJ/FREEOBJ symmetry
173+
// Always store something to maintain NEWOBJ/FREEOBJ symmetry:
185174
st_insert(record->object_states, (st_data_t)object, (st_data_t)state);
186175
}
187176

188-
// Internal: Process a FREEOBJ event
189-
// Looks up and deletes state, optionally calls callback
177+
// Process a FREEOBJ event. Looks up and deletes state, optionally calls callback.
190178
static void Memory_Profiler_Capture_process_freeobj(VALUE capture_value, VALUE klass, VALUE allocations, VALUE object) {
191179
struct Memory_Profiler_Capture *capture;
192180
TypedData_Get_Struct(capture_value, struct Memory_Profiler_Capture, &Memory_Profiler_Capture_type, capture);
193181

194182
struct Memory_Profiler_Capture_Allocations *record = Memory_Profiler_Allocations_get(allocations);
195183

196-
// Try to look up and delete state
184+
// Try to look up and delete state:
197185
if (record->object_states) {
198186
st_data_t state_data;
199187
if (st_delete(record->object_states, (st_data_t *)&object, &state_data)) {
200188
VALUE state = (VALUE)state_data;
201189

202-
// Found state - object was allocated during our tracking session
203190
if (DEBUG_STATE) fprintf(stderr, "Freed tracked object: %p, state=%s\n",
204191
(void *)object, NIL_P(state) ? "Qnil (sentinel)" : "real state");
205192

206-
// Only call callback if we have both callback AND real state (not Qnil sentinel)
193+
// Only call callback if we have both callback AND real state (not Qnil sentinel):
207194
if (!NIL_P(record->callback) && !NIL_P(state)) {
208-
// Temporarily disable queueing to prevent infinite loop if callback allocates
195+
// Temporarily disable queueing to prevent infinite loop:
209196
int was_enabled = capture->enabled;
210197
capture->enabled = 0;
211198

@@ -214,14 +201,12 @@ static void Memory_Profiler_Capture_process_freeobj(VALUE capture_value, VALUE k
214201
capture->enabled = was_enabled;
215202
}
216203
} else {
217-
// State not found - object allocated before tracking started
218204
if (DEBUG_STATE) fprintf(stderr, "Freed pre-existing object: %p (not tracked)\n", (void *)object);
219205
}
220206
}
221207
}
222208

223-
// Public API: Process a single event (NEWOBJ or FREEOBJ)
224-
// Called from events.c via rb_protect to catch exceptions
209+
// Process a single event (NEWOBJ or FREEOBJ). Called from events.c via rb_protect to catch exceptions.
225210
void Memory_Profiler_Capture_process_event(struct Memory_Profiler_Event *event) {
226211
switch (event->type) {
227212
case MEMORY_PROFILER_EVENT_TYPE_NEWOBJ:
@@ -235,19 +220,18 @@ void Memory_Profiler_Capture_process_event(struct Memory_Profiler_Event *event)
235220

236221
#pragma mark - Event Handlers
237222

238-
// Handler for NEWOBJ event - increment count and enqueue
239-
// Automatically tracks ALL allocations (creates records on demand)
223+
// NEWOBJ event handler. Automatically tracks ALL allocations (creates records on demand).
240224
static void Memory_Profiler_Capture_newobj_handler(VALUE self, struct Memory_Profiler_Capture *capture, VALUE klass, VALUE object) {
241225
st_data_t allocations_data;
242226
VALUE allocations;
243227

244228
if (st_lookup(capture->tracked_classes, (st_data_t)klass, &allocations_data)) {
245-
// Existing record - increment count
229+
// Existing record, increment count:
246230
allocations = (VALUE)allocations_data;
247231
struct Memory_Profiler_Capture_Allocations *record = Memory_Profiler_Allocations_get(allocations);
248232
record->new_count++;
249233
} else {
250-
// First time seeing this class - create record automatically
234+
// First time seeing this class, create record automatically:
251235
struct Memory_Profiler_Capture_Allocations *record = ALLOC(struct Memory_Profiler_Capture_Allocations);
252236
record->callback = Qnil;
253237
record->new_count = 1;
@@ -260,28 +244,25 @@ static void Memory_Profiler_Capture_newobj_handler(VALUE self, struct Memory_Pro
260244
RB_OBJ_WRITTEN(self, Qnil, allocations);
261245
}
262246

263-
// Enqueue to global event queue
247+
// Enqueue to global event queue:
264248
Memory_Profiler_Events_enqueue(MEMORY_PROFILER_EVENT_TYPE_NEWOBJ, self, klass, allocations, object);
265249
}
266250

267-
// Handler for FREEOBJ event - increment count and enqueue
268-
// Simple: just count + enqueue, all logic is in queue processing
251+
// FREEOBJ event handler. Increments count and enqueues for processing.
269252
static void Memory_Profiler_Capture_freeobj_handler(VALUE self, struct Memory_Profiler_Capture *capture, VALUE klass, VALUE object) {
270253
st_data_t allocations_data;
271254
if (st_lookup(capture->tracked_classes, (st_data_t)klass, &allocations_data)) {
272255
VALUE allocations = (VALUE)allocations_data;
273256
struct Memory_Profiler_Capture_Allocations *record = Memory_Profiler_Allocations_get(allocations);
274257

275-
// Always track counts
276258
record->free_count++;
277259

278-
// Enqueue to global event queue
260+
// Enqueue to global event queue:
279261
Memory_Profiler_Events_enqueue(MEMORY_PROFILER_EVENT_TYPE_FREEOBJ, self, klass, allocations, object);
280262
}
281263
}
282264

283-
// Check if object type is trackable (has valid class pointer and is a normal Ruby object)
284-
// Excludes internal types (T_IMEMO, T_NODE, T_ICLASS, etc.) that don't have normal classes
265+
// Check if object type is trackable. Excludes internal types (T_IMEMO, T_NODE, T_ICLASS, etc.) that don't have normal classes.
285266
int Memory_Profiler_Capture_trackable_p(VALUE object) {
286267
switch (rb_type(object)) {
287268
// Normal Ruby objects with valid class pointers

ext/memory/profiler/capture.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55

66
#include <ruby.h>
77

8-
// Initialize the Capture module
8+
// Initialize the Capture module.
99
void Init_Memory_Profiler_Capture(VALUE Memory_Profiler);
1010

11-
// Forward declaration
11+
// Forward declaration.
1212
struct Memory_Profiler_Event;
1313

14-
// Process a single event (NEWOBJ or FREEOBJ)
15-
// Called from the global event queue processor
16-
// This is wrapped with rb_protect to catch exceptions
14+
// Process a single event. Called from the global event queue processor.
15+
// This is wrapped with rb_protect to catch exceptions.
1716
void Memory_Profiler_Capture_process_event(struct Memory_Profiler_Event *event);

0 commit comments

Comments
 (0)