Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
11aead0
starting point for testing AsyncLocal impact
majocha Feb 13, 2024
34d9816
Merge branch 'main' into asynclocal-compare
majocha Feb 13, 2024
35f9a9b
fix Release mode
majocha Feb 13, 2024
2d637fb
Merge branch 'asynclocal-compare' of https://github.com/majocha/fshar…
majocha Feb 13, 2024
799ad0d
Merge branch 'main' into asynclocal-compare
majocha Feb 13, 2024
2a1cb73
log thread id
majocha Feb 13, 2024
0638056
noop NodeCode to see what breaks
majocha Feb 13, 2024
0a72208
more useful log
majocha Feb 13, 2024
7b34814
some attempts
majocha Feb 14, 2024
c817d61
zero thread statics in service entry pointsome attempts
majocha Feb 14, 2024
7fbbb3e
wip
majocha Feb 14, 2024
aa46ad3
Merge branch 'main' into asynclocal-compare
majocha Feb 14, 2024
98f5ff3
merge
majocha Feb 14, 2024
3e129fe
wip
majocha Feb 14, 2024
d8fb4a7
do not initialize in getters
majocha Feb 14, 2024
0cbbd65
test showing a problem with NodeCode
majocha Feb 14, 2024
64233fb
Merge branch 'main' into nodecode-awaitasync
majocha Feb 14, 2024
64c6f6c
merge
majocha Feb 14, 2024
73faf7e
fix test
majocha Feb 15, 2024
32454c5
more logging
majocha Feb 15, 2024
d405abd
fix some tests
majocha Feb 15, 2024
36b89ec
deparallelize a bit for now
majocha Feb 15, 2024
fbdbc9c
a lot of nulls in AsyncMemoize.Get, unfortunately
majocha Feb 15, 2024
eabf7e7
Merge branch 'main' into asynclocal-compare
majocha Feb 15, 2024
f0e59ed
don't pass non-threadsafe logger to parallel computations
majocha Feb 15, 2024
7c023a7
merge nodecode-parallel
majocha Feb 15, 2024
61d42f9
warn on AwaitAsync
majocha Feb 15, 2024
729fa6a
fix using
majocha Feb 15, 2024
3276021
just trace, callstack is useless
majocha Feb 15, 2024
73aea2b
revert
majocha Feb 15, 2024
425a180
duplicated
majocha Feb 16, 2024
3b75c59
restore
majocha Feb 16, 2024
2f78f41
fix some tests hopefuly
majocha Feb 16, 2024
4e60228
noop for now
majocha Feb 16, 2024
f8a1d34
remove
majocha Feb 16, 2024
3efb96e
fix
majocha Feb 16, 2024
9ec30c3
better Parallel
majocha Feb 16, 2024
6848559
wip
majocha Feb 16, 2024
0697453
wip
majocha Feb 16, 2024
1f8d8aa
Merge branch 'main' into asynclocal-compare
majocha Feb 16, 2024
3ea3006
wip
majocha Feb 16, 2024
12ba20e
merge main
majocha Feb 17, 2024
b8a41ca
Merge branch 'main' into asynclocal-compare
majocha Feb 17, 2024
2931c57
check only in getter
majocha Feb 17, 2024
2524df6
init logger for parse
majocha Feb 17, 2024
3802de6
wip
majocha Feb 17, 2024
a3de922
Merge branch 'asynclocal-compare' of https://github.com/majocha/fshar…
majocha Feb 17, 2024
9ad9689
wip
majocha Feb 17, 2024
aa2cc25
Merge branch 'main' into asynclocal-compare
majocha Feb 18, 2024
a8a62bf
f
majocha Feb 18, 2024
90aa5b4
check
majocha Feb 18, 2024
114f682
restore assertfalse
majocha Feb 18, 2024
01af47d
Merge branch 'asynclocal-compare' of https://github.com/majocha/fshar…
majocha Feb 19, 2024
a9359f0
trace UseDiagnosticsLogger
majocha Feb 19, 2024
f137d4d
Merge branch 'main' into asynclocal-compare
majocha Feb 19, 2024
65351d9
Merge branch 'asynclocal-compare' of https://github.com/majocha/fshar…
majocha Feb 19, 2024
efa7207
wip
majocha Feb 19, 2024
785bf2d
fix CompilerImports behavor
majocha Feb 19, 2024
8ee075f
min diff
majocha Feb 20, 2024
7336e46
wrapThreadStaticInfo
majocha Feb 20, 2024
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
40 changes: 29 additions & 11 deletions src/Compiler/Driver/ParseAndCheckInputs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeOps
open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.BuildGraph

