Skip to content

Commit

Permalink
Use concurrent dictionary in NMM - 17.11 backport (#17571)
Browse files Browse the repository at this point in the history
* Use concurrent dictionary in NameMultiMap for CE yield cache (#17565)

* Fixes
  • Loading branch information
vzarytovskii authored Aug 20, 2024
1 parent b1b810f commit 1d32c75
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5540,7 +5540,7 @@ let emptyTcEnv g =
eCallerMemberName = None
eLambdaArgInfos = []
eIsControlFlow = false
eCachedImplicitYieldExpressions = HashMultiMap(HashIdentity.Structural) }
eCachedImplicitYieldExpressions = HashMultiMap(HashIdentity.Structural, useConcurrentDictionary = true) }

let CreateInitialTcEnv(g, amap, scopem, assemblyName, ccus) =
(emptyTcEnv g, ccus) ||> List.collectFold (fun env (ccu, autoOpens, internalsVisible) ->
Expand Down
56 changes: 34 additions & 22 deletions src/Compiler/Utilities/HashMultiMap.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,56 @@
namespace Internal.Utilities.Collections

open System.Collections.Generic
open System.Collections.Concurrent

// Each entry in the HashMultiMap dictionary has at least one entry. Under normal usage each entry has _only_
// one entry. So use two hash tables: one for the main entries and one for the overflow.
[<Sealed>]
type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<'Key>) =
type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<'Key>, ?useConcurrentDictionary: bool) =

let firstEntries = Dictionary<_, _>(size, comparer)
let comparer = comparer

let rest = Dictionary<_, _>(3, comparer)
let firstEntries: IDictionary<_, _> =
if defaultArg useConcurrentDictionary false then
ConcurrentDictionary<_, _>(comparer)
else
Dictionary<_, _>(size, comparer)

new(comparer: IEqualityComparer<'Key>) = HashMultiMap<'Key, 'Value>(11, comparer)
let rest: IDictionary<_, _> =
if defaultArg useConcurrentDictionary false then
ConcurrentDictionary<_, _>(comparer)
else
Dictionary<_, _>(3, comparer)

new(entries: seq<'Key * 'Value>, comparer: IEqualityComparer<'Key>) as x =
new HashMultiMap<'Key, 'Value>(11, comparer)
then entries |> Seq.iter (fun (k, v) -> x.Add(k, v))
new(comparer: IEqualityComparer<'Key>, ?useConcurrentDictionary: bool) =
HashMultiMap<'Key, 'Value>(11, comparer, defaultArg useConcurrentDictionary false)

member x.GetRest(k) =
new(entries: seq<'Key * 'Value>, comparer: IEqualityComparer<'Key>, ?useConcurrentDictionary: bool) as this =
HashMultiMap<'Key, 'Value>(11, comparer, defaultArg useConcurrentDictionary false)
then entries |> Seq.iter (fun (k, v) -> this.Add(k, v))

member _.GetRest(k) =
match rest.TryGetValue k with
| true, res -> res
| _ -> []

member x.Add(y, z) =
member this.Add(y, z) =
match firstEntries.TryGetValue y with
| true, res -> rest[y] <- res :: x.GetRest(y)
| true, res -> rest[y] <- res :: this.GetRest(y)
| _ -> ()

firstEntries[y] <- z

member x.Clear() =
member _.Clear() =
firstEntries.Clear()
rest.Clear()

member x.FirstEntries = firstEntries
member _.FirstEntries = firstEntries

member x.Rest = rest
member _.Rest = rest

member x.Copy() =
let res = HashMultiMap<'Key, 'Value>(firstEntries.Count, firstEntries.Comparer)
member _.Copy() =
let res = HashMultiMap<'Key, 'Value>(firstEntries.Count, comparer)

for kvp in firstEntries do
res.FirstEntries.Add(kvp.Key, kvp.Value)
Expand Down Expand Up @@ -86,11 +98,11 @@ type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<
for z in rest do
f kvp.Key z

member x.Contains(y) = firstEntries.ContainsKey(y)
member _.Contains(y) = firstEntries.ContainsKey(y)

member x.ContainsKey(y) = firstEntries.ContainsKey(y)
member _.ContainsKey(y) = firstEntries.ContainsKey(y)

member x.Remove(y) =
member _.Remove(y) =
match firstEntries.TryGetValue y with
// NOTE: If not ok then nothing to remove - nop
| true, _res ->
Expand All @@ -108,14 +120,14 @@ type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<
| _ -> firstEntries.Remove(y) |> ignore
| _ -> ()

member x.Replace(y, z) = firstEntries[y] <- z
member _.Replace(y, z) = firstEntries[y] <- z

member x.TryFind(y) =
member _.TryFind(y) =
match firstEntries.TryGetValue y with
| true, res -> Some res
| _ -> None

member x.Count = firstEntries.Count
member _.Count = firstEntries.Count

interface IEnumerable<KeyValuePair<'Key, 'Value>> with

Expand Down Expand Up @@ -184,6 +196,6 @@ type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<
member s.CopyTo(arr, arrIndex) =
s |> Seq.iteri (fun j x -> arr[arrIndex + j] <- x)

member s.IsReadOnly = false
member _.IsReadOnly = false

member s.Count = s.Count
8 changes: 5 additions & 3 deletions src/Compiler/Utilities/HashMultiMap.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ open System.Collections.Generic
[<Sealed>]
type internal HashMultiMap<'Key, 'Value> =
/// Create a new empty mutable HashMultiMap with the given key hash/equality functions.
new: comparer: IEqualityComparer<'Key> -> HashMultiMap<'Key, 'Value>
new: comparer: IEqualityComparer<'Key> * ?useConcurrentDictionary: bool -> HashMultiMap<'Key, 'Value>

/// Create a new empty mutable HashMultiMap with an internal bucket array of the given approximate size
/// and with the given key hash/equality functions.
new: size: int * comparer: IEqualityComparer<'Key> -> HashMultiMap<'Key, 'Value>
new: size: int * comparer: IEqualityComparer<'Key> * ?useConcurrentDictionary: bool -> HashMultiMap<'Key, 'Value>

/// Build a map that contains the bindings of the given IEnumerable.
new: entries: seq<'Key * 'Value> * comparer: IEqualityComparer<'Key> -> HashMultiMap<'Key, 'Value>
new:
entries: seq<'Key * 'Value> * comparer: IEqualityComparer<'Key> * ?useConcurrentDictionary: bool ->
HashMultiMap<'Key, 'Value>

/// Make a shallow copy of the collection.
member Copy: unit -> HashMultiMap<'Key, 'Value>
Expand Down

0 comments on commit 1d32c75

Please sign in to comment.