Skip to content

Commit c677eae

Browse files
author
Nathan Ricci
committed
Implementation of AddMemoryPressure.
1 parent adfccb1 commit c677eae

File tree

9 files changed

+135
-14
lines changed

9 files changed

+135
-14
lines changed

src/mono/System.Private.CoreLib/src/System/GC.Mono.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ public static partial class GC
3636
private static extern void InternalCollect(int generation);
3737

3838
[MethodImplAttribute(MethodImplOptions.InternalCall)]
39-
private static extern void RecordPressure(long bytesAllocated);
39+
private static extern void AddPressure(ulong bytesAllocated);
40+
41+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
42+
private static extern void RemovePressure(ulong bytesRemoved);
4043

4144
// TODO: Move following to ConditionalWeakTable
4245
[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -60,7 +63,7 @@ public static void AddMemoryPressure(long bytesAllocated)
6063
{
6164
ArgumentOutOfRangeException.ThrowIfGreaterThan(bytesAllocated, int.MaxValue);
6265
}
63-
RecordPressure(bytesAllocated);
66+
AddPressure((ulong)bytesAllocated);
6467
}
6568

6669
public static void RemoveMemoryPressure(long bytesAllocated)
@@ -70,7 +73,7 @@ public static void RemoveMemoryPressure(long bytesAllocated)
7073
{
7174
ArgumentOutOfRangeException.ThrowIfGreaterThan(bytesAllocated, int.MaxValue);
7275
}
73-
RecordPressure(-bytesAllocated);
76+
RemovePressure((ulong)bytesAllocated);
7477
}
7578

7679
[MethodImplAttribute(MethodImplOptions.InternalCall)]

src/mono/mono/metadata/boehm-gc.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,14 +311,20 @@ mono_restart_world (MonoThreadInfoFlags flags)
311311
* are indirectly referenced by managed objects (for example unmanaged
312312
* memory holding image or other binary data).
313313
* This is a hint only to the garbage collector algorithm.
314-
* Note that negative amounts of p value will decrease the memory
315-
* pressure.
314+
* `value` must be greater than or equal to 0.
315+
* To remove pressure, use `mono_gc_remove_memory_pressure`.
316316
*/
317317
void
318-
mono_gc_add_memory_pressure (gint64 value)
318+
mono_gc_add_memory_pressure (guint64 value)
319319
{
320320
}
321321

