[MicroPerf] Avoid Choice allocation in fslib entity/val-ref equality - #20350
Conversation
|
|
Out of curiosity, would making the active patterns here ValueChoice instead have resulted in the same allocation savings? In my ideal world, we could use the nice AP features without paying the costs of them! |
4c26b20 to
88360f6
Compare
|
@baronfel : We don't have any ValueChoice , but you are right - we probably should!? EDIT: |
|
The problem is the structs might get really big with more cases. |
5ceec7c to
d5b5f53
Compare
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
d5b5f53 to
37ed1a9
Compare
# Conflicts: # src/Compiler/TypedTree/TypedTreeBasics.fs
fslibRefEq compared nlr1.Path against path2.FullPath, but PublicPath.FullPath (after #20285 derives paths instead of storing them) builds a MangledPath list plus a string[] on every call. This runs in the fslib-compile entity/val-ref equality hot path. Walk the enclosing AccessPath as a list while indexing nlr1.Path as an array instead: same O(N), zero allocation, mirroring the pubPathEq treatment #20285 already applied to its sibling. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
fslibEntityRefEqandfslibValRefEqcompare a tuple of refs against the two-case total active patterns|ERefLocal|ERefNonLocal|/|VRefLocal|VRefNonLocal|, which return a heap-allocatedChoice. These run for every entity/val-ref equality while compiling FSharp.Core, so theChoiceallocation dominates. This replaces those matches with[<return: Struct>] inlineactive patterns that return aValueOption(unboxed) and read the ref's local/non-local payload directly — same match shape, no heap allocation.Measured compiling FSharp.Core with the built compiler (
dotnet-trace --profile gc-verbose):The emitted
FSharp.Core.dllis byte-for-byte identical tomain(deterministic build, SHA-256 unchanged) — ref equality feeds optimization and codegen, so this preserves output exactly.