let CanonicalizeFilename fileName =
let basic = FileSystemUtils.fileNameOfPath fileName
Expand Down Expand Up @@ -811,23 +812,40 @@ let UseMultipleDiagnosticLoggers (inputs, diagnosticsLogger, eagerFormat) f =
logger.CommitDelayedDiagnostics diagnosticsLogger

let ParseInputFilesInParallel (tcConfig: TcConfig, lexResourceManager, sourceFiles, delayLogger: DiagnosticsLogger, retryLocked) =
node {
use _ = UseDiagnosticsLogger delayLogger

let isLastCompiland, isExe = sourceFiles |> tcConfig.ComputeCanContainEntryPoint
let isLastCompiland, isExe = sourceFiles |> tcConfig.ComputeCanContainEntryPoint

for fileName in sourceFiles do
checkInputFile tcConfig fileName
for fileName in sourceFiles do
checkInputFile tcConfig fileName

let sourceFiles = List.zip sourceFiles isLastCompiland
let sourceFiles = List.zip sourceFiles isLastCompiland

UseMultipleDiagnosticLoggers (sourceFiles, delayLogger, None) (fun sourceFilesWithDelayLoggers ->
sourceFilesWithDelayLoggers
|> ListParallel.map (fun ((fileName, isLastCompiland), delayLogger) ->
let directoryName = Path.GetDirectoryName fileName
let! result =
sourceFiles
|> Seq.map (fun (fileName, isLastCompiland) ->
node {
let directoryName = Path.GetDirectoryName fileName

let input =
parseInputFileAux (tcConfig, lexResourceManager, fileName, (isLastCompiland, isExe), delayLogger, retryLocked)
let input =
parseInputFileAux (
tcConfig,
lexResourceManager,
fileName,
(isLastCompiland, isExe),
DiagnosticsThreadStatics.DiagnosticsLogger,
retryLocked
)

(input, directoryName)))
return (input, directoryName)
})
|> NodeCode.Parallel

return result |> Array.toList
}
|> Async.AwaitNodeCode
|> Async.RunImmediate

let ParseInputFilesSequential (tcConfig: TcConfig, lexResourceManager, sourceFiles, diagnosticsLogger: DiagnosticsLogger, retryLocked) =
let isLastCompiland, isExe = sourceFiles |> tcConfig.ComputeCanContainEntryPoint
Expand Down
27 changes: 9 additions & 18 deletions src/Compiler/Facilities/AsyncMemoize.fs
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,11 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T
log (Restarted, key)
Interlocked.Increment &restarted |> ignore
System.Diagnostics.Trace.TraceInformation $"{name} Restarted {key.Label}"
let currentLogger = DiagnosticsThreadStatics.DiagnosticsLogger
DiagnosticsThreadStatics.DiagnosticsLogger <- cachingLogger

try
let! result = computation |> Async.AwaitNodeCode
post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics)))
return ()
finally
DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger

use _ = UseDiagnosticsLogger cachingLogger
let! result = computation |> Async.AwaitNodeCode
post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics)))
return ()
with
| TaskCancelled _ ->
Interlocked.Increment &cancel_exception_subsequent |> ignore
Expand Down Expand Up @@ -500,17 +496,12 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T
Async.StartAsTask(
async {
// TODO: Should unify starting and restarting
let currentLogger = DiagnosticsThreadStatics.DiagnosticsLogger
DiagnosticsThreadStatics.DiagnosticsLogger <- cachingLogger

log (Started, key)

try
let! result = computation |> Async.AwaitNodeCode
post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics)))
return result
finally
DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger
use _ = UseDiagnosticsLogger cachingLogger
let! result = computation |> Async.AwaitNodeCode
post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics)))
return result
},
cancellationToken = linkedCtSource.Token
)
Expand Down
99 changes: 40 additions & 59 deletions src/Compiler/Facilities/BuildGraph.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,28 @@ open System.Diagnostics
open System.Globalization
open FSharp.Compiler.DiagnosticsLogger
open Internal.Utilities.Library
open Internal.Utilities.Library.Cancellable

