Skip to content

Commit

Permalink
Implement ICorProfilerInfo14::GetNonGCHeapBounds (#85434)
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo authored May 2, 2023
1 parent a32df3a commit 8091325
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 4 deletions.
16 changes: 16 additions & 0 deletions src/coreclr/inc/corprof.idl
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,17 @@ typedef struct COR_PRF_GC_GENERATION_RANGE
} COR_PRF_GC_GENERATION_RANGE;


/*
* COR_PRF_NONGC_GENERATION_RANGE describes a range of memory in the GetNonGCHeapBounds function.
*/
typedef struct COR_PRF_NONGC_HEAP_RANGE
{
ObjectID rangeStart; // the start of the range
UINT_PTR rangeLength; // the used length of the range
UINT_PTR rangeLengthReserved; // the amount of memory reserved for the range (including rangeLength)

} COR_PRF_NONGC_HEAP_RANGE;


/*
* COR_PRF_CLAUSE_TYPE defines the various clause codes for the EX clauses
Expand Down Expand Up @@ -4254,6 +4265,11 @@ interface ICorProfilerInfo13 : ICorProfilerInfo12
interface ICorProfilerInfo14 : ICorProfilerInfo13
{
HRESULT EnumerateNonGCObjects([out] ICorProfilerObjectEnum** ppEnum);

HRESULT GetNonGCHeapBounds(
[in] ULONG cObjectRanges,
[out] ULONG *pcObjectRanges,
[out, size_is(cObjectRanges), length_is(*pcObjectRanges)] COR_PRF_NONGC_HEAP_RANGE ranges[]);
}

/*
Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/pal/prebuilt/inc/corprof.h
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,13 @@ typedef struct COR_PRF_GC_GENERATION_RANGE
UINT_PTR rangeLengthReserved;
} COR_PRF_GC_GENERATION_RANGE;

typedef struct COR_PRF_NONGC_HEAP_RANGE
{
ObjectID rangeStart;
UINT_PTR rangeLength;
UINT_PTR rangeLengthReserved;
} COR_PRF_NONGC_HEAP_RANGE;

typedef /* [public][public][public] */
enum __MIDL___MIDL_itf_corprof_0000_0001_0005
{
Expand Down Expand Up @@ -23231,6 +23238,11 @@ EXTERN_C const IID IID_ICorProfilerInfo14;
virtual HRESULT STDMETHODCALLTYPE EnumerateNonGCObjects(
/* [out] */ ICorProfilerObjectEnum **ppEnum) = 0;

virtual HRESULT STDMETHODCALLTYPE GetNonGCHeapBounds(
/* [in] */ ULONG cObjectRanges,
/* [out] */ ULONG *pcObjectRanges,
/* [length_is][size_is][out] */ COR_PRF_NONGC_HEAP_RANGE ranges[ ]) = 0;

};


Expand Down Expand Up @@ -24039,6 +24051,13 @@ EXTERN_C const IID IID_ICorProfilerInfo14;
ICorProfilerInfo14 * This,
/* [out] */ ICorProfilerObjectEnum **ppEnum);

DECLSPEC_XFGVIRT(ICorProfilerInfo14, GetNonGCHeapBounds)
HRESULT ( STDMETHODCALLTYPE *GetNonGCHeapBounds )(
ICorProfilerInfo14 * This,
/* [in] */ ULONG cObjectRanges,
/* [out] */ ULONG *pcObjectRanges,
/* [length_is][size_is][out] */ COR_PRF_NONGC_HEAP_RANGE ranges[ ]);

END_INTERFACE
} ICorProfilerInfo14Vtbl;

Expand Down Expand Up @@ -24402,6 +24421,9 @@ EXTERN_C const IID IID_ICorProfilerInfo14;
#define ICorProfilerInfo14_EnumerateNonGCObjects(This,ppEnum) \
( (This)->lpVtbl -> EnumerateNonGCObjects(This,ppEnum) )

