Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ICorProfilerInfo14::GetNonGCHeapBounds #85434

Merged
merged 6 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we agreed not to use COOP (Validate() needs it)

}

// 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
58 changes: 58 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,60 @@ 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);
}

*pcObjectRanges = segmentsToInspect;
EgorBo marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
*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 = %lu):\n", segCount);
for (ULONG i = 0; i < segCount; i++)
{
printf("\tseg#%ld, 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);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cshung added test coverage for IsFrozenObject on your request

if (FAILED(hr) || !isFrozen)
{
printf("EnumerateNonGCObjects: IsFrozenObject failed\n!");
_failures++;
}

isFirstObj = false;
nonGcObjectsEnumerated++;
}

Expand Down