Kaynağa Gözat

Merged PR 129185: [MERGE #5297 @VSadov] Adding telemetry for pinned objects and closed script contexts

[MERGE #5297 @VSadov] Adding telemetry for pinned objects and closed script contexts

Cherry-picked from commit `ea9a1d6d`.
Mike Kaufman 7 yıl önce
ebeveyn
işleme
08b23563d9

+ 16 - 0
lib/Common/Exceptions/ReportError.cpp

@@ -157,4 +157,20 @@ _NOINLINE void MemGCSingleAllocationLimit_unrecoverable_error()
     ReportFatalException(NULL, E_OUTOFMEMORY, Fatal_OutOfMemory, scenario);
 }
 
+// same as OutOfMemory_unrecoverable_error, but with a different `scenario`
+// - just to cause separate bucketing of these failures 
+_NOINLINE void OutOfMemoryTooManyPinnedObjects_unrecoverable_error()
+{
+    int scenario = 12;
+    ReportFatalException(NULL, E_OUTOFMEMORY, Fatal_OutOfMemory, scenario);
+}
+
+// same as OutOfMemory_unrecoverable_error, but with a different `scenario`
+// - just to cause separate bucketing of these failures 
+_NOINLINE void OutOfMemoryTooManyClosedContexts_unrecoverable_error()
+{
+    int scenario = 13;
+    ReportFatalException(NULL, E_OUTOFMEMORY, Fatal_OutOfMemory, scenario);
+}
+
 #pragma optimize("",on)

+ 2 - 0
lib/Common/Exceptions/ReportError.h

@@ -76,6 +76,8 @@ void RpcFailure_unrecoverable_error(HRESULT hr);
 void OutOfMemory_unrecoverable_error();
 void RecyclerSingleAllocationLimit_unrecoverable_error();
 void MemGCSingleAllocationLimit_unrecoverable_error();
+void OutOfMemoryTooManyPinnedObjects_unrecoverable_error();
+void OutOfMemoryTooManyClosedContexts_unrecoverable_error();
 
 #ifndef DISABLE_SEH
 // RtlReportException is available on Vista and up, but we cannot use it for OOB release.

+ 7 - 6
lib/Common/Memory/AllocationPolicyManager.h

@@ -134,16 +134,17 @@ private:
         if (newCurrentMemory < currentMemory ||
             newCurrentMemory > memoryLimit ||
             (memoryAllocationCallback != NULL && !memoryAllocationCallback(context, MemoryAllocateEvent::MemoryAllocate, byteCount)))
-        {
-            if (memoryAllocationCallback != NULL)
-            {
-                memoryAllocationCallback(context, MemoryAllocateEvent::MemoryFailure, byteCount);
-            }
-            
+        {            
             // oopjit number allocator allocated pages, we can't stop it from allocating so just increase the usage number
             if (externalAlloc)
             {
                 currentMemory = newCurrentMemory;
+                return true;
+            }
+
+            if (memoryAllocationCallback != NULL)
+            {
+                memoryAllocationCallback(context, MemoryAllocateEvent::MemoryFailure, byteCount);
             }
 
             return false;

+ 2 - 0
lib/Common/Memory/Recycler.h

@@ -1146,6 +1146,8 @@ public:
 #ifdef NTBUILD
     void SetTelemetryBlock(RecyclerWatsonTelemetryBlock * telemetryBlock) { this->telemetryBlock = telemetryBlock; }
 #endif
+    
+    uint GetPinnedObjectCount() const { return this->pinnedObjectMap.Count(); }
 
     void Prime();
     void* GetOwnerContext() { return (void*) this->collectionWrapper; }

+ 4 - 0
lib/Common/Memory/RecyclerTelemetryInfo.cpp

@@ -138,6 +138,8 @@ namespace Memory
                 {
                     LPFILETIME ft = this->hostInterface->GetLastScriptExecutionEndTime();
                     stats->lastScriptExecutionEndTime = *ft;
+
+                    stats->closedContextCount = this->hostInterface->GetClosedContextCount();
                 }
 
                 stats->processCommittedBytes_start = RecyclerTelemetryInfo::GetProcessCommittedBytes();
@@ -152,6 +154,8 @@ namespace Memory
                 this->FillInSizeData(this->recycler->GetHeapInfo()->GetRecyclerWithBarrierPageAllocator(), &stats->recyclerWithBarrierPageAllocator_start);
 #endif
                 stats->startPassProcessingElapsedTime = Js::Tick::Now() - start;
+
+                stats->pinnedObjectCount = this->recycler->pinnedObjectMap.Count();
             }
         }
     }

