Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
41 changes: 41 additions & 0 deletions src/coreclr/src/System.Private.CoreLib/src/System/GC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,47 @@ public static GCMemoryInfo GetGCMemoryInfo()
fragmentedBytes: (long)(ulong)lastRecordedFragmentationBytes);
}

[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Ansi)]
private static extern void GetGCConfigurationVariable(string name, StringHandleOnStack retString);

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string[] GetGCConfigurationVariables();

/// <summary>
/// Given the name of a GC configuration variable, get the set or default value.
/// </summary>
/// <remarks>
/// Returns `null` for an invalid name.
/// For a list of possible names, see the keys of `GetConfigurationVariables`.
///
/// Numeric are in decimal even though environment variables are specified using hexadecimal.
///
/// This reflects actually used values, not just explicit settings.
/// For example, if you set `System.GC.HeapCount` but not `System.GC.Server`,
/// the result for "HeapCount" would be "1" as workstation GC only uses 1 heap.
/// Similarly, "NoAffinitize" may be true if "HeapHardLimit" is set and HeapAffinitizeRanges is not.
/// </remarks>
public static string? GetConfigurationVariable(string name)
{
string result = "";
GetGCConfigurationVariable(name, new StringHandleOnStack(ref result));
return result == "" ? null : result;
}

/// <summary>
/// Returns all possible GC configuration variables and their values.
/// </summary>
/// <remarks>
/// See `GetConfigurationVariable` for description of how we get values.
/// </remarks>
public static IEnumerable<KeyValuePair<string, string>> GetConfigurationVariables()
{
foreach (string v in GetGCConfigurationVariables())
{
yield return new KeyValuePair<string, string>(v, GetConfigurationVariable(v)!);
}
}

[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
internal static extern int _StartNoGCRegion(long totalSize, bool lohSizeKnown, long lohSize, bool disallowFullBlockingGC);

Expand Down
115 changes: 115 additions & 0 deletions src/coreclr/src/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38815,6 +38815,121 @@ void GCHeap::GetMemoryInfo(uint64_t* highMemLoadThresholdBytes,
*lastRecordedFragmentationBytes = gc_heap::last_gc_fragmentation;
}

static const char* bool_to_str(const bool value)
{
const char* content = value ? "true" : "false";
const size_t len = strlen(content);
// + 1 for the '\0'
char* out = new (nothrow) char[len + 1];
if (out != nullptr)
{
strncpy(out, content, len + 1);
assert(out[len] == '\0' && strcmp(out, content) == 0);
}
return out;
}

static const char* int64_t_to_str(const int64_t value)
{
// 2**64 in base ten has 20 characters at most, + 1 for the '\0'
const size_t max_size = 21;
char* out = new (nothrow) char[max_size];
if (out != nullptr)
{
int n = _snprintf_s (out, max_size, _TRUNCATE, "%llu", (long long) value);
// -1 because n does not include the '\0'
assert (n <= max_size - 1);
}
return out;
}

static char const* const configuration_variables[11] =
{
"CpuGroup",
"HeapAffinitizeMask",
"HeapAffinitizeRanges",
"HeapCount",
"HeapHardLimit",
"HeapHardLimitPercent",
"HighMemoryPercent",
"LargePages",
"LOHThreshold",
"NoAffinitize",
"Server"
};

slice<char const* const> GCHeap::GetGCConfigurationVariables()
{
return slice<char const* const>::FromArray<11>(configuration_variables);
}

const char* GCHeap::GetGCConfigurationVariable(const char* key)
{
if (strcmp(key, "CpuGroup") == 0)
{
return bool_to_str(GCConfig::GetGCCpuGroup());
}
else if (strcmp(key, "HeapAffinitizeMask") == 0)
{
return int64_t_to_str(GCConfig::GetGCHeapAffinitizeMask());
}
else if (strcmp(key, "HeapAffinitizeRanges") == 0)
{
// GetGCHeapAffinitizeRanges returns a GCConfigStringHolder which will delete the string, but not if we Extract() it.
return GCConfig::GetGCHeapAffinitizeRanges().Extract();
}
else if (strcmp(key, "HeapCount") == 0)
{
#ifdef MULTIPLE_HEAPS
const size_t heapCount = gc_heap::n_heaps;
#else
const size_t heapCount = 1;
#endif
return int64_t_to_str(heapCount);
}
else if (strcmp(key, "HeapHardLimit") == 0)
{
return int64_t_to_str(gc_heap::heap_hard_limit);
}
else if (strcmp(key, "HeapHardLimitPercent") == 0)
{
return int64_t_to_str(GCConfig::GetGCHeapHardLimitPercent());
}
else if (strcmp(key, "HighMemoryPercent") == 0)
{
return int64_t_to_str(gc_heap::high_memory_load_th);
}
else if (strcmp(key, "LargePages") == 0)
{
return bool_to_str(gc_heap::use_large_pages_p);
}
else if (strcmp(key, "LOHThreshold") == 0)
{
return int64_t_to_str(loh_size_threshold);
}
else if (strcmp(key, "NoAffinitize") == 0)
{
#ifdef MULTIPLE_HEAPS
const bool noAffinitize = gc_heap::gc_thread_no_affinitize_p;
#else
const bool noAffinitize = false;
#endif
return bool_to_str(noAffinitize);
}
else if (strcmp(key, "Server") == 0)
{
#ifdef MULTIPLE_HEAPS
return bool_to_str(true);
#else
return bool_to_str(false);
#endif
}
else
{
return nullptr;
}
}

int GCHeap::GetGcLatencyMode()
{
return (int)(pGenGCHeap->settings.pause_mode);
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/src/gc/gcconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ class GCConfigStringHolder

// Retrieves the wrapped config string.
const char* Get() const { return m_str; }

// Returns the wrapped config string and sets to null.
// Now the caller is responsible for freeing it.
const char* Extract() {
const char* result = m_str;
m_str = nullptr;
return result;
}
};

// Note that the configs starting BGCFLTuningEnabled ending BGCG2RatioStep are for BGC servo
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/gc/gcimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ class GCHeap : public IGCHeapInternal
uint32_t* lastRecordedMemLoadPct,
size_t* lastRecordedHeapSizeBytes,
size_t* lastRecordedFragmentationBytes);

