diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index 45b5bda0d10..cde4e8aea1e 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -95,6 +95,8 @@ + + diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index fbff9619b88..cf67ff37d15 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -560,7 +560,7 @@ and [] FSha referencedProjects: FSharpReferencedProjectSnapshot list, isIncompleteTypeCheckEnvironment: bool, useScriptResolutionRules: bool, - loadTime: DateTime, + loadTime: DateTime, unresolvedReferences: FSharpUnresolvedReferencesSet option, originalLoadReferences: (range * string * string) list, stamp: int64 option @@ -676,27 +676,32 @@ and [] FSha |> async.Return FSharpProjectSnapshot.FromOptions(options, getFileSnapshot) + +let internal snapshotTable = ConditionalWeakTable() + +let rec internal snapshotToOptions (projectSnapshot: ProjectSnapshot) = + snapshotTable.GetValue(projectSnapshot, fun projectSnapshot -> + { + ProjectFileName = projectSnapshot.ProjectFileName + ProjectId = projectSnapshot.ProjectId + SourceFiles = projectSnapshot.SourceFiles |> Seq.map (fun x -> x.FileName) |> Seq.toArray + OtherOptions = projectSnapshot.CommandLineOptions |> List.toArray + ReferencedProjects = + projectSnapshot.ReferencedProjects + |> Seq.map (function + | FSharpReference(name, opts) -> FSharpReferencedProject.FSharpReference(name, opts.ProjectSnapshot |> snapshotToOptions) + | PEReference(getStamp, reader) -> FSharpReferencedProject.PEReference(getStamp, reader) + | ILModuleReference(name, getStamp, getReader) -> FSharpReferencedProject.ILModuleReference(name, getStamp, getReader)) + |> Seq.toArray + IsIncompleteTypeCheckEnvironment = projectSnapshot.IsIncompleteTypeCheckEnvironment + UseScriptResolutionRules = projectSnapshot.UseScriptResolutionRules + LoadTime = projectSnapshot.LoadTime + UnresolvedReferences = projectSnapshot.UnresolvedReferences + OriginalLoadReferences = projectSnapshot.OriginalLoadReferences + Stamp = projectSnapshot.Stamp + } + ) -let rec internal snapshotToOptions (projectSnapshot: ProjectSnapshotBase<_>) = - { - ProjectFileName = projectSnapshot.ProjectFileName - ProjectId = projectSnapshot.ProjectId - SourceFiles = projectSnapshot.SourceFiles |> Seq.map (fun x -> x.FileName) |> Seq.toArray - OtherOptions = projectSnapshot.CommandLineOptions |> List.toArray - ReferencedProjects = - projectSnapshot.ReferencedProjects - |> Seq.map (function - | FSharpReference(name, opts) -> FSharpReferencedProject.FSharpReference(name, opts.ProjectSnapshot |> snapshotToOptions) - | PEReference(getStamp, reader) -> FSharpReferencedProject.PEReference(getStamp, reader) - | ILModuleReference(name, getStamp, getReader) -> FSharpReferencedProject.ILModuleReference(name, getStamp, getReader)) - |> Seq.toArray - IsIncompleteTypeCheckEnvironment = projectSnapshot.IsIncompleteTypeCheckEnvironment - UseScriptResolutionRules = projectSnapshot.UseScriptResolutionRules - LoadTime = projectSnapshot.LoadTime - UnresolvedReferences = projectSnapshot.UnresolvedReferences - OriginalLoadReferences = projectSnapshot.OriginalLoadReferences - Stamp = projectSnapshot.Stamp - } [] type internal Extensions = diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 735a6b241f1..65d61fa5927 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -258,45 +258,119 @@ module private TypeCheckingGraphProcessing = return finalFileResults, state } - -type internal CompilerCaches(sizeFactor: int) = +type CacheSizes = { + ParseFileKeepStrongly: int + ParseFileKeepWeakly: int + ParseFileWithoutProjectKeepStrongly: int + ParseFileWithoutProjectKeepWeakly: int + ParseAndCheckFileInProjectKeepStrongly: int + ParseAndCheckFileInProjectKeepWeakly: int + ParseAndCheckAllFilesInProjectKeepStrongly: int + ParseAndCheckAllFilesInProjectKeepWeakly: int + ParseAndCheckProjectKeepStrongly: int + ParseAndCheckProjectKeepWeakly: int + FrameworkImportsKeepStrongly: int + FrameworkImportsKeepWeakly: int + BootstrapInfoStaticKeepStrongly: int + BootstrapInfoStaticKeepWeakly: int + BootstrapInfoKeepStrongly: int + BootstrapInfoKeepWeakly: int + TcLastFileKeepStrongly: int + TcLastFileKeepWeakly: int + TcIntermediateKeepStrongly: int + TcIntermediateKeepWeakly: int + DependencyGraphKeepStrongly: int + DependencyGraphKeepWeakly: int + ProjectExtrasKeepStrongly: int + ProjectExtrasKeepWeakly: int + AssemblyDataKeepStrongly: int + AssemblyDataKeepWeakly: int + SemanticClassificationKeepStrongly: int + SemanticClassificationKeepWeakly: int + ItemKeyStoreKeepStrongly: int + ItemKeyStoreKeepWeakly: int + ScriptClosureKeepStrongly: int + ScriptClosureKeepWeakly: int +} +with + static member Create sizeFactor = + + { + ParseFileKeepStrongly = 50 * sizeFactor + ParseFileKeepWeakly = 20 * sizeFactor + ParseFileWithoutProjectKeepStrongly = 5 * sizeFactor + ParseFileWithoutProjectKeepWeakly = 2 * sizeFactor + ParseAndCheckFileInProjectKeepStrongly = sizeFactor + ParseAndCheckFileInProjectKeepWeakly = 2 * sizeFactor + ParseAndCheckAllFilesInProjectKeepStrongly = sizeFactor + ParseAndCheckAllFilesInProjectKeepWeakly = 2 * sizeFactor + ParseAndCheckProjectKeepStrongly = sizeFactor + ParseAndCheckProjectKeepWeakly = 2 * sizeFactor + FrameworkImportsKeepStrongly = sizeFactor + FrameworkImportsKeepWeakly = 2 * sizeFactor + BootstrapInfoStaticKeepStrongly = sizeFactor + BootstrapInfoStaticKeepWeakly = 2 * sizeFactor + BootstrapInfoKeepStrongly = sizeFactor + BootstrapInfoKeepWeakly = 2 * sizeFactor + TcLastFileKeepStrongly = sizeFactor + TcLastFileKeepWeakly = 2 * sizeFactor + TcIntermediateKeepStrongly = 20 * sizeFactor + TcIntermediateKeepWeakly = 20 * sizeFactor + DependencyGraphKeepStrongly = sizeFactor + DependencyGraphKeepWeakly = 2 * sizeFactor + ProjectExtrasKeepStrongly = sizeFactor + ProjectExtrasKeepWeakly = 2 * sizeFactor + AssemblyDataKeepStrongly = sizeFactor + AssemblyDataKeepWeakly = 2 * sizeFactor + SemanticClassificationKeepStrongly = sizeFactor + SemanticClassificationKeepWeakly = 2 * sizeFactor + ItemKeyStoreKeepStrongly = sizeFactor + ItemKeyStoreKeepWeakly = 2 * sizeFactor + ScriptClosureKeepStrongly = sizeFactor + ScriptClosureKeepWeakly = 2 * sizeFactor + } + + static member Default = + let sizeFactor = 100 + CacheSizes.Create sizeFactor +type internal CompilerCaches(sizeFactor: CacheSizes) = let sf = sizeFactor - member _.SizeFactor = sf + member _.CacheSizes = sf - member val ParseFile = AsyncMemoize(keepStrongly = 50 * sf, keepWeakly = 20 * sf, name = "ParseFile") + member val ParseFile = AsyncMemoize(keepStrongly = sf.ParseFileKeepStrongly, keepWeakly = sf.ParseFileKeepWeakly, name = "ParseFile") member val ParseFileWithoutProject = - AsyncMemoize(keepStrongly = 5 * sf, keepWeakly = 2 * sf, name = "ParseFileWithoutProject") + AsyncMemoize(sf.ParseFileWithoutProjectKeepStrongly, keepWeakly = sf.ParseFileWithoutProjectKeepWeakly, name = "ParseFileWithoutProject") - member val ParseAndCheckFileInProject = AsyncMemoize(sf, 2 * sf, name = "ParseAndCheckFileInProject") + member val ParseAndCheckFileInProject = AsyncMemoize(sf.ParseAndCheckFileInProjectKeepStrongly, sf.ParseAndCheckFileInProjectKeepWeakly, name = "ParseAndCheckFileInProject") - member val ParseAndCheckAllFilesInProject = AsyncMemoizeDisabled(sf, 2 * sf, name = "ParseAndCheckFullProject") + member val ParseAndCheckAllFilesInProject = AsyncMemoizeDisabled(sf.ParseAndCheckAllFilesInProjectKeepStrongly, sf.ParseAndCheckAllFilesInProjectKeepWeakly, name = "ParseAndCheckFullProject") - member val ParseAndCheckProject = AsyncMemoize(sf, 2 * sf, name = "ParseAndCheckProject") + member val ParseAndCheckProject = AsyncMemoize(sf.ParseAndCheckProjectKeepStrongly, sf.ParseAndCheckProjectKeepWeakly, name = "ParseAndCheckProject") - member val FrameworkImports = AsyncMemoize(sf, 2 * sf, name = "FrameworkImports") + member val FrameworkImports = AsyncMemoize(sf.FrameworkImportsKeepStrongly, sf.FrameworkImportsKeepWeakly, name = "FrameworkImports") - member val BootstrapInfoStatic = AsyncMemoize(sf, 2 * sf, name = "BootstrapInfoStatic") + member val BootstrapInfoStatic = AsyncMemoize(sf.BootstrapInfoStaticKeepStrongly, sf.BootstrapInfoStaticKeepWeakly, name = "BootstrapInfoStatic") - member val BootstrapInfo = AsyncMemoize(sf, 2 * sf, name = "BootstrapInfo") + member val BootstrapInfo = AsyncMemoize(sf.BootstrapInfoKeepStrongly, sf.BootstrapInfoKeepWeakly, name = "BootstrapInfo") - member val TcLastFile = AsyncMemoizeDisabled(sf, 2 * sf, name = "TcLastFile") + member val TcLastFile = AsyncMemoizeDisabled(sf.TcLastFileKeepStrongly, sf.TcLastFileKeepWeakly, name = "TcLastFile") - member val TcIntermediate = AsyncMemoize(20 * sf, 20 * sf, name = "TcIntermediate") + member val TcIntermediate = AsyncMemoize(sf.TcIntermediateKeepStrongly, sf.TcIntermediateKeepWeakly, name = "TcIntermediate") - member val DependencyGraph = AsyncMemoize(sf, 2 * sf, name = "DependencyGraph") + member val DependencyGraph = AsyncMemoize(sf.DependencyGraphKeepStrongly, sf.DependencyGraphKeepWeakly, name = "DependencyGraph") - member val ProjectExtras = AsyncMemoizeDisabled(sf, 2 * sf, name = "ProjectExtras") + member val ProjectExtras = AsyncMemoizeDisabled(sf.ProjectExtrasKeepStrongly, sf.ProjectExtrasKeepWeakly, name = "ProjectExtras") - member val AssemblyData = AsyncMemoize(sf, 2 * sf, name = "AssemblyData") + member val AssemblyData = AsyncMemoize(sf.AssemblyDataKeepStrongly, sf.AssemblyDataKeepWeakly, name = "AssemblyData") - member val SemanticClassification = AsyncMemoize(sf, 2 * sf, name = "SemanticClassification") + member val SemanticClassification = AsyncMemoize(sf.SemanticClassificationKeepStrongly, sf.SemanticClassificationKeepWeakly, name = "SemanticClassification") - member val ItemKeyStore = AsyncMemoize(sf, 2 * sf, name = "ItemKeyStore") + member val ItemKeyStore = AsyncMemoize(sf.ItemKeyStoreKeepStrongly, sf.ItemKeyStoreKeepWeakly, name = "ItemKeyStore") - member val ScriptClosure = AsyncMemoize(sf, 2 * sf, name = "ScriptClosure") + member val ScriptClosure = AsyncMemoize(sf.ScriptClosureKeepStrongly, sf.ScriptClosureKeepWeakly, name = "ScriptClosure") member this.Clear(projects: Set) = let shouldClear project = projects |> Set.contains project @@ -327,7 +401,8 @@ type internal TransparentCompiler captureIdentifiersWhenParsing, getSource: (string -> Async) option, useChangeNotifications, - useSyntaxTreeCache + useSyntaxTreeCache, + ?cacheSizes ) as self = let documentSource = @@ -337,9 +412,11 @@ type internal TransparentCompiler // Is having just one of these ok? let lexResourceManager = Lexhelp.LexResourceManager() + + let cacheSizes = defaultArg cacheSizes CacheSizes.Default // Mutable so we can easily clear them by creating a new instance - let mutable caches = CompilerCaches(100) + let mutable caches = CompilerCaches(cacheSizes) // TODO: do we need this? //let maxTypeCheckingParallelism = max 1 (Environment.ProcessorCount / 2) @@ -1378,8 +1455,8 @@ type internal TransparentCompiler node, (fun tcInfo -> - if tcInfo.stateContainsNodes |> Set.contains fileNode then - failwith $"Oops!" + // if tcInfo.stateContainsNodes |> Set.contains fileNode then + // failwith $"Oops!" //if // tcInfo.stateContainsNodes @@ -1424,14 +1501,8 @@ type internal TransparentCompiler fileNode, (fun tcInfo -> - if tcInfo.stateContainsNodes |> Set.contains fileNode then - failwith $"Oops!" - - // if - // tcInfo.stateContainsNodes - // |> Set.contains (NodeToTypeCheck.PhysicalFile(index + 1)) - // then - // failwith $"Oops!!!" + // if tcInfo.stateContainsNodes |> Set.contains fileNode then + // failwith $"Oops!" let parsedInput = projectSnapshot.SourceFiles[index].ParsedInput let prefixPathOpt = None @@ -1689,6 +1760,7 @@ type internal TransparentCompiler cacheKey.GetKey(), (fun (_fullVersion, fileContentVersion) -> fileContentVersion = (snd version)) ) + match parseFileResultsAndcheckFileAnswer with | Some(parseFileResults, FSharpCheckFileAnswer.Succeeded checkFileResults) -> Some(parseFileResults, checkFileResults) @@ -2096,9 +2168,13 @@ type internal TransparentCompiler member _.Caches = caches - member _.SetCacheSizeFactor(sizeFactor: int) = - if sizeFactor <> caches.SizeFactor then - caches <- CompilerCaches(sizeFactor) + member _.SetCacheSize(cacheSize : CacheSizes) = + if cacheSize <> caches.CacheSizes then + caches <- CompilerCaches(cacheSize) + + member x.SetCacheSizeFactor(sizeFactor : int) = + let newCacheSize = CacheSizes.Create sizeFactor + x.SetCacheSize newCacheSize interface IBackgroundCompiler with @@ -2160,7 +2236,7 @@ type internal TransparentCompiler member _.ClearCaches() : unit = backgroundCompiler.ClearCaches() - caches <- CompilerCaches(100) // TODO: check + caches <- CompilerCaches(cacheSizes) // TODO: check member _.DownsizeCaches() : unit = backgroundCompiler.DownsizeCaches() diff --git a/src/Compiler/Service/TransparentCompiler.fsi b/src/Compiler/Service/TransparentCompiler.fsi index be1f5ab64fa..b7646d7d3dc 100644 --- a/src/Compiler/Service/TransparentCompiler.fsi +++ b/src/Compiler/Service/TransparentCompiler.fsi @@ -97,9 +97,44 @@ type internal Extensions = fileSnapshots: #ProjectSnapshot.IFileSnapshot list * ?extraKeyFlag: DependencyGraphType -> ICacheKey<(DependencyGraphType option * byte array), string> +type CacheSizes = { + ParseFileKeepStrongly: int + ParseFileKeepWeakly: int + ParseFileWithoutProjectKeepStrongly: int + ParseFileWithoutProjectKeepWeakly: int + ParseAndCheckFileInProjectKeepStrongly: int + ParseAndCheckFileInProjectKeepWeakly: int + ParseAndCheckAllFilesInProjectKeepStrongly: int + ParseAndCheckAllFilesInProjectKeepWeakly: int + ParseAndCheckProjectKeepStrongly: int + ParseAndCheckProjectKeepWeakly: int + FrameworkImportsKeepStrongly: int + FrameworkImportsKeepWeakly: int + BootstrapInfoStaticKeepStrongly: int + BootstrapInfoStaticKeepWeakly: int + BootstrapInfoKeepStrongly: int + BootstrapInfoKeepWeakly: int + TcLastFileKeepStrongly: int + TcLastFileKeepWeakly: int + TcIntermediateKeepStrongly: int + TcIntermediateKeepWeakly: int + DependencyGraphKeepStrongly: int + DependencyGraphKeepWeakly: int + ProjectExtrasKeepStrongly: int + ProjectExtrasKeepWeakly: int + AssemblyDataKeepStrongly: int + AssemblyDataKeepWeakly: int + SemanticClassificationKeepStrongly: int + SemanticClassificationKeepWeakly: int + ItemKeyStoreKeepStrongly: int + ItemKeyStoreKeepWeakly: int + ScriptClosureKeepStrongly: int + ScriptClosureKeepWeakly: int +} + type internal CompilerCaches = - new: sizeFactor: int -> CompilerCaches + new: sizeFactor: CacheSizes -> CompilerCaches member AssemblyData: AsyncMemoize<(string * string), (string * string), ProjectAssemblyDataResult> @@ -131,7 +166,7 @@ type internal CompilerCaches = member SemanticClassification: AsyncMemoize<(string * (string * string)), string, SemanticClassificationView option> - member SizeFactor: int + member CacheSizes: CacheSizes member TcIntermediate: AsyncMemoize<(string * (string * string)), (string * int), TcIntermediate> @@ -156,7 +191,8 @@ type internal TransparentCompiler = captureIdentifiersWhenParsing: bool * getSource: (string -> Async) option * useChangeNotifications: bool * - useSyntaxTreeCache: bool -> + useSyntaxTreeCache: bool * + ?cacheSizes: CacheSizes -> TransparentCompiler member FindReferencesInFile: @@ -175,6 +211,7 @@ type internal TransparentCompiler = fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * _userOpName: 'a -> Async + member SetCacheSize: cacheSize: CacheSizes -> unit member SetCacheSizeFactor: sizeFactor: int -> unit member Caches: CompilerCaches