fantomas icon indicating copy to clipboard operation
fantomas copied to clipboard

Use FSharp.Core.Extended

Open nojaf opened this issue 8 months ago • 7 comments

Before

| Method | Mean     | Error    | StdDev   | Rank | Gen0     | Gen1     | Allocated |
|------- |---------:|---------:|---------:|-----:|---------:|---------:|----------:|
| Format | 60.39 ms | 1.102 ms | 1.312 ms |    1 | 888.8889 | 333.3333 | 155.13 MB |

After

| Method | Mean     | Error    | StdDev   | Rank | Gen0     | Gen1     | Allocated |
|------- |---------:|---------:|---------:|-----:|---------:|---------:|----------:|
| Format | 60.51 ms | 0.489 ms | 0.458 ms |    1 | 888.8889 | 333.3333 | 155.13 MB |

It didn't really do anything for this repo. Maybe I missed something in setting this up, although we probably don't use any of the optimized APIs.

//cc @vzarytovskii

nojaf avatar May 19 '25 07:05 nojaf

Yeah, fair. I will look at the fantomas codebase and see what it can benefit from.

vzarytovskii avatar May 19 '25 07:05 vzarytovskii

Does it need a open FSharp.Core.Extended.Collections to use the alternate functions?

Yeah, fair. I will look at the fantomas codebase and see what it can benefit from.

A quick attempt at profiling suggests that a version of Seq.tryHead using ValueOption might shave off some Option allocations in a few places fwiw

Numpsy avatar May 23 '25 15:05 Numpsy

Does it need a open FSharp.Core.Extended.Collections to use the alternate functions?

Yeah, fair. I will look at the fantomas codebase and see what it can benefit from.

A quick attempt at profiling suggests that a version of Seq.tryHead using ValueOption might shave off some Option allocations in a few places fwiw

That's on my list, however on latest runtime, reference types which do not escape the stack frame can be lifted to be allocated on stack. So this might be an improvement even without that change.

vzarytovskii avatar May 23 '25 19:05 vzarytovskii

Does the automatic stack allocation require tryHead to be inline to remove the allocations in .NET 9?

A small obervation when I ran the VS memory profiler on the 'Format' benchmark in case it's of interest - it says there are 67781 allocations of 0 length arrays of TriviaNode -

image

Those all appear to be from creating Queues with an explicit 0 capacity at https://github.com/fsprojects/fantomas/blob/bc7402c39c56fc7cf996e3c2243cff6f3d279618/src/Fantomas.Core/SyntaxOak.fs#L34 because it appears that Queue always creates a new array when a capacity is specified, even if the capacity is 0, and just using the default constructor instead there reduces the reported memory allocations in the benchmark from 155.09 MB to 153.53 MB

Numpsy avatar May 24 '25 15:05 Numpsy

On the related thought, would the Array.choose |> Array.tryHead at https://github.com/fsprojects/fantomas/blob/d21ab681da1328407aa4d607e67e1174d6214629/src/Fantomas.Core/Trivia.fs#L161 work as Array.tryPick ?

Numpsy avatar Jun 12 '25 10:06 Numpsy

On the related thought, would the Array.choose |> Array.tryHead at

https://github.com/fsprojects/fantomas/blob/d21ab681da1328407aa4d607e67e1174d6214629/src/Fantomas.Core/Trivia.fs#L161

work as Array.tryPick ?

Probably, would accept a PR, but I doubt it will have much impact.

nojaf avatar Jun 12 '25 12:06 nojaf

Saves 0.37MB of memory allocations in the benchmark project according to BDN, which is admitedly small compared to 155MB overall

Numpsy avatar Jun 12 '25 13:06 Numpsy

Going to close this, but would accept/consider a new PR with this idea.

nojaf avatar Nov 12 '25 09:11 nojaf