Skip to content
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

Parallel project analysis behind a feature flag #13521

Merged
merged 18 commits into from
Sep 24, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
9 changes: 9 additions & 0 deletions src/Compiler/Driver/CompilerConfig.fs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,11 @@ type MetadataAssemblyGeneration =
| ReferenceOut of outputPath: string
| ReferenceOnly

[<RequireQualifiedAccess>]
type ParallelReferenceResolution =
| On
| Off

[<NoEquality; NoComparison>]
type TcConfigBuilder =
{
Expand Down Expand Up @@ -580,6 +585,8 @@ type TcConfigBuilder =
mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option

mutable exiter: Exiter

mutable parallelReferenceResolution: ParallelReferenceResolution
}

// Directories to start probing in
Expand Down Expand Up @@ -767,6 +774,7 @@ type TcConfigBuilder =
sdkDirOverride = sdkDirOverride
xmlDocInfoLoader = None
exiter = QuitProcessExiter
parallelReferenceResolution = ParallelReferenceResolution.Off
}

member tcConfigB.FxResolver =
Expand Down Expand Up @@ -1310,6 +1318,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) =
member _.applyLineDirectives = data.applyLineDirectives
member _.xmlDocInfoLoader = data.xmlDocInfoLoader
member _.exiter = data.exiter
member _.parallelReferenceResolution = data.parallelReferenceResolution

static member Create(builder, validate) =
use _ = UseBuildPhase BuildPhase.Parameter
Expand Down
9 changes: 9 additions & 0 deletions src/Compiler/Driver/CompilerConfig.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ type MetadataAssemblyGeneration =
/// Only emits the assembly as a reference assembly.
| ReferenceOnly

[<RequireQualifiedAccess>]
type ParallelReferenceResolution =
| On
| Off

[<NoEquality; NoComparison>]
type TcConfigBuilder =
{
Expand Down Expand Up @@ -482,6 +487,8 @@ type TcConfigBuilder =
mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option

mutable exiter: Exiter

mutable parallelReferenceResolution: ParallelReferenceResolution
}

static member CreateNew:
Expand Down Expand Up @@ -845,6 +852,8 @@ type TcConfig =

member exiter: Exiter

member parallelReferenceResolution: ParallelReferenceResolution

/// Represents a computation to return a TcConfig. Normally this is just a constant immutable TcConfig,
/// but for F# Interactive it may be based on an underlying mutable TcConfigBuilder.
[<Sealed>]
Expand Down
8 changes: 7 additions & 1 deletion src/Compiler/Driver/CompilerImports.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2141,6 +2141,12 @@ and [<Sealed>] TcImports
node {
CheckDisposed()

let tcConfig = tcConfigP.Get ctok
let runMethod =
match tcConfig.parallelReferenceResolution with
| ParallelReferenceResolution.On -> NodeCode.Parallel
| ParallelReferenceResolution.Off -> NodeCode.Sequential

let! results =
nms
|> List.map (fun nm ->
Expand All @@ -2151,7 +2157,7 @@ and [<Sealed>] TcImports
errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range))
return None
})
|> NodeCode.Sequential
|> runMethod

let dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip
fixupOrphanCcus ()
Expand Down
8 changes: 8 additions & 0 deletions src/Compiler/Driver/CompilerOptions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1680,6 +1680,14 @@ let internalFlags (tcConfigB: TcConfigBuilder) =
None
)

CompilerOption(
"parallelreferenceresolution",
tagNone,
OptionUnit(fun () -> tcConfigB.parallelReferenceResolution <- ParallelReferenceResolution.On),
Some(InternalCommandLineOption("--parallelreferenceresolution", rangeCmdArgs)),
None
)

testFlag tcConfigB
]
@
Expand Down
17 changes: 17 additions & 0 deletions src/Compiler/Driver/fsc.fs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,18 @@ let TryFindVersionAttribute g attrib attribName attribs deterministic =
[<NoEquality; NoComparison>]
type Args<'T> = Args of 'T

let getParallelReferenceResolutionFromEnvironment () =
Environment.GetEnvironmentVariable("FCS_ParallelReferenceResolution")
|> Option.ofObj
|> Option.bind (fun flag ->
match bool.TryParse flag with
| true, runInParallel ->
if runInParallel then
Some ParallelReferenceResolution.On
else
Some ParallelReferenceResolution.Off
| false, _ -> None)

/// First phase of compilation.
/// - Set up console encoding and code page settings
/// - Process command line, flags and collect filenames
Expand Down Expand Up @@ -533,6 +545,11 @@ let main1

