Makes GetTotalAllocatedBytes monotonic in nonprecise case. (#24875)
authorVladimir Sadov <vsadov@microsoft.com>
Fri, 31 May 2019 14:45:03 +0000 (07:45 -0700)
committerGitHub <noreply@github.com>
Fri, 31 May 2019 14:45:03 +0000 (07:45 -0700)
* Makes GetTotalAllocatedBytes monotonic in nonprecise case.

Fixes:#24615

* read `dead_threads_non_alloc_bytes` atomically on 32bit platforms

* Update src/vm/comutilnative.cpp

Co-Authored-By: Jan Kotas <jkotas@microsoft.com>
src/vm/comutilnative.cpp

index 8d3879e..3305b8a 100644 (file)
@@ -1293,12 +1293,30 @@ FCIMPL1(INT64, GCInterface::GetTotalAllocatedBytes, CLR_BOOL precise)
 
     if (!precise)
     {
-        // NOTE: we do not want to make imprecise flavor too slow. 
-        // As it could be noticed we read 64bit values that may be concurrently updated.
-        // Such reads are not guaranteed to be atomic on 32bit and inrare cases we may see torn values resultng in outlier results.
-        // That would be extremely rare and in a context of imprecise helper is not worth additional synchronization.
+#ifdef _TARGET_64BIT_
         uint64_t unused_bytes = Thread::dead_threads_non_alloc_bytes;
-        return GCHeapUtilities::GetGCHeap()->GetTotalAllocatedBytes() - unused_bytes;
+#else
+        // As it could be noticed we read 64bit values that may be concurrently updated.
+        // Such reads are not guaranteed to be atomic on 32bit so extra care should be taken.
+        uint64_t unused_bytes = FastInterlockCompareExchangeLong((LONG64*)& Thread::dead_threads_non_alloc_bytes, 0, 0);
+#endif
+
+        uint64_t allocated_bytes = GCHeapUtilities::GetGCHeap()->GetTotalAllocatedBytes() - unused_bytes;
+
+        // highest reported allocated_bytes. We do not want to report a value less than that even if unused_bytes has increased.
+        static uint64_t high_watermark;
+
+        uint64_t current_high = high_watermark;
+        while (allocated_bytes > current_high)
+        {           
+            uint64_t orig = FastInterlockCompareExchangeLong((LONG64*)& high_watermark, allocated_bytes, current_high);
+            if (orig == current_high)
+                return allocated_bytes;
+
+            current_high = orig;
+        }
+
+        return current_high;
     }
 
     INT64 allocated;