const char* GetGCConfigurationVariable(const char* key);
slice<char const* const> GetGCConfigurationVariables();

int GetGcLatencyMode();
int SetGcLatencyMode(int newLatencyMode);
Expand Down
29 changes: 29 additions & 0 deletions src/coreclr/src/gc/gcinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@
// mismatches can still interopate correctly, with some care.
#define GC_INTERFACE_MINOR_VERSION 1

template <typename T>
class slice {
T* _begin;
size_t _length;

slice(T* begin, size_t length) : _begin{begin}, _length{length} {}

public:
template <size_t size>
static slice<T> FromArray(T data[size])
{
return slice<T> { data, size };
}

size_t size() const
{
return _length;
}

const T& operator[](size_t index) const
{
assert(index < _length);
return _begin[index];
}
};

struct ScanContext;
struct gc_alloc_context;
class CrawlFrame;
Expand Down Expand Up @@ -612,6 +638,9 @@ class IGCHeap {
size_t* lastRecordedHeapSizeBytes,
size_t* lastRecordedFragmentationBytes) = 0;

virtual const char* GetGCConfigurationVariable(const char* key) = 0;
virtual slice<char const* const> GetGCConfigurationVariables() = 0;

// Gets the current GC latency mode.
virtual int GetGcLatencyMode() = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCName, W("GCName"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCHeapHardLimit, W("GCHeapHardLimit"), "Specifies the maximum commit size for the GC heap")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCHeapHardLimitPercent, W("GCHeapHardLimitPercent"), "Specifies the GC heap usage as a percentage of the total memory")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCHeapAffinitizeRanges, W("GCHeapAffinitizeRanges"), "Specifies list of processors for Server GC threads. The format is a comma separated list of processor numbers or ranges of processor numbers. Example: 1,3,5,7-9,12")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCLargePages, W("GCLargePages"), "Specifies whether large pages should be used when a heap hard limit is set")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCLargePages, W("GCLargePages"), 0, "Specifies whether large pages should be used when a heap hard limit is set")