tcConfigB.conditionalDefines <- "COMPILED" :: tcConfigB.conditionalDefines

// Override ParallelReferenceResolution set on the CLI with an environment setting if present.
match getParallelReferenceResolutionFromEnvironment () with
| Some parallelReferenceResolution -> tcConfigB.parallelReferenceResolution <- parallelReferenceResolution
| None -> ()

// Display the banner text, if necessary
if not bannerAlreadyPrinted then
Console.Write(GetBannerText tcConfigB)
Expand Down
3 changes: 3 additions & 0 deletions src/Compiler/Driver/fsc.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ val CompileFromCommandLineArguments:
tcImportsCapture: (TcImports -> unit) option *
dynamicAssemblyCreator: (TcConfig * TcGlobals * string * ILModuleDef -> unit) option ->
unit

/// Read the parallelReferenceResolution flag from environment variables
val internal getParallelReferenceResolutionFromEnvironment: unit -> ParallelReferenceResolution option
8 changes: 7 additions & 1 deletion src/Compiler/Facilities/BuildGraph.fs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ type NodeCode private () =

return results.ToArray()
}

static member Parallel (computations: NodeCode<'T> seq) =
computations
|> Seq.map (fun (Node x) -> x)
|> Async.Parallel
|> Node

type private AgentMessage<'T> = GetValue of AsyncReplyChannel<Result<'T, Exception>> * callerCancellationToken: CancellationToken

Expand Down Expand Up @@ -331,7 +337,7 @@ type GraphNode<'T>(retryCompute: bool, computation: NodeCode<'T>) =
// occur, making sure we are under the protection of the 'try'.
// For example, NodeCode's 'try/finally' (TryFinally) uses async.TryFinally which does
// implicit cancellation checks even before the try is entered, as do the
// de-sugaring of 'do!' and other CodeCode constructs.
// de-sugaring of 'do!' and other NodeCode constructs.
let mutable taken = false

try
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Facilities/BuildGraph.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type NodeCode =

static member Sequential: computations: NodeCode<'T> seq -> NodeCode<'T[]>

static member Parallel: computations: (NodeCode<'T> seq) -> NodeCode<'T[]>

/// Execute the cancellable computation synchronously using the ambient cancellation token of
/// the NodeCode.
static member FromCancellable: computation: Cancellable<'T> -> NodeCode<'T>
Expand Down
4 changes: 3 additions & 1 deletion src/Compiler/Service/IncrementalBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1432,7 +1432,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc
enableBackgroundItemKeyStoreAndSemanticClassification,
enablePartialTypeChecking: bool,
enableParallelCheckingWithSignatureFiles: bool,
dependencyProvider
dependencyProvider,
parallelReferenceResolution
) =

let useSimpleResolutionSwitch = "--simpleresolution"
Expand Down Expand Up @@ -1514,6 +1515,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc
|> Some

tcConfigB.parallelCheckingWithSignatureFiles <- enableParallelCheckingWithSignatureFiles
tcConfigB.parallelReferenceResolution <- parallelReferenceResolution

tcConfigB, sourceFilesNew

Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/Service/IncrementalBuild.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ type internal IncrementalBuilder =
enableBackgroundItemKeyStoreAndSemanticClassification: bool *
enablePartialTypeChecking: bool *
enableParallelCheckingWithSignatureFiles: bool *
dependencyProvider: DependencyProvider option ->
dependencyProvider: DependencyProvider option *
parallelReferenceResolution: ParallelReferenceResolution ->
NodeCode<IncrementalBuilder option * FSharpDiagnostic[]>

/// Generalized Incremental Builder. This is exposed only for unit testing purposes.
Expand Down
38 changes: 32 additions & 6 deletions src/Compiler/Service/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ type BackgroundCompiler
keepAllBackgroundSymbolUses,
enableBackgroundItemKeyStoreAndSemanticClassification,
enablePartialTypeChecking,
enableParallelCheckingWithSignatureFiles
enableParallelCheckingWithSignatureFiles,
parallelReferenceResolution
) as self =

let beforeFileChecked = Event<string * FSharpProjectOptions>()
Expand Down Expand Up @@ -303,7 +304,8 @@ type BackgroundCompiler
enableBackgroundItemKeyStoreAndSemanticClassification,
enablePartialTypeChecking,
enableParallelCheckingWithSignatureFiles,
dependencyProvider
dependencyProvider,
parallelReferenceResolution
)