322+
void
323+
mono_gc_remove_memory_pressure (guint64 value)
324+
{
325+
}
326+
327+
322328
/**
323329
* mono_gc_get_used_size:
324330
*

src/mono/mono/metadata/gc-internals.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ mono_gc_register_object_with_weak_fields (MonoObjectHandle obj);
169169
typedef void (*MonoFinalizationProc)(gpointer, gpointer); // same as SGenFinalizationProc, GC_finalization_proc
170170

171171
void mono_gc_register_for_finalization (MonoObject *obj, MonoFinalizationProc user_data);
172-
void mono_gc_add_memory_pressure (gint64 value);
172+
void mono_gc_add_memory_pressure (guint64 value);
173+
void mono_gc_remove_memory_pressure (guint64 value);
174+
173175
MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg);
174176
MONO_COMPONENT_API void mono_gc_deregister_root (char* addr);
175177
void mono_gc_finalize_domain (MonoDomain *domain);

src/mono/mono/metadata/icall-decl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ ICALL_EXPORT void ves_icall_System_Array_SetGenericValue_icall (MonoObjectHandle
131131

132132
ICALL_EXPORT void ves_icall_System_Environment_Exit (int);
133133
ICALL_EXPORT void ves_icall_System_GC_InternalCollect (int generation);
134-
ICALL_EXPORT void ves_icall_System_GC_RecordPressure (gint64);
134+
ICALL_EXPORT void ves_icall_System_GC_AddPressure (guint64);
135+
ICALL_EXPORT void ves_icall_System_GC_RemovePressure (guint64);
136+
135137
ICALL_EXPORT void ves_icall_System_GC_WaitForPendingFinalizers (void);
136138
ICALL_EXPORT void ves_icall_System_GC_GetGCMemoryInfo (gint64*, gint64*, gint64*, gint64*, gint64*, gint64*);
137139

src/mono/mono/metadata/icall-def.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ NOHANDLES(ICALL(ENV_15, "get_TickCount", ves_icall_System_Environment_get_TickCo
206206
NOHANDLES(ICALL(ENV_15a, "get_TickCount64", ves_icall_System_Environment_get_TickCount64))
207207
NOHANDLES(ICALL(ENV_20, "set_ExitCode", mono_environment_exitcode_set))
208208

209-
ICALL_TYPE(GC, "System.GC", GC_13)
209+
ICALL_TYPE(GC, "System.GC", GC_4a)
210+
NOHANDLES(ICALL(GC_4a, "AddPressure", ves_icall_System_GC_AddPressure))
210211
HANDLES(GC_13, "AllocPinnedArray", ves_icall_System_GC_AllocPinnedArray, MonoArray, 2, (MonoReflectionType, gint32))
211212
NOHANDLES(ICALL(GC_10, "GetAllocatedBytesForCurrentThread", ves_icall_System_GC_GetAllocatedBytesForCurrentThread))
212213
NOHANDLES(ICALL(GC_0, "GetCollectionCount", ves_icall_System_GC_GetCollectionCount))
@@ -215,7 +216,7 @@ NOHANDLES(ICALL(GC_0b, "GetMaxGeneration", ves_icall_System_GC_GetMaxGeneration)
215216
HANDLES(GC_11, "GetTotalAllocatedBytes", ves_icall_System_GC_GetTotalAllocatedBytes, guint64, 1, (MonoBoolean))
216217
NOHANDLES(ICALL(GC_1, "GetTotalMemory", ves_icall_System_GC_GetTotalMemory))
217218
NOHANDLES(ICALL(GC_2, "InternalCollect", ves_icall_System_GC_InternalCollect))
218-
NOHANDLES(ICALL(GC_4a, "RecordPressure", ves_icall_System_GC_RecordPressure))
219+
NOHANDLES(ICALL(GC_5, "RemovePressure", ves_icall_System_GC_RemovePressure))
219220
NOHANDLES(ICALL(GC_6, "WaitForPendingFinalizers", ves_icall_System_GC_WaitForPendingFinalizers))
220221
NOHANDLES(ICALL(GC_12, "_GetGCMemoryInfo", ves_icall_System_GC_GetGCMemoryInfo))
221222
HANDLES(GC_6b, "_ReRegisterForFinalize", ves_icall_System_GC_ReRegisterForFinalize, void, 1, (MonoObject))

src/mono/mono/metadata/icall.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7286,11 +7286,17 @@ ves_icall_System_GC_GetTotalAllocatedBytes (MonoBoolean precise, MonoError* erro
72867286
}
72877287

72887288
void
7289-
ves_icall_System_GC_RecordPressure (gint64 value)
7289+
ves_icall_System_GC_AddPressure (guint64 value)
72907290
{
72917291
mono_gc_add_memory_pressure (value);
72927292
}
72937293

7294+
void
7295+
ves_icall_System_GC_RemovePressure (guint64 value)
7296+
{
7297+
mono_gc_remove_memory_pressure (value);
7298+
}
7299+
72947300
MonoBoolean
72957301
ves_icall_System_Threading_Thread_YieldInternal (void)
72967302
{

src/mono/mono/metadata/sgen-mono.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2867,11 +2867,16 @@ mono_gc_card_table_nursery_check (void)
28672867
return !sgen_get_major_collector ()->is_concurrent;
28682868
}
28692869

2870-
/* Negative value to remove */
28712870
void
2872-
mono_gc_add_memory_pressure (gint64 value)
2871+
mono_gc_add_memory_pressure (guint64 value)
28732872
{
2874-
/* FIXME: Implement at some point? */
2873+
sgen_add_memory_pressure(value);
2874+
}
2875+
2876+
void
2877+
mono_gc_remove_memory_pressure (guint64 value)
2878+
{
2879+
sgen_remove_memory_pressure(value);
28752880
}
28762881

28772882
/*

src/mono/mono/sgen/sgen-gc.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
This should help weak consistency archs.
156156
*/
157157
#include "config.h"
158+
158159
#ifdef HAVE_SGEN_GC
159160

160161
#ifdef __MACH__
@@ -4083,4 +4084,96 @@ sgen_check_canary_for_object (gpointer addr)
40834084
}
40844085
}
40854086

