From 2908f1976cc78c77aff28735a294e4cc146e472d Mon Sep 17 00:00:00 2001 From: Phillip Carter Date: Thu, 19 Dec 2019 14:45:41 -0800 Subject: [PATCH 1/2] Set LOH threshold for chunked resizearray to be smaller to avoid LOH allocations --- src/absil/illib.fs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/absil/illib.fs b/src/absil/illib.fs index 0a7d471e141..1c71edbd7f6 100644 --- a/src/absil/illib.fs +++ b/src/absil/illib.fs @@ -40,8 +40,9 @@ let inline nonNull msg x = if isNull x then failwith ("null: " + msg) else x let inline (===) x y = LanguagePrimitives.PhysicalEquality x y /// Per the docs the threshold for the Large Object Heap is 85000 bytes: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap#how-an-object-ends-up-on-the-large-object-heap-and-how-gc-handles-them -/// We set the limit to slightly under that to allow for some 'slop' -let LOH_SIZE_THRESHOLD_BYTES = 84_900 +/// We set the limit to be lower than that because F# can run in a 64-bit environment where a value of 85k would actually still result in an LOH allocation. +/// A limit of 1024 is not going to do that, and frankly, 1024 is still a pretty decently-sized chunk. +let REASONABLE_THRESHOLD_TO_AVOID_LOH = 1024 //--------------------------------------------------------------------- // Library: ReportTime @@ -472,7 +473,11 @@ module ResizeArray = let mapToSmallArrayChunks f (inp: ResizeArray<'t>) = let itemSizeBytes = sizeof<'t> // rounding down here is good because it ensures we don't go over - let maxArrayItemCount = LOH_SIZE_THRESHOLD_BYTES / itemSizeBytes + let maxArrayItemCount = + if itemSizeBytes < REASONABLE_THRESHOLD_TO_AVOID_LOH then + REASONABLE_THRESHOLD_TO_AVOID_LOH / itemSizeBytes + else + REASONABLE_THRESHOLD_TO_AVOID_LOH /// chunk the provided input into arrays that are smaller than the LOH limit /// in order to prevent long-term storage of those values From 4d990e41aca21180c7482f75a6931ec4785fb1a8 Mon Sep 17 00:00:00 2001 From: Phillip Carter Date: Fri, 20 Dec 2019 07:52:47 -0800 Subject: [PATCH 2/2] Update illib.fs --- src/absil/illib.fs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/absil/illib.fs b/src/absil/illib.fs index 1c71edbd7f6..9a84e94e34a 100644 --- a/src/absil/illib.fs +++ b/src/absil/illib.fs @@ -40,9 +40,8 @@ let inline nonNull msg x = if isNull x then failwith ("null: " + msg) else x let inline (===) x y = LanguagePrimitives.PhysicalEquality x y /// Per the docs the threshold for the Large Object Heap is 85000 bytes: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap#how-an-object-ends-up-on-the-large-object-heap-and-how-gc-handles-them -/// We set the limit to be lower than that because F# can run in a 64-bit environment where a value of 85k would actually still result in an LOH allocation. -/// A limit of 1024 is not going to do that, and frankly, 1024 is still a pretty decently-sized chunk. -let REASONABLE_THRESHOLD_TO_AVOID_LOH = 1024 +/// We set the limit to be 80k to account for larger pointer sizes for when F# is running 64-bit. +let LOH_SIZE_THRESHOLD_BYTES = 80_000 //--------------------------------------------------------------------- // Library: ReportTime @@ -473,11 +472,7 @@ module ResizeArray = let mapToSmallArrayChunks f (inp: ResizeArray<'t>) = let itemSizeBytes = sizeof<'t> // rounding down here is good because it ensures we don't go over - let maxArrayItemCount = - if itemSizeBytes < REASONABLE_THRESHOLD_TO_AVOID_LOH then - REASONABLE_THRESHOLD_TO_AVOID_LOH / itemSizeBytes - else - REASONABLE_THRESHOLD_TO_AVOID_LOH + let maxArrayItemCount = LOH_SIZE_THRESHOLD_BYTES / itemSizeBytes /// chunk the provided input into arrays that are smaller than the LOH limit /// in order to prevent long-term storage of those values