match builderOpt with
Expand Down Expand Up @@ -1096,7 +1098,8 @@ type FSharpChecker
keepAllBackgroundSymbolUses,
enableBackgroundItemKeyStoreAndSemanticClassification,
enablePartialTypeChecking,
enableParallelCheckingWithSignatureFiles
enableParallelCheckingWithSignatureFiles,
parallelReferenceResolution
) =

let backgroundCompiler =
Expand All @@ -1110,7 +1113,8 @@ type FSharpChecker
keepAllBackgroundSymbolUses,
enableBackgroundItemKeyStoreAndSemanticClassification,
enablePartialTypeChecking,
enableParallelCheckingWithSignatureFiles
enableParallelCheckingWithSignatureFiles,
parallelReferenceResolution
)

static let globalInstance = lazy FSharpChecker.Create()
Expand All @@ -1122,6 +1126,24 @@ type FSharpChecker
let braceMatchCache =
MruCache<AnyCallerThreadToken, _, _>(braceMatchCacheSize, areSimilar = AreSimilarForParsing, areSame = AreSameForParsing)

static let inferParallelReferenceResolution (parallelReferenceResolution: bool option) =
let explicitValue =
parallelReferenceResolution
|> Option.defaultValue false
|> function
| true -> ParallelReferenceResolution.On
| false -> ParallelReferenceResolution.Off

let withEnvOverride =
// Override ParallelReferenceResolution set on the constructor with an environment setting if present.
getParallelReferenceResolutionFromEnvironment ()
|> Option.defaultValue explicitValue

withEnvOverride

static member getParallelReferenceResolutionFromEnvironment() =
getParallelReferenceResolutionFromEnvironment ()

/// Instantiate an interactive checker.
static member Create
(
Expand All @@ -1134,7 +1156,8 @@ type FSharpChecker
?keepAllBackgroundSymbolUses,
?enableBackgroundItemKeyStoreAndSemanticClassification,
?enablePartialTypeChecking,
?enableParallelCheckingWithSignatureFiles
?enableParallelCheckingWithSignatureFiles,
?parallelReferenceResolution
) =

let legacyReferenceResolver =
Expand All @@ -1158,6 +1181,8 @@ type FSharpChecker
if keepAssemblyContents && enablePartialTypeChecking then
invalidArg "enablePartialTypeChecking" "'keepAssemblyContents' and 'enablePartialTypeChecking' cannot be both enabled."

let parallelReferenceResolution = inferParallelReferenceResolution parallelReferenceResolution

FSharpChecker(
legacyReferenceResolver,
projectCacheSizeReal,
Expand All @@ -1168,7 +1193,8 @@ type FSharpChecker
keepAllBackgroundSymbolUses,
enableBackgroundItemKeyStoreAndSemanticClassification,
enablePartialTypeChecking,
enableParallelCheckingWithSignatureFiles
enableParallelCheckingWithSignatureFiles,
parallelReferenceResolution
)

member _.ReferenceResolver = legacyReferenceResolver
Expand Down
5 changes: 4 additions & 1 deletion src/Compiler/Service/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open System
open System.IO
open FSharp.Compiler.AbstractIL.ILBinaryReader
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Symbols
Expand All @@ -32,6 +33,7 @@ type public FSharpChecker =
/// <param name="enableBackgroundItemKeyStoreAndSemanticClassification">Indicates whether a table of symbol keys should be kept for background compilation</param>
/// <param name="enablePartialTypeChecking">Indicates whether to perform partial type checking. Cannot be set to true if keepAssmeblyContents is true. If set to true, can cause duplicate type-checks when richer information on a file is needed, but can skip background type-checking entirely on implementation files with signature files.</param>
/// <param name="enableParallelCheckingWithSignatureFiles">Type check implementation files that are backed by a signature file in parallel.</param>
/// <param name="parallelReferenceResolution">Indicates whether to resolve references in parallel.</param>
static member Create:
?projectCacheSize: int *
?keepAssemblyContents: bool *
Expand All @@ -42,7 +44,8 @@ type public FSharpChecker =
?keepAllBackgroundSymbolUses: bool *
?enableBackgroundItemKeyStoreAndSemanticClassification: bool *
?enablePartialTypeChecking: bool *
?enableParallelCheckingWithSignatureFiles: bool ->
?enableParallelCheckingWithSignatureFiles: bool *
?parallelReferenceResolution: bool ->
FSharpChecker

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2009,7 +2009,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles()
FSharp.Compiler.CodeAnalysis.FSharpChecker
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
Expand Down
22 changes: 0 additions & 22 deletions tests/fsharp/regression/13219/test.fsx

This file was deleted.