#define ICorProfilerInfo14_GetNonGCHeapBounds(This,cObjectRanges,pcObjectRanges,ranges) \
( (This)->lpVtbl -> GetNonGCHeapBounds(This,cObjectRanges,pcObjectRanges,ranges) )

#endif /* COBJMACROS */


Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/vm/frozenobjectheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,7 @@ Object* FrozenObjectSegment::GetNextObject(Object* obj) const
uint8_t* nextObj = (reinterpret_cast<uint8_t*>(obj) + ALIGN_UP(obj->GetSize(), DATA_ALIGNMENT));
if (nextObj < m_pCurrent)
{
Object* result = reinterpret_cast<Object*>(nextObj);
INDEBUG(result->Validate());
return result;
return reinterpret_cast<Object*>(nextObj);
}

// Current object is the last one in the segment
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/frozenobjectheap.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class FrozenObjectHeapManager
FrozenObjectSegment* m_CurrentSegment;

friend class ProfilerObjectEnum;
friend class ProfToEEInterfaceImpl;
};

class FrozenObjectSegment
Expand Down Expand Up @@ -72,6 +73,7 @@ class FrozenObjectSegment
INDEBUG(size_t m_ObjectsCount);

friend class ProfilerObjectEnum;
friend class ProfToEEInterfaceImpl;
};

#endif // _FROZENOBJECTHEAP_H
Expand Down
64 changes: 64 additions & 0 deletions src/coreclr/vm/proftoeeinterfaceimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
#include "safemath.h"
#include "threadsuspend.h"
#include "inlinetracking.h"
#include "frozenobjectheap.h"

#ifdef PROFILING_SUPPORTED
#include "profilinghelper.h"
Expand Down Expand Up @@ -7598,6 +7599,9 @@ HRESULT ProfToEEInterfaceImpl::EnumerateNonGCObjects(ICorProfilerObjectEnum** pp
GC_NOTRIGGER;
MODE_ANY;
EE_THREAD_NOT_REQUIRED;

// FrozenObjectHeapManager takes a lock
CAN_TAKE_LOCK;
}
CONTRACTL_END;

Expand All @@ -7624,6 +7628,66 @@ HRESULT ProfToEEInterfaceImpl::EnumerateNonGCObjects(ICorProfilerObjectEnum** pp
return hr;
}

HRESULT ProfToEEInterfaceImpl::GetNonGCHeapBounds(ULONG cObjectRanges,
ULONG *pcObjectRanges,
COR_PRF_NONGC_HEAP_RANGE ranges[])
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
EE_THREAD_NOT_REQUIRED;

// FrozenObjectHeapManager takes a lock
CAN_TAKE_LOCK;
}
CONTRACTL_END;

if ((cObjectRanges > 0) && (ranges == nullptr))
{
// Copy GetGenerationBounds's behavior for consistency
return E_INVALIDARG;
}

FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager();
CrstHolder ch(&foh->m_Crst);

const unsigned segmentsCount = foh->m_FrozenSegments.GetCount();
FrozenObjectSegment** segments = foh->m_FrozenSegments.GetElements();
if (segments != nullptr && segmentsCount > 0)
{
const ULONG segmentsToInspect = min(cObjectRanges, (ULONG)segmentsCount);

for (unsigned segIdx = 0; segIdx < segmentsToInspect; segIdx++)
{
uint8_t* firstObj = segments[segIdx]->m_pStart + sizeof(ObjHeader);

// Start of the segment (first object)
ranges[segIdx].rangeStart = (ObjectID)firstObj;

// Total size reserved for a segment
ranges[segIdx].rangeLengthReserved = (UINT_PTR)segments[segIdx]->m_Size;

// Size of the segment that is currently in use
ranges[segIdx].rangeLength = (UINT_PTR)(segments[segIdx]->m_pCurrent - firstObj);
}

if (pcObjectRanges != nullptr)
{
*pcObjectRanges = segmentsToInspect;
}
}
else
{
if (pcObjectRanges != nullptr)
{
*pcObjectRanges = 0;
}
}
return S_OK;
}

