Browse Source

Make HeapInc.gs.hugeUsed atomic.

Rika Ichinose 2 months ago
parent
commit
1ca244023f
1 changed files with 22 additions and 15 deletions
  1. 22 15
      rtl/inc/heap.inc

+ 22 - 15
rtl/inc/heap.inc

@@ -420,6 +420,7 @@ type
       function FreeVar(p: pointer): SizeUint;
       function FreeVar(p: pointer): SizeUint;
       function TryResizeVar(p: pointer; size: SizeUint): pointer;
       function TryResizeVar(p: pointer; size: SizeUint): pointer;
 
 
+      class function AddToHugeUsed(delta: SizeInt): SizeUint; static;
       function AllocHuge(size: SizeUint): pointer;
       function AllocHuge(size: SizeUint): pointer;
       function FreeHuge(p: pointer): SizeUint;
       function FreeHuge(p: pointer): SizeUint;
       function TryResizeHuge(p: pointer; size: SizeUint): pointer;
       function TryResizeHuge(p: pointer; size: SizeUint): pointer;
@@ -441,7 +442,7 @@ type
 
 
     GlobalState = record
     GlobalState = record
       hugeUsed: SizeUint; { Same as non-existing “hugeAllocated” as huge chunks don’t have free space.
       hugeUsed: SizeUint; { Same as non-existing “hugeAllocated” as huge chunks don’t have free space.
-                            Protected by gs.lock, but can be read unprotected if unreliability is tolerable.
+                            Atomic, but can be read unprotected if unreliability is tolerable.
                             Huge chunks don’t have thread affinity, so are tracked here. Presently, this value is added to all memory statistics.
                             Huge chunks don’t have thread affinity, so are tracked here. Presently, this value is added to all memory statistics.
                             Not a good idea and makes multithreaded statistics a strange and unreliable mix, but alternatives are even worse. }
                             Not a good idea and makes multithreaded statistics a strange and unreliable mix, but alternatives are even worse. }
 
 
@@ -1350,9 +1351,23 @@ type
     If SysOSFree is not available, there’s no choice but to cache them.
     If SysOSFree is not available, there’s no choice but to cache them.
     Caching is done directly into gs.freeOS if FPC_HAS_FEATURE_THREADING, otherwise ThreadState.freeOS. }
     Caching is done directly into gs.freeOS if FPC_HAS_FEATURE_THREADING, otherwise ThreadState.freeOS. }
 
 
+  class function HeapInc.ThreadState.AddToHugeUsed(delta: SizeInt): SizeUint;
+  begin
+  {$if not defined(FPC_HAS_FEATURE_THREADING)}
+    result := SizeUint(SizeInt(gs.hugeUsed) + delta);
+    gs.hugeUsed := result;
+  {$elseif not defined(VER3_2)}
+    result := AtomicIncrement(gs.hugeUsed, SizeUint(delta));
+  {$elseif sizeof(SizeInt) = sizeof(int64)}
+    result := SizeUint(delta + InterlockedExchangeAdd64(SizeInt(gs.hugeUsed), delta));
+  {$else}
+    result := SizeUint(delta + InterlockedExchangeAdd(SizeInt(gs.hugeUsed), delta));
+  {$endif}
+  end;
+
   function HeapInc.ThreadState.AllocHuge(size: SizeUint): pointer;
   function HeapInc.ThreadState.AllocHuge(size: SizeUint): pointer;
   var
   var
-    userSize, hugeUsed: SizeUint;
+    userSize: SizeUint;
   begin
   begin
     userSize := size;
     userSize := size;
     size := (size + (HugeChunkDataOffset + CommonHeaderSize + OSChunkVarSizeQuant - 1)) and SizeUint(-OSChunkVarSizeQuant);
     size := (size + (HugeChunkDataOffset + CommonHeaderSize + OSChunkVarSizeQuant - 1)) and SizeUint(-OSChunkVarSizeQuant);
@@ -1380,11 +1395,7 @@ type
   {$endif HAS_SYSOSFREE}
   {$endif HAS_SYSOSFREE}
     pCommonHeader(result + HugeChunkDataOffset)^.h := HugeHeader;
     pCommonHeader(result + HugeChunkDataOffset)^.h := HugeHeader;
     inc(result, HugeChunkDataOffset + CommonHeaderSize);
     inc(result, HugeChunkDataOffset + CommonHeaderSize);
