Skip to content

Commit

Permalink
Transparent compiler buffs (#1356)
Browse files Browse the repository at this point in the history
* Set cache sizes for TC

* Ensure typechecks are accurate on hover/codelens

* Add RunContinuationsAsynchronously to TCS

* cleanup ITextDocumentIdentifier

* Add analyzers thorttle

* Add typecheck throttler
  • Loading branch information
TheAngryByrd authored Feb 13, 2025
1 parent b6bfc04 commit 1550bf4
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/FsAutoComplete.Core/AdaptiveExtensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ and AdaptiveCancellableTask<'a>(cancel: unit -> unit, real: Task<'a>) =
if real.IsCompleted then
real
else
cachedTcs <- new TaskCompletionSource<'a>()
cachedTcs <- new TaskCompletionSource<'a>(TaskCreationOptions.RunContinuationsAsynchronously)

cachedTcs.TrySetFromTaskFinished real

Expand Down
37 changes: 30 additions & 7 deletions src/FsAutoComplete.Core/CompilerServiceInterface.fs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,22 @@ type CompilerProjectOption =
| BackgroundCompiler(options) -> options.OtherOptions |> Array.toList
| TransparentCompiler(snapshot) -> snapshot.OtherOptions

type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelReferenceResolution, useTransparentCompiler)
=
type FSharpCompilerServiceChecker
(
hasAnalyzers,
typecheckCacheSize,
parallelReferenceResolution,
useTransparentCompiler,
?transparentCompilerCacheSizes: int
) =
let checker =
let cacheSize =
if useTransparentCompiler then
TransparentCompiler.CacheSizes.Create(defaultArg transparentCompilerCacheSizes 10)
|> Some
else
None

FSharpChecker.Create(
projectCacheSize = 200,
keepAssemblyContents = hasAnalyzers,
Expand All @@ -91,7 +104,8 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe
enablePartialTypeChecking = not hasAnalyzers,
parallelReferenceResolution = parallelReferenceResolution,
captureIdentifiersWhenParsing = true,
useTransparentCompiler = useTransparentCompiler
useTransparentCompiler = useTransparentCompiler,
?transparentCompilerCacheSizes = cacheSize
)

let entityCache = EntityCache()
Expand Down Expand Up @@ -502,7 +516,10 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe
let ops =
MemoryCacheEntryOptions().SetSize(1).SetSlidingExpiration(TimeSpan.FromMinutes(5.))

return lastCheckResults.Set(filePath, r, ops)
lastCheckResults.Set(filePath, WeakReference<ParseAndCheckResults>(r), ops)
|> ignore<WeakReference<ParseAndCheckResults>>

return r
else
return r
with ex ->
Expand Down Expand Up @@ -553,7 +570,10 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe
let ops =
MemoryCacheEntryOptions().SetSize(1).SetSlidingExpiration(TimeSpan.FromMinutes(5.))

return lastCheckResults.Set(filePath, r, ops)
lastCheckResults.Set(filePath, WeakReference<ParseAndCheckResults>(r), ops)
|> ignore<WeakReference<ParseAndCheckResults>>

return r
else
return r
with ex ->
Expand All @@ -578,8 +598,11 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe

checkerLogger.info (Log.setMessage "{opName}" >> Log.addContextDestructured "opName" opName)

match lastCheckResults.TryGetValue<ParseAndCheckResults>(file) with
| (true, v) -> Some v
match lastCheckResults.TryGetValue<WeakReference<ParseAndCheckResults>>(file) with
| (true, v) ->
match v.TryGetTarget() with
| (true, v) -> Some v
| _ -> None
| _ -> None

member _.TryGetRecentCheckResultsForFile(file: string<LocalPath>, snapshot: FSharpProjectSnapshot) =
Expand Down
6 changes: 5 additions & 1 deletion src/FsAutoComplete.Core/CompilerServiceInterface.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ type CompilerProjectOption =

type FSharpCompilerServiceChecker =
new:
hasAnalyzers: bool * typecheckCacheSize: int64 * parallelReferenceResolution: bool * useTransparentCompiler: bool ->
hasAnalyzers: bool *
typecheckCacheSize: int64 *
parallelReferenceResolution: bool *
useTransparentCompiler: bool *
?transparentCompilerCacheSizes: int ->
FSharpCompilerServiceChecker

member DisableInMemoryProjectReferences: bool with get, set
Expand Down
4 changes: 3 additions & 1 deletion src/FsAutoComplete.Core/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ module ProcessHelper =

