1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-11 02:13:38 +09:00

Fix race condition in nongcheap.cpp test (#105658)

This commit is contained in:
Egor Bogatov 2024-07-31 23:09:39 +02:00 committed by GitHub
parent bcbca94ce9
commit 7f10eeada7
Signed by: github
GPG key ID: B5690EEEBB952194
3 changed files with 56 additions and 14 deletions

View file

@ -141,20 +141,22 @@ namespace Profiler.Tests
return 100; return 100;
} }
public const string ProfilerName = "Profiler";
public static string GetProfilerPath() public static string GetProfilerPath()
{ {
string profilerName; string profilerName;
if (TestLibrary.Utilities.IsWindows) if (TestLibrary.Utilities.IsWindows)
{ {
profilerName = "Profiler.dll"; profilerName = $"{ProfilerName}.dll";
} }
else if (TestLibrary.Utilities.IsLinux) else if (TestLibrary.Utilities.IsLinux)
{ {
profilerName = "libProfiler.so"; profilerName = $"lib{ProfilerName}.so";
} }
else else
{ {
profilerName = "libProfiler.dylib"; profilerName = $"lib{ProfilerName}.dylib";
} }
string profilerPath = Path.Combine(Environment.CurrentDirectory, profilerName); string profilerPath = Path.Combine(Environment.CurrentDirectory, profilerName);

View file

@ -3,6 +3,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
namespace Profiler.Tests namespace Profiler.Tests
@ -26,16 +27,28 @@ namespace Profiler.Tests
int gen = GC.GetGeneration("string7"); int gen = GC.GetGeneration("string7");
if (gen != int.MaxValue) if (gen != int.MaxValue)
throw new Exception("object is expected to be in a non-gc heap for this test to work"); throw new Exception("object is expected to be in a non-gc heap for this test to work");
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void InvokeGc()
{
// Notify the profiler that we're done with the allocations
// It's a sort of workaround for possible race conditions between
// GarbageCollectionFinished and ObjectAllocated
NotifyNongcAllocationsFinished();
GC.Collect(); GC.Collect();
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
static void Consume(object o) {} static void Consume(object o) { }
public static int RunTest(String[] args) [DllImport(ProfilerTestRunner.ProfilerName)]
private static extern void NotifyNongcAllocationsFinished();
public static int RunTest(String[] args)
{ {
AllocateNonGcHeapObjects(); AllocateNonGcHeapObjects();
InvokeGc();
Console.WriteLine("Test Passed"); Console.WriteLine("Test Passed");
return 100; return 100;
} }

View file

@ -4,6 +4,12 @@
#include "nongcheap.h" #include "nongcheap.h"
#include <vector> #include <vector>
#ifdef _MSC_VER
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __attribute__((visibility("default")))
#endif // _MSC_VER
GUID NonGcHeapProfiler::GetClsid() GUID NonGcHeapProfiler::GetClsid()
{ {
// {EF0D191C-3FC7-4311-88AF-E474CBEB2859} // {EF0D191C-3FC7-4311-88AF-E474CBEB2859}
@ -11,8 +17,17 @@ GUID NonGcHeapProfiler::GetClsid()
return clsid; return clsid;
} }
std::atomic<bool> _allocationsFinished;
extern "C" DLLEXPORT void NotifyNongcAllocationsFinished()
{
printf("NotifyNongcAllocationsFinished is invoked.\n");
_allocationsFinished = true;
}
HRESULT NonGcHeapProfiler::Initialize(IUnknown* pICorProfilerInfoUnk) HRESULT NonGcHeapProfiler::Initialize(IUnknown* pICorProfilerInfoUnk)
{ {
_allocationsFinished = false;
Profiler::Initialize(pICorProfilerInfoUnk); Profiler::Initialize(pICorProfilerInfoUnk);
HRESULT hr = S_OK; HRESULT hr = S_OK;
@ -20,7 +35,7 @@ HRESULT NonGcHeapProfiler::Initialize(IUnknown* pICorProfilerInfoUnk)
COR_PRF_ENABLE_OBJECT_ALLOCATED | COR_PRF_MONITOR_OBJECT_ALLOCATED, COR_PRF_ENABLE_OBJECT_ALLOCATED | COR_PRF_MONITOR_OBJECT_ALLOCATED,
COR_PRF_HIGH_BASIC_GC))) COR_PRF_HIGH_BASIC_GC)))
{ {
printf("FAIL: ICorProfilerInfo::SetEventMask2() failed hr=0x%x", hr); printf("FAIL: ICorProfilerInfo::SetEventMask2() failed hr=0x%x\n", hr);
return hr; return hr;
} }
@ -41,16 +56,22 @@ HRESULT STDMETHODCALLTYPE NonGcHeapProfiler::ObjectAllocated(ObjectID objectId,
{ {
// We expect GetObjectGeneration to return an error (CORPROF_E_NOT_GC_OBJECT) // We expect GetObjectGeneration to return an error (CORPROF_E_NOT_GC_OBJECT)
// for non-GC objects. // for non-GC objects.
printf("FAIL: GetObjectGeneration failed for nongc object: hr=0x%x\n", hr);
_failures++; _failures++;
} }
_nonGcHeapObjects++;
if (gen.rangeLength != 0 || gen.rangeLengthReserved != 0 || gen.rangeStart != 0) if (gen.rangeLength != 0 || gen.rangeLengthReserved != 0 || gen.rangeStart != 0)
{ {
printf("FAIL: GetObjectGeneration returned unexpected values: rangeLength=%u, rangeLengthReserved=%u, rangeStart=%p\n",
(uint32_t)gen.rangeLength, (uint32_t)gen.rangeLengthReserved, (void*)gen.rangeStart);
_failures++; _failures++;
} }
_nonGcHeapObjects++;
} }
else if (FAILED(hr)) else if (FAILED(hr))
{ {
printf("FAIL: GetObjectGeneration failed: hr=0x%x\n", hr);
_failures++; _failures++;
} }
return S_OK; return S_OK;
@ -60,6 +81,12 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()
{ {
SHUTDOWNGUARD(); SHUTDOWNGUARD();
if (!_allocationsFinished)
{
printf("Ignoring this GarbageCollectionFinished: NotifyNongcAllocationsFinished has not been invoked yet.\n");
return S_OK;
}
_garbageCollections++; _garbageCollections++;
std::vector<uint64_t> segment_starts; std::vector<uint64_t> segment_starts;
@ -93,13 +120,13 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()
if (nongc_segments[i].rangeLength > nongc_segments[i].rangeLengthReserved) if (nongc_segments[i].rangeLength > nongc_segments[i].rangeLengthReserved)
{ {
printf("FAIL: GetNonGCHeapBounds: rangeLength > rangeLengthReserved"); printf("FAIL: GetNonGCHeapBounds: rangeLength > rangeLengthReserved\n");
_failures++; _failures++;
} }
if (!nongc_segments[i].rangeStart) if (!nongc_segments[i].rangeStart)
{ {
printf("FAIL: GetNonGCHeapBounds: rangeStart is null"); printf("FAIL: GetNonGCHeapBounds: rangeStart is null\n");
_failures++; _failures++;
} }
segment_starts.push_back(nongc_segments[i].rangeStart); segment_starts.push_back(nongc_segments[i].rangeStart);
@ -128,13 +155,13 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()
if (gc_segments[i].rangeLength > gc_segments[i].rangeLengthReserved) if (gc_segments[i].rangeLength > gc_segments[i].rangeLengthReserved)
{ {
printf("FAIL: GetGenerationBounds: rangeLength > rangeLengthReserved"); printf("FAIL: GetGenerationBounds: rangeLength > rangeLengthReserved\n");
_failures++; _failures++;
} }
if (!gc_segments[i].rangeStart) if (!gc_segments[i].rangeStart)
{ {
printf("FAIL: GetGenerationBounds: rangeStart is null"); printf("FAIL: GetGenerationBounds: rangeStart is null\n");
_failures++; _failures++;
} }
segment_starts.push_back(gc_segments[i].rangeStart); segment_starts.push_back(gc_segments[i].rangeStart);
@ -154,12 +181,12 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()
if (segment_starts[i] == segment_starts[i+1]) if (segment_starts[i] == segment_starts[i+1])
{ {
printf("FAIL: Duplicated segment starts"); printf("FAIL: Duplicated segment starts\n");
_failures++; _failures++;
} }
if (segment_ends[i] == segment_ends[i+1]) if (segment_ends[i] == segment_ends[i+1])
{ {
printf("FAIL: Duplicated segment ends"); printf("FAIL: Duplicated segment ends\n");
_failures++; _failures++;
} }
if (segment_ends[i] > segment_starts[i+1]) if (segment_ends[i] > segment_starts[i+1])
@ -211,7 +238,7 @@ HRESULT NonGcHeapProfiler::GarbageCollectionFinished()
if (nonGcObjectsEnumerated != _nonGcHeapObjects) if (nonGcObjectsEnumerated != _nonGcHeapObjects)
{ {
printf("FAIL: objectAllocated(%d) != _nonGcHeapObjects(%d)\n!", nonGcObjectsEnumerated, (int)_nonGcHeapObjects); printf("FAIL: nonGcObjectsEnumerated(%d) != _nonGcHeapObjects(%d)\n!", nonGcObjectsEnumerated, (int)_nonGcHeapObjects);
_failures++; _failures++;
} }
} }