///
/// IBC
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/src/inc/holder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,7 @@ FORCEINLINE void DeleteArray(TYPE *value)

NEW_WRAPPER_TEMPLATE1(NewArrayHolder, DeleteArray<_TYPE>);
typedef NewArrayHolder<CHAR> AStringHolder;
typedef NewArrayHolder<const CHAR> AConstStringHolder;
typedef NewArrayHolder<WCHAR> WStringHolder;

//-----------------------------------------------------------------------------
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/src/utilcode/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "corinfo.h"
#include "volatile.h"

#include "../inc/configuration.h"

#ifndef DACCESS_COMPILE
UINT32 g_nClrInstanceId = 0;
#endif //!DACCESS_COMPILE
Expand Down Expand Up @@ -989,7 +991,7 @@ DWORD LCM(DWORD u, DWORD v)
CONTRACTL_END;

#if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
BOOL enableGCCPUGroups = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCCpuGroup) != 0;
BOOL enableGCCPUGroups = Configuration::GetKnobBooleanValue(W("System.GC.CpuGroup"), CLRConfig::EXTERNAL_GCCpuGroup);
BOOL threadUseAllCpuGroups = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Thread_UseAllCpuGroups) != 0;

if (!enableGCCPUGroups)
Expand Down
37 changes: 37 additions & 0 deletions src/coreclr/src/vm/comutilnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,43 @@ FCIMPL6(void, GCInterface::GetMemoryInfo, UINT64* highMemLoadThreshold, UINT64*
}
FCIMPLEND

void QCALLTYPE GCInterface::GetGCConfigurationVariable(const char* key, QCall::StringHandleOnStack result)
{
QCALL_CONTRACT;

BEGIN_QCALL;

AConstStringHolder value;
value = GCHeapUtilities::GetGCHeap()->GetGCConfigurationVariable(key);
if (value)
{
result.Set(value);
}

END_QCALL;
}

FCIMPL0(Object*, GCInterface::GetGCConfigurationVariables)
{
FCALL_CONTRACT;

slice<char const* const> configVariables = GCHeapUtilities::GetGCHeap()->GetGCConfigurationVariables();

PTRARRAYREF strArray = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_1(strArray);
strArray = (PTRARRAYREF) AllocateObjectArray(static_cast<DWORD>(configVariables.size()), g_pStringClass);
for (unsigned int i = 0; i < configVariables.size(); i++)
{
STRINGREF str = StringObject::NewString(configVariables[i]); // This copies it
STRINGREF * destData = ((STRINGREF*)(strArray->GetDataPtr())) + i;
SetObjectReference((OBJECTREF*)destData, (OBJECTREF)str);
}

HELPER_METHOD_FRAME_END();
return OBJECTREFToObject(strArray);
}
FCIMPLEND

