@@ -2365,8 +2365,8 @@ void PMTraceConsumer::CompletePresent(std::shared_ptr<PresentEvent> const& p)
23652365 static_cast <int32_t >(appFrameId - it->second .FrameId ) >= 10 ) {
23662366 // Remove the app frame data if the app frame id is too old
23672367 it = mAppTimingDataByAppFrameId .erase (it); // Erase and move to the next element
2368- } else if (appFrameId == 0 && it->second .ProcessId == processId &&
2369- it->second .AssignedToPresent == false && it->second .AppPresentStartTime != 0 &&
2368+ } else if (appFrameId == 0 && it->second .ProcessId == processId &&
2369+ it->second .AssignedToPresent == false && it->second .AppPresentStartTime != 0 &&
23702370 presentStartTime >= it->second .AppPresentStartTime &&
23712371 presentStartTime - it->second .AppPresentStartTime >= mDeferralTimeLimit ) {
23722372 // Remove app frame data if the app present start time is too old
@@ -2376,6 +2376,47 @@ void PMTraceConsumer::CompletePresent(std::shared_ptr<PresentEvent> const& p)
23762376 ++it; // Move to the next element
23772377 }
23782378 }
2379+
2380+ // Prune out old PC Latency timing data to prevent memory leaks.
2381+ // This is critical because PCL data accumulates for every frame and the
2382+ // PCLStatsShutdown event (the only other cleanup mechanism) is app-controlled.
2383+ if (mTrackPcLatency ) {
2384+ auto pclFrameId = present->PclFrameId ;
2385+ for (auto it = mPclTimingDataByPclFrameId .begin (); it != mPclTimingDataByPclFrameId .end ();) {
2386+ if (it->first .second == processId) {
2387+ // For entries from this process:
2388+ // 1. Remove if assigned and frame ID is too old (10+ frames behind)
2389+ // 2. Remove if timestamp is too old (stale data - assigned or not)
2390+ bool shouldRemove = false ;
2391+
2392+ // Get the best available timestamp for this entry
2393+ uint64_t timingValue = mUsingOutOfBoundPresentStart
2394+ ? it->second .PclOutOfBandPresentStartTime
2395+ : it->second .PclPresentStartTime ;
2396+ if (timingValue == 0 ) {
2397+ timingValue = it->second .PclSimStartTime ;
2398+ }
2399+
2400+ if (pclFrameId != 0 && it->second .AssignedToPresent &&
2401+ static_cast <int32_t >(pclFrameId - it->second .FrameId ) >= 10 ) {
2402+ // Remove assigned PCL data if frame id is too old
2403+ shouldRemove = true ;
2404+ } else if (timingValue != 0 && presentStartTime >= timingValue &&
2405+ presentStartTime - timingValue >= mDeferralTimeLimit ) {
2406+ // Remove PCL data (assigned or not) if timestamp is too old
2407+ shouldRemove = true ;
2408+ }
2409+
2410+ if (shouldRemove) {
2411+ it = mPclTimingDataByPclFrameId .erase (it);
2412+ } else {
2413+ ++it;
2414+ }
2415+ } else {
2416+ ++it;
2417+ }
2418+ }
2419+ }
23792420}
23802421
23812422void PMTraceConsumer::UpdateReadyCount (bool useLock)
@@ -2708,6 +2749,16 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord)
27082749 event.ProcessId = desc[0 ].GetData <uint32_t >();
27092750 event.IsStartEvent = false ;
27102751
2752+ // Clean up PC Latency tracking data for this process to prevent memory leaks.
2753+ // This is necessary because PCLStatsShutdown events are application-controlled
2754+ // and may not be sent if the app crashes or terminates abnormally.
2755+ if (mTrackPcLatency ) {
2756+ std::erase_if (mPclTimingDataByPclFrameId , [&event](const auto & p) {
2757+ return p.first .second == event.ProcessId ;
2758+ });
2759+ mLatestPingTimestampByProcessId .erase (event.ProcessId );
2760+ }
2761+
27112762 break ;
27122763 }
27132764 default :
@@ -2734,6 +2785,14 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord)
27342785 mMetadata .GetEventData (pEventRecord, desc, _countof (desc));
27352786 event.ProcessId = desc[0 ].GetData <uint32_t >();
27362787 event.IsStartEvent = false ;
2788+
2789+ // Clean up PC Latency tracking data for this process to prevent memory leaks.
2790+ if (mTrackPcLatency ) {
2791+ std::erase_if (mPclTimingDataByPclFrameId , [&event](const auto & p) {
2792+ return p.first .second == event.ProcessId ;
2793+ });
2794+ mLatestPingTimestampByProcessId .erase (event.ProcessId );
2795+ }
27372796 } else {
27382797 return ;
27392798 }
0 commit comments