[<NoEquality; NoComparison>]
type NodeCode<'T> = Node of Async<'T>

let wrapThreadStaticInfo computation =
async {
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger
let phase = DiagnosticsThreadStatics.BuildPhase
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLoggerNC
let phase = DiagnosticsThreadStatics.BuildPhaseNC

try
return! computation
finally
DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhase <- phase
DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhaseNC <- phase
}

let unwrapNode (Node(computation)) = computation

type Async<'T> with

static member AwaitNodeCode(node: NodeCode<'T>) =
match node with
| Node(computation) -> wrapThreadStaticInfo computation
static member AwaitNodeCode(node: NodeCode<'T>) = unwrapNode node

[<Sealed>]
type NodeCodeBuilder() =
Expand Down Expand Up @@ -95,27 +94,8 @@ type NodeCodeBuilder() =
member _.Combine(Node(p1): NodeCode<unit>, Node(p2): NodeCode<'T>) : NodeCode<'T> = Node(async.Combine(p1, p2))

[<DebuggerHidden; DebuggerStepThrough>]
member _.Using(value: CompilationGlobalsScope, binder: CompilationGlobalsScope -> NodeCode<'U>) =
Node(
async {
DiagnosticsThreadStatics.DiagnosticsLogger <- value.DiagnosticsLogger
DiagnosticsThreadStatics.BuildPhase <- value.BuildPhase

try
return! binder value |> Async.AwaitNodeCode
finally
(value :> IDisposable).Dispose()
}
)

[<DebuggerHidden; DebuggerStepThrough>]
member _.Using(value: IDisposable, binder: IDisposable -> NodeCode<'U>) =
Node(
async {
use _ = value
return! binder value |> Async.AwaitNodeCode
}
)
member this.Using(resource: ('T :> IDisposable), binder: ('T :> IDisposable) -> NodeCode<'U>) =
async.Using(resource, binder >> unwrapNode) |> Node

let node = NodeCodeBuilder()

Expand All @@ -125,49 +105,49 @@ type NodeCode private () =
static let cancellationToken = Node(wrapThreadStaticInfo Async.CancellationToken)

static member RunImmediate(computation: NodeCode<'T>, ct: CancellationToken) =
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger
let phase = DiagnosticsThreadStatics.BuildPhase
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLoggerNC
let phase = DiagnosticsThreadStatics.BuildPhaseNC

try
try
let work =
async {
DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhase <- phase
return! computation |> Async.AwaitNodeCode
DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhaseNC <- phase
return! unwrapNode computation
}

Async.StartImmediateAsTask(work, cancellationToken = ct).Result
finally
DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhase <- phase
DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhaseNC <- phase
with :? AggregateException as ex when ex.InnerExceptions.Count = 1 ->
raise (ex.InnerExceptions[0])

static member RunImmediateWithoutCancellation(computation: NodeCode<'T>) =
NodeCode.RunImmediate(computation, CancellationToken.None)

static member StartAsTask_ForTesting(computation: NodeCode<'T>, ?ct: CancellationToken) =
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger
let phase = DiagnosticsThreadStatics.BuildPhase
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLoggerNC
let phase = DiagnosticsThreadStatics.BuildPhaseNC

try
let work =
async {
DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhase <- phase
return! computation |> Async.AwaitNodeCode
DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhaseNC <- phase
return! unwrapNode computation
}

Async.StartAsTask(work, cancellationToken = defaultArg ct CancellationToken.None)
finally
DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhase <- phase
DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger
DiagnosticsThreadStatics.BuildPhaseNC <- phase

static member CancellationToken = cancellationToken

static member FromCancellable(computation: Cancellable<'T>) =
Node(wrapThreadStaticInfo (Cancellable.toAsync computation))
Node(Cancellable.toAsync computation)

static member AwaitAsync(computation: Async<'T>) = Node(wrapThreadStaticInfo computation)

Expand All @@ -176,6 +156,12 @@ type NodeCode private () =

static member AwaitTask(task: Task) =
Node(wrapThreadStaticInfo (Async.AwaitTask task))

static member AwaitTaskWithoutWrapping(task: Task<'T>) =
Node((Async.AwaitTask task))

static member AwaitTaskWithoutWrapping(task: Task) =
Node((Async.AwaitTask task))

static member AwaitWaitHandle_ForTesting(waitHandle: WaitHandle) =
Node(wrapThreadStaticInfo (Async.AwaitWaitHandle(waitHandle)))
Expand All @@ -196,26 +182,21 @@ type NodeCode private () =

static member Parallel(computations: NodeCode<'T> seq) =
node {
let concurrentLogging = new CaptureDiagnosticsConcurrently()
let phase = DiagnosticsThreadStatics.BuildPhase
// Why does it return just IDisposable?
use _ = concurrentLogging
use concurrentLogging = new CaptureDiagnosticsConcurrently()

let injectLogger i computation =
let logger = concurrentLogging.GetLoggerForTask($"NodeCode.Parallel {i}")

async {
DiagnosticsThreadStatics.DiagnosticsLogger <- logger
DiagnosticsThreadStatics.BuildPhase <- phase
return! unwrapNode computation
SetThreadDiagnosticsLoggerNoUnwind logger
SetThreadBuildPhaseNoUnwind phase

return! computation |> unwrapNode
}

return!
computations
|> Seq.mapi injectLogger
|> Async.Parallel
|> wrapThreadStaticInfo
|> Node
return! computations |> Seq.mapi injectLogger |> Async.Parallel |> wrapThreadStaticInfo |> Node

}

[<RequireQualifiedAccess>]
Expand Down Expand Up @@ -256,6 +237,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption
cachedResultNode
else
node {

Interlocked.Increment(&requestCount) |> ignore

try
Expand All @@ -278,18 +260,17 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption
||| TaskContinuationOptions.NotOnFaulted
||| TaskContinuationOptions.ExecuteSynchronously)
)
|> NodeCode.AwaitTask
|> NodeCode.AwaitTaskWithoutWrapping

match cachedResult with
| ValueSome value -> return value
| _ ->
let tcs = TaskCompletionSource<'T>()
let (Node(p)) = computation

Async.StartWithContinuations(
async {
Thread.CurrentThread.CurrentUICulture <- GraphNode.culture
return! p
return! computation |> unwrapNode |> wrapThreadStaticInfo
},
(fun res ->
cachedResult <- ValueSome res
Expand All @@ -301,7 +282,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption
ct
)

return! tcs.Task |> NodeCode.AwaitTask
return! tcs.Task |> NodeCode.AwaitTaskWithoutWrapping
finally
if taken then
semaphore.Release() |> ignore
Expand Down
5 changes: 1 addition & 4 deletions src/Compiler/Facilities/BuildGraph.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ type NodeCodeBuilder =

member Combine: x1: NodeCode<unit> * x2: NodeCode<'T> -> NodeCode<'T>

/// A limited form 'use' for establishing the compilation globals.
member Using: CompilationGlobalsScope * (CompilationGlobalsScope -> NodeCode<'T>) -> NodeCode<'T>
member Using: ('T :> IDisposable) * (('T :> IDisposable) -> NodeCode<'U>) -> NodeCode<'U>

/// A generic 'use' that disposes of the IDisposable at the end of the computation.
member Using: IDisposable * (IDisposable -> NodeCode<'T>) -> NodeCode<'T>

/// Specifies code that can be run as part of the build graph.
val node: NodeCodeBuilder
Expand Down
Loading