-  {$ifdef FPC_HAS_FEATURE_THREADING} EnterCriticalSection(gs.lock); {$endif}
-    hugeUsed := gs.hugeUsed + size;
-    gs.hugeUsed := hugeUsed;
-  {$ifdef FPC_HAS_FEATURE_THREADING} LeaveCriticalSection(gs.lock); {$endif}
-    UpdateMaxStats(hugeUsed);
+    UpdateMaxStats(AddToHugeUsed(size));
   end;
   end;
 
 
   function HeapInc.ThreadState.FreeHuge(p: pointer): SizeUint;
   function HeapInc.ThreadState.FreeHuge(p: pointer): SizeUint;
@@ -1396,11 +1407,11 @@ type
   begin
   begin
     dec(p, HugeChunkDataOffset + CommonHeaderSize);
     dec(p, HugeChunkDataOffset + CommonHeaderSize);
     result := pHugeChunk(p)^.size;
     result := pHugeChunk(p)^.size;
-  {$ifdef FPC_HAS_FEATURE_THREADING} EnterCriticalSection(gs.lock); {$endif}
-    dec(gs.hugeUsed, result);
+    AddToHugeUsed(-SizeInt(result));
   {$ifndef HAS_SYSOSFREE} { But you’d better have SysOSFree... }
   {$ifndef HAS_SYSOSFREE} { But you’d better have SysOSFree... }
   {$ifdef FPC_HAS_FEATURE_THREADING}
   {$ifdef FPC_HAS_FEATURE_THREADING}
     fOs := @gs.freeOS; { gs.freeOS aren’t counted anywhere (for now). }
     fOs := @gs.freeOS; { gs.freeOS aren’t counted anywhere (for now). }
+    EnterCriticalSection(gs.lock);
   {$else FPC_HAS_FEATURE_THREADING}
   {$else FPC_HAS_FEATURE_THREADING}
     fOs := @freeOS;
     fOs := @freeOS;
     inc(allocated, result); { ThreadState.freeOS are counted in ThreadState.allocated. But since “size” (= result) is just moved from “hugeUsed” to “allocated”, it won’t affect maximums. }
     inc(allocated, result); { ThreadState.freeOS are counted in ThreadState.allocated. But since “size” (= result) is just moved from “hugeUsed” to “allocated”, it won’t affect maximums. }
@@ -1415,8 +1426,8 @@ type
     else
     else
       fOs^.first := p;
       fOs^.first := p;
     fOs^.last := p;
     fOs^.last := p;
-  {$endif ndef HAS_SYSOSFREE}
   {$ifdef FPC_HAS_FEATURE_THREADING} LeaveCriticalSection(gs.lock); {$endif}
   {$ifdef FPC_HAS_FEATURE_THREADING} LeaveCriticalSection(gs.lock); {$endif}
+  {$endif ndef HAS_SYSOSFREE}
   {$ifdef HAS_SYSOSFREE} SysOSFree(p, result); {$endif}
   {$ifdef HAS_SYSOSFREE} SysOSFree(p, result); {$endif}
     dec(result, HugeChunkDataOffset + CommonHeaderSize);
     dec(result, HugeChunkDataOffset + CommonHeaderSize);
   end;
   end;
@@ -1438,11 +1449,7 @@ type
     result := SysOSRealloc(p - (HugeChunkDataOffset + CommonHeaderSize), oldSize, size);
     result := SysOSRealloc(p - (HugeChunkDataOffset + CommonHeaderSize), oldSize, size);
     if Assigned(result) then
     if Assigned(result) then
     begin
     begin
-    {$ifdef FPC_HAS_FEATURE_THREADING} EnterCriticalSection(gs.lock); {$endif}
-      gs.hugeUsed := gs.hugeUsed - oldSize + size;
-    {$ifdef FPC_HAS_FEATURE_THREADING} LeaveCriticalSection(gs.lock); {$endif}
-      if size > oldSize then
-        UpdateMaxStats(gs.hugeUsed);
+      UpdateMaxStats(AddToHugeUsed(SizeInt(size) - SizeInt(oldSize)));
       pHugeChunk(result)^.size := size;
       pHugeChunk(result)^.size := size;
       inc(result, HugeChunkDataOffset + CommonHeaderSize);
       inc(result, HugeChunkDataOffset + CommonHeaderSize);
     end;
     end;