Skip to content

Enable TypeSubsumptionCache for IDE use #18499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
May 1, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5233567
add cache
majocha Apr 24, 2025
df70074
enable typeSubsumptionCache in IDE
majocha Apr 24, 2025
460f592
add some monitoring
majocha Apr 24, 2025
e94a9e5
Merge branch 'main' into compiler-cache
majocha Apr 24, 2025
b2a130a
yeet LFU
majocha Apr 24, 2025
4c7e044
flesh out the comparer
majocha Apr 24, 2025
a269b6a
fix sources
majocha Apr 24, 2025
874d9c1
try to deal with CI memory overload
majocha Apr 24, 2025
c266706
Merge branch 'main' into compiler-cache
majocha Apr 24, 2025
4bca2df
replace singleton with CWT again
majocha Apr 25, 2025
9ba405d
remove sketchy logic
majocha Apr 25, 2025
5c6a500
cache of caches
majocha Apr 25, 2025
605c967
Merge branch 'main' into compiler-cache
majocha Apr 25, 2025
3046f88
ilver
majocha Apr 25, 2025
80dc554
events -> counters
majocha Apr 25, 2025
6926f97
precompute hash
majocha Apr 25, 2025
ec8fab4
no metrics in ci
majocha Apr 26, 2025
59cb94e
simplify
majocha Apr 26, 2025
b8ba293
simplify
majocha Apr 26, 2025
13cded8
clean up
majocha Apr 26, 2025
365ae5b
cut unnecessary stuff
majocha Apr 26, 2025
96fa966
add name
majocha Apr 27, 2025
2743a4d
naming
majocha Apr 27, 2025
8b2b986
basic tests
majocha Apr 28, 2025
8e4f662
Merge branch 'main' into compiler-cache
majocha Apr 28, 2025
bf17afa
rn
majocha Apr 28, 2025
d49e276
fix tests
majocha Apr 28, 2025
f7f766e
Merge branch 'main' into compiler-cache
majocha Apr 28, 2025
aa76a84
ilver
majocha Apr 28, 2025
a182b36
use MailboxProcessor for lock-free eviction handling
majocha Apr 29, 2025
d6b3ac9
ilverify
majocha Apr 29, 2025
523fea3
return
majocha Apr 29, 2025
9c70966
restore cts
majocha Apr 29, 2025
4ae54c0
Merge branch 'main' into compiler-cache
majocha Apr 30, 2025
95b8115
Merge branch 'main' into compiler-cache
majocha Apr 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
no metrics in ci
  • Loading branch information
