From 633b20c3de5a030dd4629d6fa35c516f8560d816 Mon Sep 17 00:00:00 2001 From: Mukul Sabharwal Date: Mon, 6 May 2019 20:53:14 -0700 Subject: [PATCH] Add option to only notify profiler of LOH allocations (#24291) --- src/inc/corprof.idl | 9 ++++++++- src/inc/profilepriv.inl | 15 ++++++++++++++ src/pal/prebuilt/inc/corprof.h | 13 ++++++++++++- src/vm/eeprofinterfaces.inl | 9 +++++++++ src/vm/gchelpers.cpp | 25 ++++++++++++++++++------ src/vm/proftoeeinterfaceimpl.cpp | 42 +++++++++++++++++++++++++++++++++++++++- src/vm/proftoeeinterfaceimpl.h | 2 ++ 7 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/inc/corprof.idl b/src/inc/corprof.idl index b34fd31..fa1dfe8 100644 --- a/src/inc/corprof.idl +++ b/src/inc/corprof.idl @@ -634,10 +634,14 @@ typedef enum COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0, + // Enables the large object allocation monitoring according to the LOH threshold. + COR_PRF_HIGH_MONITOR_LARGEOBJECT_ALLOCATED = 0x00000040, + COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED | COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS | COR_PRF_HIGH_BASIC_GC | - COR_PRF_HIGH_MONITOR_GC_MOVED_OBJECTS, + COR_PRF_HIGH_MONITOR_GC_MOVED_OBJECTS | + COR_PRF_HIGH_MONITOR_LARGEOBJECT_ALLOCATED, // MONITOR_IMMUTABLE represents all flags that may only be set during initialization. // Trying to change any of these flags elsewhere will result in a @@ -3932,6 +3936,9 @@ interface ICorProfilerInfo10 : ICorProfilerInfo9 // Given an ObjectID, determines whether it is in a read only segment. HRESULT IsFrozenObject(ObjectID objectId, BOOL *pbFrozen); + + // Gets the value of the configured LOH Threshold. + HRESULT GetLOHObjectSizeThreshold(DWORD *pThreshold); } /* diff --git a/src/inc/profilepriv.inl b/src/inc/profilepriv.inl index 413090f..9126241 100644 --- a/src/inc/profilepriv.inl +++ b/src/inc/profilepriv.inl @@ -264,6 +264,21 @@ inline BOOL CORProfilerTrackAllocations() ((&g_profControlBlock)->dwEventMask & COR_PRF_MONITOR_OBJECT_ALLOCATED)); } +inline BOOL CORProfilerTrackLargeAllocations() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + CANNOT_TAKE_LOCK; + } + CONTRACTL_END; + + return + (CORProfilerPresent() && + ((&g_profControlBlock)->dwEventMaskHigh & COR_PRF_HIGH_MONITOR_LARGEOBJECT_ALLOCATED)); +} + inline BOOL CORProfilerEnableRejit() { CONTRACTL diff --git a/src/pal/prebuilt/inc/corprof.h b/src/pal/prebuilt/inc/corprof.h index 0963b03..9edfc35 100644 --- a/src/pal/prebuilt/inc/corprof.h +++ b/src/pal/prebuilt/inc/corprof.h @@ -547,7 +547,8 @@ enum __MIDL___MIDL_itf_corprof_0000_0000_0006 COR_PRF_HIGH_BASIC_GC = 0x10, COR_PRF_HIGH_MONITOR_GC_MOVED_OBJECTS = 0x20, COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0, - COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = ( ( ( COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED | COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS ) | COR_PRF_HIGH_BASIC_GC ) | COR_PRF_HIGH_MONITOR_GC_MOVED_OBJECTS ) , + COR_PRF_HIGH_MONITOR_LARGEOBJECT_ALLOCATED = 0x40, + COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = ( ( ( ( COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED | COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS ) | COR_PRF_HIGH_BASIC_GC ) | COR_PRF_HIGH_MONITOR_GC_MOVED_OBJECTS ) | COR_PRF_HIGH_MONITOR_LARGEOBJECT_ALLOCATED ) , COR_PRF_HIGH_MONITOR_IMMUTABLE = COR_PRF_HIGH_DISABLE_TIERED_COMPILATION } COR_PRF_HIGH_MONITOR; @@ -15195,6 +15196,9 @@ EXTERN_C const IID IID_ICorProfilerInfo10; ObjectID objectId, BOOL *pbFrozen) = 0; + virtual HRESULT STDMETHODCALLTYPE GetLOHObjectSizeThreshold( + DWORD *pThreshold) = 0; + }; @@ -15793,6 +15797,10 @@ EXTERN_C const IID IID_ICorProfilerInfo10; ObjectID objectId, BOOL *pbFrozen); + HRESULT ( STDMETHODCALLTYPE *GetLOHObjectSizeThreshold )( + ICorProfilerInfo10 * This, + DWORD *pThreshold); + END_INTERFACE } ICorProfilerInfo10Vtbl; @@ -16101,6 +16109,9 @@ EXTERN_C const IID IID_ICorProfilerInfo10; #define ICorProfilerInfo10_IsFrozenObject(This,objectId,pbFrozen) \ ( (This)->lpVtbl -> IsFrozenObject(This,objectId,pbFrozen) ) +#define ICorProfilerInfo10_GetLOHObjectSizeThreshold(This,pThreshold) \ + ( (This)->lpVtbl -> GetLOHObjectSizeThreshold(This,pThreshold) ) + #endif /* COBJMACROS */ diff --git a/src/vm/eeprofinterfaces.inl b/src/vm/eeprofinterfaces.inl index a080002..ea29ede 100644 --- a/src/vm/eeprofinterfaces.inl +++ b/src/vm/eeprofinterfaces.inl @@ -23,5 +23,14 @@ FORCEINLINE BOOL TrackAllocations() #endif // PROFILING_SUPPORTED } +FORCEINLINE BOOL TrackLargeAllocations() +{ +#ifdef PROFILING_SUPPORTED + return CORProfilerTrackLargeAllocations(); +#else + return FALSE; +#endif // PROFILING_SUPPORTED +} + #endif diff --git a/src/vm/gchelpers.cpp b/src/vm/gchelpers.cpp index 8cb4fee..22a1a5d 100644 --- a/src/vm/gchelpers.cpp +++ b/src/vm/gchelpers.cpp @@ -542,10 +542,13 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS // Initialize Object orArray->m_NumComponents = cElements; + bool bProfilerNotifyLargeAllocation = false; + if (bAllocateInLargeHeap || (totalSize >= g_pConfig->GetGCLOHThreshold())) { GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orArray); + bProfilerNotifyLargeAllocation = TrackLargeAllocations(); } #ifdef _LOGALLOC @@ -566,7 +569,7 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS // Notify the profiler of the allocation // do this after initializing bounds so callback has size information - if (TrackAllocations()) + if (TrackAllocations() || bProfilerNotifyLargeAllocation) { ProfileTrackArrayAlloc(orArray); } @@ -768,10 +771,13 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, // Initialize Object orArray->m_NumComponents = cElements; + bool bProfilerNotifyLargeAllocation = false; + if (bAllocateInLargeHeap || (totalSize >= g_pConfig->GetGCLOHThreshold())) { GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orArray); + bProfilerNotifyLargeAllocation = TrackLargeAllocations(); } #ifdef _LOGALLOC @@ -804,7 +810,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, // Notify the profiler of the allocation // do this after initializing bounds so callback has size information - if (TrackAllocations()) + if (TrackAllocations() || bProfilerNotifyLargeAllocation) { ProfileTrackArrayAlloc(orArray); } @@ -988,13 +994,15 @@ STRINGREF AllocateString( DWORD cchStringLength ) orObject->SetMethodTable( g_pStringClass ); orObject->SetStringLength( cchStringLength ); + bool bProfilerNotifyLargeAllocation = false; if (ObjectSize >= g_pConfig->GetGCLOHThreshold()) { + bProfilerNotifyLargeAllocation = TrackLargeAllocations(); GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); } // Notify the profiler of the allocation - if (TrackAllocations()) + if (TrackAllocations() || bProfilerNotifyLargeAllocation) { OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); GCPROTECT_BEGIN(objref); @@ -1062,13 +1070,16 @@ UTF8STRINGREF AllocateUtf8String(DWORD cchStringLength) orObject->SetMethodTable(g_pUtf8StringClass); orObject->SetLength(cchStringLength); - if (ObjectSize >= LARGE_OBJECT_SIZE) + bool bProfilerNotifyLargeAllocation = false; + + if (ObjectSize >= g_pConfig->GetGCLOHThreshold()) { GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); + bProfilerNotifyLargeAllocation = TrackLargeAllocations(); } // Notify the profiler of the allocation - if (TrackAllocations()) + if (TrackAllocations() || bProfilerNotifyLargeAllocation) { OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); GCPROTECT_BEGIN(objref); @@ -1192,9 +1203,11 @@ OBJECTREF AllocateObject(MethodTable *pMT // verify zero'd memory (at least for sync block) _ASSERTE( orObject->HasEmptySyncBlockInfo() ); + bool bProfilerNotifyLargeAllocation = false; if ((baseSize >= g_pConfig->GetGCLOHThreshold())) { orObject->SetMethodTableForLargeObject(pMT); + bProfilerNotifyLargeAllocation = TrackLargeAllocations(); GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); } else @@ -1203,7 +1216,7 @@ OBJECTREF AllocateObject(MethodTable *pMT } // Notify the profiler of the allocation - if (TrackAllocations()) + if (TrackAllocations() || bProfilerNotifyLargeAllocation) { OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); GCPROTECT_BEGIN(objref); diff --git a/src/vm/proftoeeinterfaceimpl.cpp b/src/vm/proftoeeinterfaceimpl.cpp index 467ab29..b5ade59 100644 --- a/src/vm/proftoeeinterfaceimpl.cpp +++ b/src/vm/proftoeeinterfaceimpl.cpp @@ -649,7 +649,7 @@ void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId // Notify the profiler of the allocation { - BEGIN_PIN_PROFILER(CORProfilerTrackAllocations()); + BEGIN_PIN_PROFILER(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations()); // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs. // Thus we strip any instantiations of the ClassID (which is really a type handle) here. g_profControlBlock.pProfInterface->ObjectAllocated( @@ -6893,6 +6893,46 @@ HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen) } /* + * GetLOHObjectSizeThreshold + * + * Gets the value of the configured LOH Threshold. + * + * Parameters: + * pThreshold - value of the threshold in bytes + * + * Returns: + * S_OK if successful + * + */ +HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + EE_THREAD_NOT_REQUIRED; + CANNOT_TAKE_LOCK; + } + CONTRACTL_END; + + PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX( + kP2EEAllowableAfterAttach, + (LF_CORPROF, + LL_INFO1000, + "**PROF: GetLOHObjectSizeThreshold\n")); + + if (pThreshold == nullptr) + { + return E_INVALIDARG; + } + + *pThreshold = g_pConfig->GetGCLOHThreshold(); + + return S_OK; +} + +/* * GetStringLayout * * This function describes to a profiler the internal layout of a string. diff --git a/src/vm/proftoeeinterfaceimpl.h b/src/vm/proftoeeinterfaceimpl.h index d41eec9..ff5e463 100644 --- a/src/vm/proftoeeinterfaceimpl.h +++ b/src/vm/proftoeeinterfaceimpl.h @@ -611,6 +611,8 @@ public: COM_METHOD IsFrozenObject(ObjectID objectId, BOOL *pbFrozen); + COM_METHOD GetLOHObjectSizeThreshold(DWORD *pThreshold); + // end ICorProfilerInfo10 protected: -- 2.7.4