/*
* GetStringLayout
*
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/proftoeeinterfaceimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,10 @@ class ProfToEEInterfaceImpl : public ICorProfilerInfo14
COM_METHOD EnumerateNonGCObjects(
ICorProfilerObjectEnum** ppEnum);

COM_METHOD GetNonGCHeapBounds(ULONG cObjectRanges,
ULONG * pcObjectRanges,
COR_PRF_NONGC_HEAP_RANGE ranges[]);

// end ICorProfilerInfo14

protected:
Expand Down
64 changes: 63 additions & 1 deletion src/tests/profiler/native/nongcheap/nongcheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,51 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()

_garbageCollections++;

const int MAX_NON_GC_HEAP_SEGMENTS = 16;
COR_PRF_NONGC_HEAP_RANGE segments[MAX_NON_GC_HEAP_SEGMENTS];
ULONG segCount;
ObjectID firstObj = 0;
HRESULT hr = pCorProfilerInfo->GetNonGCHeapBounds(MAX_NON_GC_HEAP_SEGMENTS, &segCount, segments);
if (FAILED(hr))
{
printf("GetNonGCHeapBounds returned an error\n!");
_failures++;
}
else if (segCount == 0 || segCount > MAX_NON_GC_HEAP_SEGMENTS)
{
printf("GetNonGCHeapBounds: invalid segCount (%u)\n!", segCount);
_failures++;
}
else
{
// Save very first object ID to compare with EnumerateNonGCObjects
firstObj = segments[0].rangeStart;

printf("\nGetNonGCHeapBounds (segCount = %u):\n", segCount);
for (ULONG i = 0; i < segCount; i++)
{
printf("\tseg#%u, rangeStart=%p, rangeLength=%u, rangeLengthReserved=%u\n",
i, (void*)segments[i].rangeStart, (ULONG)segments[i].rangeLength, (ULONG)segments[i].rangeLengthReserved);

if ((ULONG)segments[i].rangeLength > (ULONG)segments[i].rangeLengthReserved)
{
printf("GetNonGCHeapBounds: rangeLength > rangeLengthReserved");
_failures++;
}

if (!segments[i].rangeStart)
{
printf("GetNonGCHeapBounds: rangeStart is null");
_failures++;
}
}
printf("\n");
}

// Let's make sure we got the same number of objects as we got from the callback
// by testing the EnumerateNonGCObjects API.
ICorProfilerObjectEnum* pEnum = NULL;
HRESULT hr = pCorProfilerInfo->EnumerateNonGCObjects(&pEnum);
hr = pCorProfilerInfo->EnumerateNonGCObjects(&pEnum);
if (FAILED(hr))
{
printf("EnumerateNonGCObjects returned an error\n!");
Expand All @@ -72,8 +113,29 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()
{
int nonGcObjectsEnumerated = 0;
ObjectID obj;
bool isFirstObj = true;
while (pEnum->Next(1, &obj, NULL) == S_OK)
{
if (isFirstObj)
{
if (firstObj != obj)
{
printf("EnumerateNonGCObjects: firstObj != obj\n!");
_failures++;
}
}

// Add test coverage for IsFrozenObject API, currently, it is expected to return true
// for objects from non-GC heap (it might also return true for frozen segments we don't track)
BOOL isFrozen;
hr = pCorProfilerInfo->IsFrozenObject(obj, &isFrozen);
if (FAILED(hr) || !isFrozen)
{
printf("EnumerateNonGCObjects: IsFrozenObject failed\n!");
_failures++;
}

isFirstObj = false;
nonGcObjectsEnumerated++;
}

Expand Down

0 comments on commit 8091325

Please # to comment.