@@ -472,8 +472,23 @@ impl Profile {
472472 allocation_address : u64 ,
473473 allocation_size : i64 ,
474474 ) {
475- let stack_index = self . stack_index_for_frames ( thread, frames) ;
476- self . threads [ thread. 0 ] . add_allocation_sample (
475+ // The profile format strictly separates sample data from different threads.
476+ // For allocation samples, this separation is a bit unfortunate, especially
477+ // when it comes to the "Retained Memory" panel which shows allocation stacks
478+ // for just objects that haven't been deallocated yet. This panel is per-thread,
479+ // and it needs to know about deallocations even if they happened on a different
480+ // thread from the allocation.
481+ // To resolve this conundrum, for now, we will put all allocation and deallocation
482+ // samples on a single thread per process, regardless of what thread they actually
483+ // happened on.
484+ // The Gecko profiler puts all allocation samples on the main thread, for example.
485+ // Here in fxprof-processed-profile, we just deem the first thread of each process
486+ // as the processes "allocation thread".
487+ let process_handle = self . threads [ thread. 0 ] . process ( ) ;
488+ let process = & self . processes [ process_handle. 0 ] ;
489+ let allocation_thread_handle = process. thread_handle_for_allocations ( ) . unwrap ( ) ;
490+ let stack_index = self . stack_index_for_frames ( allocation_thread_handle, frames) ;
491+ self . threads [ allocation_thread_handle. 0 ] . add_allocation_sample (
477492 timestamp,
478493 stack_index,
479494 allocation_address,
0 commit comments