dotnet / dotnet/fsharp

Significant allocations writing F# types using Console.Logger

Open
#16,378 6 comments 0 reactions 0 assignees View on GitHub
Area-Compiler-CodeGen Feature Improvement Theme-Performance
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 22h
Merged PRs (30d)
144

Description

### Description

I've been working on reducing memory allocation across my app after migrating to .net 8, and after I was done with the majority of C# codebase I've stumbled across huge memory allocation produced by logging.

### Configuration

```xml


Exe
net6.0





```

```fsharp

module Program

open System
open BenchmarkDotNet.Attributes
open BenchmarkDotNet.Jobs
open BenchmarkDotNet.Running
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.Logging
open Microsoft.Extensions.DependencyInjection

type StoreError =
| Exception of exn
| ErrorDuringReadingChannelFromDatabase of channel: string
| AlreadyExists of Guid
| NotFound of Guid
with member this.SerializeError (): obj =
match this with
| Exception ex -> ex
| ErrorDuringReadingChannelFromDatabase channel -> $"ErrorDuringReadingChannelFromDatabase: {channel}"
| AlreadyExists id -> $"AlreadyExists: {id}"
| NotFound id -> $"NotFound: {id}"

let sampleNotFound = NotFound(Guid.NewGuid())
let sampleException = Exception(new Exception("Test"))

[]
[]
[]
[]
type Benchmark() =
[] val mutable logger : ILogger

[]
member this.Setup() =
let builder = WebApplication.CreateBuilder();
let app = builder.Build();
this.logger <- app.Services.GetRequiredService>()

[]
member this.One() =
this.logger.LogError("Hello world {Error}", sampleNotFound);

[]
member this.Two() =
this.logger.LogError("Hello world {Error}", sampleNotFound.SerializeError())

[]
member this.Three() =
this.logger.LogError("Hello world {Error}", sampleException);

[]
member this.Four() =
this.logger.LogError("Hello world {Error}", sampleException.SerializeError());


[]
let Run (args: string array) =
BenchmarkRunner.Run() |> ignore
0

```

### Regression?

| Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Allocated |
|---------------------- |------------------ |--------- |---------:|----------:|---------:|-------:|----------:|
| 'Raw NotFound' | ShortRun-.NET 6.0 | .NET 6.0 | 221.7 us | 78.49 us | 4.30 us | 0.2441 | 36.43 KB |
| 'Processed NotFound' | ShortRun-.NET 6.0 | .NET 6.0 | 210.7 us | 23.75 us | 1.30 us | - | 1.89 KB |
| 'Raw Exception' | ShortRun-.NET 6.0 | .NET 6.0 | 210.8 us | 94.25 us | 5.17 us | 0.2441 | 35.6 KB |
| 'Processed Exception' | ShortRun-.NET 6.0 | .NET 6.0 | 214.6 us | 141.40 us | 7.75 us | - | 1.51 KB |
| 'Raw NotFound' | ShortRun-.NET 7.0 | .NET 7.0 | 213.3 us | 21.77 us | 1.19 us | 0.2441 | 36.64 KB |
| 'Processed NotFound' | ShortRun-.NET 7.0 | .NET 7.0 | 215.6 us | 211.11 us | 11.57 us | - | 1.8 KB |
| 'Raw Exception' | ShortRun-.NET 7.0 | .NET 7.0 | 213.5 us | 170.31 us | 9.34 us | 0.2441 | 35.82 KB |
| 'Processed Exception' | ShortRun-.NET 7.0 | .NET 7.0 | 210.5 us | 55.88 us | 3.06 us | - | 1.41 KB |
| 'Raw NotFound' | ShortRun-.NET 8.0 | .NET 8.0 | 174.3 us | 772.66 us | 42.35 us | - | 36.65 KB |
| 'Processed NotFound' | ShortRun-.NET 8.0 | .NET 8.0 | 207.2 us | 147.52 us | 8.09 us | - | 1.8 KB |
| 'Raw Exception' | ShortRun-.NET 8.0 | .NET 8.0 | 174.7 us | 680.77 us | 37.32 us | - | 35.83 KB |
| 'Processed Exception' | ShortRun-.NET 8.0 | .NET 8.0 | 217.6 us | 73.26 us | 4.02 us | - | 1.41 KB |

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.