1414enum {
1515 DEBUG = 0 ,
1616 DEBUG_FREED_QUEUE = 0 ,
17+ DEBUG_STATE = 0 ,
1718};
1819
1920static VALUE Memory_Profiler_Capture = Qnil ;
@@ -198,9 +199,7 @@ static void Memory_Profiler_Capture_process_freed_queue(void *arg) {
198199 struct Memory_Profiler_Capture * capture ;
199200 TypedData_Get_Struct (self , struct Memory_Profiler_Capture , & Memory_Profiler_Capture_type , capture );
200201
201- if (DEBUG_FREED_QUEUE ) {
202- fprintf (stderr , "Processing freed queue with %zu entries\n" , capture -> freed_queue .count );
203- }
202+ if (DEBUG_FREED_QUEUE ) fprintf (stderr , "Processing freed queue with %zu entries\n" , capture -> freed_queue .count );
204203
205204 // Process all freed objects in the queue
206205 for (size_t i = 0 ; i < capture -> freed_queue .count ; i ++ ) {
@@ -245,6 +244,9 @@ static void Memory_Profiler_Capture_newobj_handler(VALUE self, struct Memory_Pro
245244 if (!record -> object_states ) {
246245 record -> object_states = st_init_numtable ();
247246 }
247+
248+ if (DEBUG_STATE ) fprintf (stderr , "Memory_Profiler_Capture_newobj_handler: Inserting state for object: %p (%s)\n" , (void * )object , rb_class2name (klass ));
249+
248250 st_insert (record -> object_states , (st_data_t )object , (st_data_t )state );
249251 // Notify GC about the state VALUE stored in the table
250252 RB_OBJ_WRITTEN (self , Qnil , state );
@@ -281,22 +283,29 @@ static void Memory_Profiler_Capture_freeobj_handler(VALUE self, struct Memory_Pr
281283
282284 // If we have a callback and detailed tracking, queue the freeobj for later processing
283285 if (!NIL_P (record -> callback ) && record -> object_states ) {
286+ if (DEBUG_STATE ) fprintf (stderr , "Memory_Profiler_Capture_freeobj_handler: Looking up state for object: %p\n" , (void * )object );
287+
284288 // Look up state stored during NEWOBJ
285289 st_data_t state_data ;
286290 if (st_delete (record -> object_states , (st_data_t * )& object , & state_data )) {
291+ if (DEBUG_STATE ) fprintf (stderr , "Found state for object: %p\n" , (void * )object );
287292 VALUE state = (VALUE )state_data ;
288293
289294 // Push a new item onto the queue (returns pointer to write to)
290295 // NOTE: realloc is safe during GC (doesn't trigger Ruby allocation)
291296 struct Memory_Profiler_Queue_Item * freed = Memory_Profiler_Queue_push (& capture -> freed_queue );
292297 if (freed ) {
298+ if (DEBUG_FREED_QUEUE ) fprintf (stderr , "Queued freed object, queue size now: %zu/%zu\n" , capture -> freed_queue .count , capture -> freed_queue .capacity );
293299 // Write directly to the allocated space
294300 freed -> klass = klass ;
295301 freed -> allocations = allocations ;
296302 freed -> state = state ;
297303
298304 // Trigger postponed job to process the queue after GC
305+ if (DEBUG_FREED_QUEUE ) fprintf (stderr , "Triggering postponed job to process the queue after GC\n" );
299306 rb_postponed_job_trigger (capture -> postponed_job_handle );
307+ } else {
308+ if (DEBUG_FREED_QUEUE ) fprintf (stderr , "Failed to queue freed object, out of memory\n" );
300309 }
301310 // If push failed (out of memory), silently drop this freeobj event
302311 }
@@ -455,6 +464,7 @@ static VALUE Memory_Profiler_Capture_stop(VALUE self) {
455464// Add a class to track with optional callback
456465// Usage: track(klass) or track(klass) { |obj, klass| ... }
457466// Callback can call caller_locations with desired depth
467+ // Returns the Allocations object for the tracked class
458468static VALUE Memory_Profiler_Capture_track (int argc , VALUE * argv , VALUE self ) {
459469 struct Memory_Profiler_Capture * capture ;
460470 TypedData_Get_Struct (self , struct Memory_Profiler_Capture , & Memory_Profiler_Capture_type , capture );
@@ -463,8 +473,10 @@ static VALUE Memory_Profiler_Capture_track(int argc, VALUE *argv, VALUE self) {
463473 rb_scan_args (argc , argv , "1&" , & klass , & callback );
464474
465475 st_data_t allocations_data ;
476+ VALUE allocations ;
477+
466478 if (st_lookup (capture -> tracked_classes , (st_data_t )klass , & allocations_data )) {
467- VALUE allocations = (VALUE )allocations_data ;
479+ allocations = (VALUE )allocations_data ;
468480 struct Memory_Profiler_Capture_Allocations * record = Memory_Profiler_Allocations_get (allocations );
469481 RB_OBJ_WRITE (self , & record -> callback , callback );
470482 } else {
@@ -475,7 +487,7 @@ static VALUE Memory_Profiler_Capture_track(int argc, VALUE *argv, VALUE self) {
475487 record -> object_states = NULL ;
476488
477489 // Wrap the record in a VALUE
478- VALUE allocations = Memory_Profiler_Allocations_wrap (record );
490+ allocations = Memory_Profiler_Allocations_wrap (record );
479491
480492 st_insert (capture -> tracked_classes , (st_data_t )klass , (st_data_t )allocations );
481493 // Notify GC about the class VALUE stored as key in the table
@@ -488,7 +500,7 @@ static VALUE Memory_Profiler_Capture_track(int argc, VALUE *argv, VALUE self) {
488500 }
489501 }
490502
491- return self ;
503+ return allocations ;
492504}
493505
494506// Stop tracking a class
@@ -578,6 +590,19 @@ static VALUE Memory_Profiler_Capture_each(VALUE self) {
578590 return self ;
579591}
580592
593+ // Get allocations for a specific class
594+ static VALUE Memory_Profiler_Capture_aref (VALUE self , VALUE klass ) {
595+ struct Memory_Profiler_Capture * capture ;
596+ TypedData_Get_Struct (self , struct Memory_Profiler_Capture , & Memory_Profiler_Capture_type , capture );
597+
598+ st_data_t allocations_data ;
599+ if (st_lookup (capture -> tracked_classes , (st_data_t )klass , & allocations_data )) {
600+ return (VALUE )allocations_data ;
601+ }
602+
603+ return Qnil ;
604+ }
605+
581606void Init_Memory_Profiler_Capture (VALUE Memory_Profiler )
582607{
583608 // Initialize event symbols
@@ -597,6 +622,7 @@ void Init_Memory_Profiler_Capture(VALUE Memory_Profiler)
597622 rb_define_method (Memory_Profiler_Capture , "tracking?" , Memory_Profiler_Capture_tracking_p , 1 );
598623 rb_define_method (Memory_Profiler_Capture , "count_for" , Memory_Profiler_Capture_count_for , 1 );
599624 rb_define_method (Memory_Profiler_Capture , "each" , Memory_Profiler_Capture_each , 0 );
625+ rb_define_method (Memory_Profiler_Capture , "[]" , Memory_Profiler_Capture_aref , 1 );
600626 rb_define_method (Memory_Profiler_Capture , "clear" , Memory_Profiler_Capture_clear , 0 );
601627
602628 // Initialize Allocations class
0 commit comments