FCIMPL0(int, GCInterface::GetGcLatencyMode)
{
FCALL_CONTRACT;
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/vm/comutilnative.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ class GCInterface {
static FORCEINLINE UINT64 InterlockedSub(UINT64 *pMinuend, UINT64 subtrahend);

static FCDECL6(void, GetMemoryInfo, UINT64* highMemLoadThresholdBytes, UINT64* totalAvailableMemoryBytes, UINT64* lastRecordedMemLoadBytes, UINT32* lastRecordedMemLoadPct, size_t* lastRecordedHeapSizBytes, size_t* lastRecordedFragmentationBytes);
static void QCALLTYPE GetGCConfigurationVariable(const char* key, QCall::StringHandleOnStack result);
// The object will be a string[]
static FCDECL0(Object*, GetGCConfigurationVariables);
static FCDECL0(int, GetGcLatencyMode);
static FCDECL1(int, SetGcLatencyMode, int newLatencyMode);
static FCDECL0(int, GetLOHCompactionMode);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/src/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,8 @@ FCFuncStart(gGCInterfaceFuncs)
QCFuncElement("_StartNoGCRegion", GCInterface::StartNoGCRegion)
QCFuncElement("_EndNoGCRegion", GCInterface::EndNoGCRegion)
FCFuncElement("GetSegmentSize", GCInterface::GetSegmentSize)
QCFuncElement("GetGCConfigurationVariable", GCInterface::GetGCConfigurationVariable)
FCFuncElement("GetGCConfigurationVariables", GCInterface::GetGCConfigurationVariables)
FCFuncElement("GetLastGCPercentTimeInGC", GCInterface::GetLastGCPercentTimeInGC)
FCFuncElement("GetGenerationSize", GCInterface::GetGenerationSize)
QCFuncElement("_AddMemoryPressure", GCInterface::_AddMemoryPressure)
Expand Down
8 changes: 7 additions & 1 deletion src/coreclr/src/vm/eeconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,12 +814,18 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
if (!iGCgen0size) iGCgen0size = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCgen0size, iGCgen0size);
#endif //BIT64

const ULONGLONG ullHeapHardLimit = Configuration::GetKnobULONGLONGValue(W("System.GC.HeapHardLimit"));
ULONGLONG ullHeapHardLimit = Configuration::GetKnobULONGLONGValue(W("System.GC.HeapHardLimit"));
if (!ullHeapHardLimit) ullHeapHardLimit = GetConfigULONGLONG_DontUse_(CLRConfig::EXTERNAL_GCHeapHardLimit, 0);
iGCHeapHardLimit = FitsIn<size_t, ULONGLONG>(ullHeapHardLimit)
? static_cast<size_t>(ullHeapHardLimit)
: ClrSafeInt<size_t>::MaxInt();
iGCHeapHardLimitPercent = Configuration::GetKnobDWORDValue(W("System.GC.HeapHardLimitPercent"), 0);

iGCCpuGroup = Configuration::GetKnobBooleanValue(W("System.GC.CpuGroup"), CLRConfig::EXTERNAL_GCCpuGroup);
iGCHighMemoryPercent = Configuration::GetKnobDWORDValue(W("System.GC.HighMemoryPercent"), CLRConfig::EXTERNAL_GCHighMemPercent);
fGCLargePages = Configuration::GetKnobBooleanValue(W("System.GC.LargePages"), CLRConfig::EXTERNAL_GCLargePages);
lpszGCHeapAffinitizeRanges = Configuration::GetKnobStringValue(W("System.GC.HeapAffinitizeRanges"), CLRConfig::EXTERNAL_GCHeapAffinitizeRanges);

if (g_IGCHoardVM)
iGCHoardVM = g_IGCHoardVM;
else
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/src/vm/eeconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,12 @@ class EEConfig
int GetGCHeapCount() const {LIMITED_METHOD_CONTRACT; return iGCHeapCount;}
int GetGCNoAffinitize () const {LIMITED_METHOD_CONTRACT; return iGCNoAffinitize;}
size_t GetGCAffinityMask() const {LIMITED_METHOD_CONTRACT; return iGCAffinityMask;}
LPCWSTR GetGCHeapAffinitizeRanges() const {LIMITED_METHOD_CONTRACT; return lpszGCHeapAffinitizeRanges;}
int GetGCHighMemoryPercent() const {LIMITED_METHOD_CONTRACT; return iGCHighMemoryPercent;}
size_t GetGCHeapHardLimit() const {LIMITED_METHOD_CONTRACT; return iGCHeapHardLimit;}
int GetGCHeapHardLimitPercent() const {LIMITED_METHOD_CONTRACT; return iGCHeapHardLimitPercent;}
bool GetGCLargePages() const {LIMITED_METHOD_CONTRACT; return fGCLargePages;}
bool GetGCCpuGroup() const {LIMITED_METHOD_CONTRACT; return iGCCpuGroup;}

#ifdef GCTRIMCOMMIT

Expand Down Expand Up @@ -917,8 +921,13 @@ class EEConfig
int iGCHeapCount;
int iGCNoAffinitize;
size_t iGCAffinityMask;
bool iGCCpuGroup;
// this points to a string from GetKnobStringValue and should not be freed.
LPCWSTR lpszGCHeapAffinitizeRanges;
int iGCHighMemoryPercent;
size_t iGCHeapHardLimit;
int iGCHeapHardLimitPercent;
bool fGCLargePages;

#ifdef GCTRIMCOMMIT

Expand Down
Loading