majocha committed Apr 26, 2025
commit ec8fab4d49193dfad72c420d996a6b955cb3483c
35 changes: 35 additions & 0 deletions eng/eng.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DumpPackageRoot", "DumpPackageRoot\DumpPackageRoot.csproj", "{B89EE536-0BE7-2F71-3534-80C865BF7F34}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{881589EE-639B-0A35-DBCE-5D94E4FC90C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools", "common\internal\Tools.csproj", "{EC3C2A6A-F9C1-3B52-791D-863B6891FEFB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B89EE536-0BE7-2F71-3534-80C865BF7F34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B89EE536-0BE7-2F71-3534-80C865BF7F34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B89EE536-0BE7-2F71-3534-80C865BF7F34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B89EE536-0BE7-2F71-3534-80C865BF7F34}.Release|Any CPU.Build.0 = Release|Any CPU
{EC3C2A6A-F9C1-3B52-791D-863B6891FEFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC3C2A6A-F9C1-3B52-791D-863B6891FEFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC3C2A6A-F9C1-3B52-791D-863B6891FEFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC3C2A6A-F9C1-3B52-791D-863B6891FEFB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{EC3C2A6A-F9C1-3B52-791D-863B6891FEFB} = {881589EE-639B-0A35-DBCE-5D94E4FC90C0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {69994860-C020-43F2-8564-C0EAC60E82FE}
EndGlobalSection
EndGlobal
4 changes: 2 additions & 2 deletions src/Compiler/Checking/import.fs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ let createTypeSubsumptionCache (g: TcGlobals) =
| CompilationMode.OneOff ->
// This is a one-off compilation, so we don't need to worry about eviction.
{ CacheOptions.Default with
MaximumCapacity = 4 * 1024
MaximumCapacity = 4 * 32768
EvictionMethod = EvictionMethod.NoEviction }
| _ ->
// Incremental use, so we need to set up the cache with eviction.
Expand All @@ -110,7 +110,7 @@ let createTypeSubsumptionCache (g: TcGlobals) =
MaximumCapacity = 4 * 32768 }
Cache.Create<TTypeCacheKey, bool>(options)

let typeSubsumptionCaches = Cache.Create<TcGlobals, Cache<TTypeCacheKey, bool>>({ CacheOptions.Default with MaximumCapacity = 16 })
let typeSubsumptionCaches = Cache.Create<TcGlobals, Cache<TTypeCacheKey, bool>>({ CacheOptions.Default with MaximumCapacity = 24 })

do typeSubsumptionCaches.ValueEvicted.Add <| _.Dispose()

Expand Down
11 changes: 7 additions & 4 deletions src/Compiler/Utilities/Caches.fs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type CacheMetrics(cacheId) =

let readings = ConcurrentDictionary<string, int64 ref>()

#if DEBUG
let listener =
new MeterListener(
InstrumentPublished =
Expand All @@ -82,6 +83,11 @@ type CacheMetrics(cacheId) =
listener.SetMeasurementEventCallback<int64>(fun k v _ _ -> Interlocked.Add(readings.GetOrAdd(k.Name, ref 0L), v) |> ignore)
listener.Start()

member this.Dispose() = listener.Dispose()
#else
member this.Dispose() = ()
#endif

member val CacheId = cacheId

member val RecentStats = "-" with get, set
Expand Down Expand Up @@ -116,8 +122,6 @@ type CacheMetrics(cacheId) =
else
false

member this.Dispose() = listener.Dispose()

static member GetStats(cacheId) =
instrumentedCaches[cacheId].TryUpdateStats(false) |> ignore
instrumentedCaches[cacheId].RecentStats
Expand Down Expand Up @@ -342,8 +346,7 @@ module Cache =
let applyOverride (options: CacheOptions) =
let capacity =
match Environment.GetEnvironmentVariable(overrideVariable) with
| NonNull _ when options.MaximumCapacity < 100 -> 5
| NonNull _ -> 8912
| NonNull _ when options.MaximumCapacity > 1024 -> 1024
| _ -> options.MaximumCapacity

{ options with
Expand Down
74 changes: 42 additions & 32 deletions tests/FSharp.Test.Utilities/XunitHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,46 @@ type CustomTheoryTestCase =

#endif


type OpenTelemetryExport(testRunName, enable) =
// On Windows forwarding localhost to wsl2 docker container sometimes does not work. Use IP address instead.
let otlpEndpoint = Uri("http://127.0.0.1:4317")

// Configure OpenTelemetry export.
let providers : IDisposable list =
if not enable then [] else
[
// Configure OpenTelemetry tracing export. Traces can be viewed in Jaeger or other compatible tools.
OpenTelemetry.Sdk.CreateTracerProviderBuilder()
.AddSource(ActivityNames.FscSourceName)
.ConfigureResource(fun r -> r.AddService("F#") |> ignore)
.AddOtlpExporter(fun o ->
o.Endpoint <- otlpEndpoint
o.Protocol <- OpenTelemetry.Exporter.OtlpExportProtocol.Grpc
// Empirical values to ensure no traces are lost and no significant delay at the end of test run.
o.TimeoutMilliseconds <- 200
o.BatchExportProcessorOptions.MaxQueueSize <- 16384
o.BatchExportProcessorOptions.ScheduledDelayMilliseconds <- 100
)
.Build()

// Configure OpenTelemetry metrics export. Metrics can be viewed in Prometheus or other compatible tools.
OpenTelemetry.Sdk.CreateMeterProviderBuilder()
.AddMeter(nameof FSharp.Compiler.CacheMetrics)
.AddMeter("System.Runtime")
.ConfigureResource(fun r -> r.AddService(testRunName) |> ignore)
.AddOtlpExporter(fun e m ->
e.Endpoint <- otlpEndpoint
e.Protocol <- OpenTelemetry.Exporter.OtlpExportProtocol.Grpc
m.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds <- 1000
)
.Build()
]

interface IDisposable with
member this.Dispose() =
for p in providers do p.Dispose()

/// `XunitTestFramework` providing parallel console support and conditionally enabling optional xUnit customizations.
type FSharpXunitFramework(sink: IMessageSink) =
inherit XunitTestFramework(sink)
Expand All @@ -150,37 +190,9 @@ type FSharpXunitFramework(sink: IMessageSink) =
FSharp.Compiler.Cache.OverrideMaxCapacityForTesting()

let testRunName = $"RunTests_{assemblyName.Name} {Runtime.InteropServices.RuntimeInformation.FrameworkDescription}"

// On Windows forwarding localhost to wsl2 docker container sometimes does not work. Use IP address instead.
let otlpEndpoint = Uri("http://127.0.0.1:4317")

// Configure OpenTelemetry export. Traces can be viewed in Jaeger or other compatible tools.
use tracerProvider =
OpenTelemetry.Sdk.CreateTracerProviderBuilder()
.AddSource(ActivityNames.FscSourceName)
.ConfigureResource(fun r -> r.AddService("F#") |> ignore)
.AddOtlpExporter(fun o ->
o.Endpoint <- otlpEndpoint
o.Protocol <- OpenTelemetry.Exporter.OtlpExportProtocol.Grpc
// Empirical values to ensure no traces are lost and no significant delay at the end of test run.
o.TimeoutMilliseconds <- 200
o.BatchExportProcessorOptions.MaxQueueSize <- 16384
o.BatchExportProcessorOptions.ScheduledDelayMilliseconds <- 100
)
.Build()

use meterProvider =
OpenTelemetry.Sdk.CreateMeterProviderBuilder()
.AddMeter(nameof FSharp.Compiler.CacheMetrics)
.AddMeter("System.Runtime")
.ConfigureResource(fun r -> r.AddService(testRunName) |> ignore)
.AddOtlpExporter(fun e m ->
e.Endpoint <- otlpEndpoint
e.Protocol <- OpenTelemetry.Exporter.OtlpExportProtocol.Grpc
m.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds <- 1000
)
.Build()

use _ = new OpenTelemetryExport(testRunName, Environment.GetEnvironmentVariable("FSHARP_OTEL_EXPORT") <> null)

logConfig initialConfig
log "Installing TestConsole redirection"
TestConsole.install()
Expand All @@ -192,8 +204,6 @@ type FSharpXunitFramework(sink: IMessageSink) =
runner.RunAsync().Wait()
end

tracerProvider.ForceFlush() |> ignore

cleanUpTemporaryDirectoryOfThisTestRun ()
}

Expand Down
Loading