+ 3 - 0
lib/Common/Memory/RecyclerTelemetryInfo.h

@@ -33,6 +33,7 @@ namespace Memory
         virtual bool IsTelemetryProviderEnabled() const = 0;
         virtual bool IsThreadBound() const = 0;
         virtual DWORD GetCurrentScriptThreadID() const = 0;
+        virtual uint GetClosedContextCount() const = 0;
     };
 
 #ifdef ENABLE_BASIC_TELEMETRY
@@ -61,6 +62,8 @@ namespace Memory
         bool isInScript;
         bool isScriptActive;
         bool isGCPassActive;
+        uint closedContextCount;
+        uint pinnedObjectCount;
 
         size_t processAllocaterUsedBytes_start;
         size_t processAllocaterUsedBytes_end;

+ 4 - 0
lib/Runtime/Base/ScriptContext.cpp

@@ -569,6 +569,9 @@ namespace Js
         }
 #endif
 
+        Assert(this->IsActuallyClosed());
+        this->GetThreadContext()->closedScriptContextCount--;
+
         PERF_COUNTER_DEC(Basic, ScriptContext);
     }
 
@@ -617,6 +620,7 @@ namespace Js
     void ScriptContext::InternalClose()
     {
         isScriptContextActuallyClosed = true;
+        this->GetThreadContext()->closedScriptContextCount++;
 
         PERF_COUNTER_DEC(Basic, ScriptContextActive);
 

+ 6 - 0
lib/Runtime/Base/ThreadContext.cpp

@@ -212,6 +212,7 @@ ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager,
     , recyclerTelemetryHostInterface(this)
     , reentrancySafeOrHandled(false)
     , isInReentrancySafeRegion(false)
+    , closedScriptContextCount(0)
 {
     pendingProjectionContextCloseList = JsUtil::List<IProjectionContext*, ArenaAllocator>::New(GetThreadAlloc());
     hostScriptContextStack = Anew(GetThreadAlloc(), JsUtil::Stack<HostScriptContext*>, GetThreadAlloc());
@@ -720,6 +721,11 @@ DWORD ThreadContext::ThreadContextRecyclerTelemetryHostInterface::GetCurrentScri
     return this->tc->GetCurrentThreadId();
 }
 
+uint ThreadContext::ThreadContextRecyclerTelemetryHostInterface::GetClosedContextCount() const
+{
+    return this->tc->closedScriptContextCount;
+}
+
 Recycler* ThreadContext::EnsureRecycler()
 {
     if (recycler == NULL)

+ 7 - 1
lib/Runtime/Base/ThreadContext.h

@@ -622,7 +622,7 @@ private:
     bool reentrancySafeOrHandled;
     bool isInReentrancySafeRegion;
 
-    AllocationPolicyManager * allocationPolicyManager;
+    AllocationPolicyManager * allocationPolicyManager; 
 
     JsUtil::ThreadService threadService;
 #if ENABLE_NATIVE_CODEGEN
@@ -856,6 +856,11 @@ public:
 
     AllocationPolicyManager * GetAllocationPolicyManager() { return allocationPolicyManager; }
 
+    // used for diagnosing abnormally high number of closed, but still formally reachable script contexts
+    // at the time of failfast due to allocation limits.
+    // high number may indicate that context leaks have occured.
+    uint closedScriptContextCount;
+
 #if ENABLE_NATIVE_CODEGEN
     PreReservedVirtualAllocWrapper * GetPreReservedVirtualAllocator() { return &preReservedVirtualAllocator; }
 #if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
@@ -1879,6 +1884,7 @@ private:
         virtual bool ThreadContextRecyclerTelemetryHostInterface::IsThreadBound() const;
         virtual DWORD ThreadContextRecyclerTelemetryHostInterface::GetCurrentScriptThreadID() const;
         virtual bool IsTelemetryProviderEnabled() const;
+        virtual uint GetClosedContextCount() const;
 
     private:
         ThreadContext * tc;