let WaitForExitAsync (p: Process) =
asyncEx {
let tcs = TaskCompletionSource<obj>()
let tcs =
TaskCompletionSource<obj>(TaskCreationOptions.RunContinuationsAsynchronously)

p.EnableRaisingEvents <- true
p.Exited.Add(fun _args -> tcs.TrySetResult(null) |> ignore)

Expand Down
6 changes: 1 addition & 5 deletions src/FsAutoComplete/LspHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,7 @@ module Conversions =
| Some(U2.C2 code) -> code |> Some
| None -> None

type TextDocumentIdentifier with

member doc.GetFilePath() = Path.FileUriToLocalPath doc.Uri

type VersionedTextDocumentIdentifier with
type ITextDocumentIdentifier with

member doc.GetFilePath() = Path.FileUriToLocalPath doc.Uri

Expand Down
6 changes: 1 addition & 5 deletions src/FsAutoComplete/LspHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,7 @@ module Conversions =

member CodeAsString: string option

type TextDocumentIdentifier with

member GetFilePath: unit -> string

type VersionedTextDocumentIdentifier with
type ITextDocumentIdentifier with

member GetFilePath: unit -> string

Expand Down
4 changes: 2 additions & 2 deletions src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ type AdaptiveFSharpLspServer
let (filePath, pos) = getFilePathAndPosition p
let! volatileFile = state.GetOpenFileOrRead filePath |> AsyncResult.ofStringErr
let! lineStr = volatileFile.Source |> tryGetLineStr pos |> Result.lineLookupErr
and! tyRes = state.GetOpenFileTypeCheckResultsCached filePath |> AsyncResult.ofStringErr
and! tyRes = state.GetOpenFileTypeCheckResults filePath |> AsyncResult.ofStringErr

match tyRes.TryGetToolTipEnhanced pos lineStr with
| Some tooltipResult ->
Expand Down Expand Up @@ -1580,7 +1580,7 @@ type AdaptiveFSharpLspServer
let filePath = Path.FileUriToLocalPath data.[0] |> Utils.normalizePath

try
let! tyRes = state.GetOpenFileTypeCheckResultsCached filePath |> AsyncResult.ofStringErr
let! tyRes = state.GetOpenFileTypeCheckResults filePath |> AsyncResult.ofStringErr


logger.info (
Expand Down
23 changes: 18 additions & 5 deletions src/FsAutoComplete/LspServers/AdaptiveServerState.fs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,14 @@ type AdaptiveState
disposables.Add
<| fileParsed.Publish.Subscribe(fun (parseResults, proj, ct) -> detectTests parseResults proj ct)

let analyzersLocker = new SemaphoreSlim(1, 1)

let typecheckLocker =
let maxConcurrency =
Math.Max(1.0, Math.Floor(float System.Environment.ProcessorCount * 0.75)) |> int

new SemaphoreSlim(maxConcurrency, maxConcurrency)

let builtInCompilerAnalyzers config (file: VolatileFile) (tyRes: ParseAndCheckResults) =
let filePath = file.FileName
let filePathUntag = UMX.untag filePath
Expand All @@ -390,14 +398,15 @@ type AdaptiveState
let checkUnusedOpens =
asyncEx {
try
let! ct = Async.CancellationToken
use! _l = analyzersLocker.LockAsync(ct)
use progress = progressLookup.CreateProgressReport(lspClient, cancellable = true)
do! progress.Begin($"Checking unused opens {fileName}...", message = filePathUntag)

let! unused =
UnusedOpens.getUnusedOpens (tyRes.GetCheckResults, getSourceLine)
|> Async.withCancellation progress.CancellationToken

let! ct = Async.CancellationToken
notifications.Trigger(NotificationEvent.UnusedOpens(filePath, (unused |> List.toArray), file.Version), ct)
with e ->
logger.error (Log.setMessage "checkUnusedOpens failed" >> Log.addExn e)
Expand All @@ -406,6 +415,8 @@ type AdaptiveState
let checkUnusedDeclarations =
asyncEx {
try
let! ct = Async.CancellationToken
use! _l = analyzersLocker.LockAsync(ct)
use progress = progressLookup.CreateProgressReport(lspClient, cancellable = true)
do! progress.Begin($"Checking unused declarations {fileName}...", message = filePathUntag)

Expand All @@ -417,7 +428,6 @@ type AdaptiveState

let unused = unused |> Seq.toArray

let! ct = Async.CancellationToken
notifications.Trigger(NotificationEvent.UnusedDeclarations(filePath, unused, file.Version), ct)
with e ->
logger.error (Log.setMessage "checkUnusedDeclarations failed" >> Log.addExn e)
Expand All @@ -426,6 +436,8 @@ type AdaptiveState
let checkSimplifiedNames =
asyncEx {
try
let! ct = Async.CancellationToken
use! _l = analyzersLocker.LockAsync(ct)
use progress = progressLookup.CreateProgressReport(lspClient, cancellable = true)
do! progress.Begin($"Checking simplifying of names {fileName}...", message = filePathUntag)

Expand All @@ -434,7 +446,6 @@ type AdaptiveState
|> Async.withCancellation progress.CancellationToken

let simplified = Array.ofSeq simplified
let! ct = Async.CancellationToken
notifications.Trigger(NotificationEvent.SimplifyNames(filePath, simplified, file.Version), ct)
with e ->
logger.error (Log.setMessage "checkSimplifiedNames failed" >> Log.addExn e)
Expand All @@ -443,6 +454,8 @@ type AdaptiveState
let checkUnnecessaryParentheses =
asyncEx {
try
let! ct = Async.CancellationToken
use! _l = analyzersLocker.LockAsync(ct)
use progress = progressLookup.CreateProgressReport(lspClient)
do! progress.Begin($"Checking for unnecessary parentheses {fileName}...", message = filePathUntag)

Expand All @@ -464,8 +477,6 @@ type AdaptiveState

| _ -> ranges)

let! ct = Async.CancellationToken

notifications.Trigger(
NotificationEvent.UnnecessaryParentheses(filePath, Array.ofSeq unnecessaryParentheses, file.Version),
ct
Expand Down Expand Up @@ -1599,6 +1610,8 @@ type AdaptiveState

]

let! ct = Async.CancellationToken
use! _l = typecheckLocker.LockAsync ct
use _ = fsacActivitySource.StartActivityForType(thisType, tags = tags)


Expand Down
5 changes: 4 additions & 1 deletion src/FsAutoComplete/LspServers/Common.fs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ module Async =
asyncEx {
let! ct2 = Async.CancellationToken
use cts = CancellationTokenSource.CreateLinkedTokenSource(ct, ct2)
let tcs = new TaskCompletionSource<'a>()

let tcs =
new TaskCompletionSource<'a>(TaskCreationOptions.RunContinuationsAsynchronously)

use _reg = cts.Token.Register(fun () -> tcs.TrySetCanceled(cts.Token) |> ignore)

let a =
Expand Down

0 comments on commit 1550bf4

Please sign in to comment.