4087+
4088+
#define MEM_PRESSURE_COUNT 4
4089+
#define MAX_MEMORYPRESSURE_RATIO 10
4090+
guint64 memory_pressure_gc_count = 0;
4091+
guint64 memory_pressure_iteration = 0;
4092+
guint64 memory_pressure_adds[MEM_PRESSURE_COUNT] = {0, 0, 0, 0};
4093+
guint64 memory_pressure_removes[MEM_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure removals
4094+
const unsigned min_memorypressure_budget = 4 * 1024 * 1024; // 4 MB
4095+
4096+
// Resets pressure accounting after a gen2 GC has occurred.
4097+
static void check_pressure_counts ()
4098+
{
4099+
if (memory_pressure_gc_count != sgen_gc_collection_count(GENERATION_OLD))
4100+
{
4101+
memory_pressure_gc_count = sgen_gc_collection_count(GENERATION_OLD);
4102+
memory_pressure_iteration++;
4103+
4104+
guint32 p = memory_pressure_iteration % MEM_PRESSURE_COUNT;
4105+
4106+
memory_pressure_adds[p] = 0; // new pressure will be accumulated here
4107+
memory_pressure_removes[p] = 0;
4108+
}
4109+
}
4110+
4111+
void sgen_remove_memory_pressure (guint64 bytes_allocated)
4112+
{
4113+
check_pressure_counts();
4114+
4115+
guint32 p = memory_pressure_iteration % MEM_PRESSURE_COUNT;
4116+
4117+
mono_atomic_fetch_add_i64((gint64*)&memory_pressure_removes[p], bytes_allocated);
4118+
}
4119+
4120+
void sgen_add_memory_pressure (guint64 bytes_allocated)
4121+
{
4122+
4123+
check_pressure_counts ();
4124+
4125+
guint p = memory_pressure_iteration % MEM_PRESSURE_COUNT;
4126+
4127+
guint64 new_mem_value = mono_atomic_fetch_add_i64 ((gint64*)&memory_pressure_adds[p], bytes_allocated);
4128+
4129+
// AddMemoryPressure contains unrolled loops which depend on MEM_PRESSURE_COUNT
4130+
g_assert (MEM_PRESSURE_COUNT == 4);
4131+
4132+
guint64 add = memory_pressure_adds[0] + memory_pressure_adds[1] + memory_pressure_adds[2] + memory_pressure_adds[3] - memory_pressure_adds[p];
4133+
guint64 rem = memory_pressure_removes[0] + memory_pressure_removes[1] + memory_pressure_removes[2] + memory_pressure_removes[3] - memory_pressure_removes[p];
4134+
4135+
if (new_mem_value >= min_memorypressure_budget)
4136+
{
4137+
guint64 budget = min_memorypressure_budget;
4138+
4139+
if (memory_pressure_iteration >= MEM_PRESSURE_COUNT) // wait until we have enough data points
4140+
{
4141+
// Adjust according to effectiveness of GC
4142+
// Scale budget according to past memory_pressure_adds / memory_pressure_removes ratio
4143+
if (add >= rem * MAX_MEMORYPRESSURE_RATIO)
4144+
{
4145+
budget = min_memorypressure_budget * MAX_MEMORYPRESSURE_RATIO;
4146+
}
4147+
else if (add > rem)
4148+
{
4149+
g_assert (rem != 0);
4150+
4151+
// Avoid overflow by calculating addPressure / remPressure as fixed point (1 = 1024)
4152+
budget = (add * 1024 / rem) * budget / 1024;
4153+
}
4154+
}
4155+
4156+
// If still over budget, check current managed heap size
4157+
if (new_mem_value >= budget)
4158+
{
4159+
guint64 heap_over_3 = sgen_gc_info.heap_size_bytes / 3;
4160+
4161+
if (budget < heap_over_3) // Max
4162+
{
4163+
budget = heap_over_3;
4164+
}
4165+
4166+
if (new_mem_value >= budget)
4167+
{
4168+
// last check - if we would exceed 20% of GC "duty cycle", do not trigger GC at this time
4169+
if ((size_t)(mono_time_since_last_stw() + time_last) > (time_last * 5))
4170+
{
4171+
sgen_gc_collect (GENERATION_OLD);
4172+
check_pressure_counts ();
4173+
}
4174+
}
4175+
}
4176+
}
4177+
}
4178+
40864179
#endif /* HAVE_SGEN_GC */

src/mono/mono/sgen/sgen-gc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,9 @@ sgen_dummy_use (gpointer v)
12301230
#endif
12311231
}
12321232

1233+
void sgen_add_memory_pressure(guint64 value);
1234+
void sgen_remove_memory_pressure(guint64 value);
1235+
12331236
#endif /* HAVE_SGEN_GC */
12341237

12351238
#endif /* __MONO_SGENGC_H__ */

0 commit comments

Comments
 (0)