Skip to content

Commit

Permalink
up
Browse files Browse the repository at this point in the history
  • Loading branch information
psfinaki committed Nov 5, 2024
1 parent fd7c2e6 commit 6df7695
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 124 deletions.
74 changes: 2 additions & 72 deletions src/Compiler/Driver/ParseAndCheckInputs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ open System.Collections.Generic

open FSharp.Compiler.Parser
open Internal.Utilities.Collections
open Internal.Utilities.Hashing
open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
open Internal.Utilities.Text.Lexing
Expand All @@ -31,6 +30,7 @@ open FSharp.Compiler.IO
open FSharp.Compiler.Lexhelp
open FSharp.Compiler.NameResolution
open FSharp.Compiler.ParseHelpers
open FSharp.Compiler.ReuseTcResults
open FSharp.Compiler.Syntax
open FSharp.Compiler.SyntaxTrivia
open FSharp.Compiler.Syntax.PrettyNaming
Expand Down Expand Up @@ -1962,80 +1962,10 @@ let CheckMultipleInputsUsingGraphMode

partialResults, tcState)

let TryReuseTypecheckingResults (tcConfig: TcConfig) inputs =
let outputDir = tcConfig.outputDir |> Option.defaultValue ""

let tcDataFileName =
FileSystem.GetFullFilePathInDirectoryShim outputDir FSharpTypecheckingDataResourceName

let getContentHash fileName =
use stream = FileSystem.OpenFileForReadShim fileName
let bytes = stream.ReadAllBytes()
let contentHash = Md5Hasher.computeHash bytes
contentHash |> BitConverter.ToString

let getThisCompilationCmdLine () =
tcConfig.cmdLineArgs |> String.concat " "

let getThisCompilationGraph () =
let sourceFiles =
inputs
|> Seq.toArray
|> Array.mapi (fun idx (input: ParsedInput) ->
{
Idx = idx
FileName = input.FileName
ParsedInput = input
})

let filePairs = FilePairMap sourceFiles

DependencyResolution.mkGraph filePairs sourceFiles
|> fst
|> Graph.map (fun idx -> idx, getContentHash sourceFiles[idx].FileName)
|> Graph.asString

let writeThisTcData (cmdLine: string) (graph: string) =
use tcDataFile = FileSystem.OpenFileForWriteShim tcDataFileName
let thisTcData = $"{cmdLine}{Environment.NewLine}{graph}"
tcDataFile.WriteAllText thisTcData

if FileSystem.FileExistsShim tcDataFileName then
use _ = Activity.start Activity.Events.reuseTcResultsCachePresent []

use tcDataFileStream = FileSystem.OpenFileForReadShim tcDataFileName
let tcDataFileReader = tcDataFileStream.GetReader None
let prevCompilationCmdLine = tcDataFileReader.ReadLine()
let thisCompilationCmdLine = getThisCompilationCmdLine ()

if prevCompilationCmdLine = thisCompilationCmdLine then
let prevCompilationGraph = tcDataFileReader.ReadToEnd()
let thisCompilationGraph = getThisCompilationGraph ()

if prevCompilationGraph = thisCompilationGraph then
use _ = Activity.start Activity.Events.reuseTcResultsCacheHit []

() // do nothing, yet
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheMissed []

writeThisTcData thisCompilationCmdLine thisCompilationGraph
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheMissed []

let thisCompilationGraph = getThisCompilationGraph ()
writeThisTcData thisCompilationCmdLine thisCompilationGraph
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheAbsent []

let thisCompilationCmdLine = getThisCompilationCmdLine ()
let thisCompilationGraph = getThisCompilationGraph ()
writeThisTcData thisCompilationCmdLine thisCompilationGraph

let CheckClosedInputSet (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, eagerFormat, inputs) =

if tcConfig.reuseTypecheckingResults = ReuseTypecheckingResults.On then
TryReuseTypecheckingResults tcConfig inputs
ReuseTcResultsDriver.TryReuseTypecheckingResults tcConfig inputs

// tcEnvAtEndOfLastFile is the environment required by fsi.exe when incrementally adding definitions
let results, tcState =
Expand Down
113 changes: 113 additions & 0 deletions src/Compiler/Driver/ReuseTcResults/ReuseTcResultsDriver.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
module internal FSharp.Compiler.ReuseTcResults.ReuseTcResultsDriver

open System
open System.IO

open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.GraphChecking
open FSharp.Compiler.IO
open FSharp.Compiler.Syntax
open FSharp.Compiler.Syntax.PrettyNaming

open Internal.Utilities.Hashing

let TryReuseTypecheckingResults (tcConfig: TcConfig) inputs =
let (++) a b = Path.Combine(a, b)

let outputDir = tcConfig.outputDir |> Option.defaultValue ""
let tcDataFolderName = outputDir ++ FSharpTypecheckingDataResourceName
let cmdFileName = "cmd"
let graphFileName = "graph"
let referencesFileName = "references"

let getContentHash fileName =
use stream = FileSystem.OpenFileForReadShim fileName
let bytes = stream.ReadAllBytes()
let contentHash = Md5Hasher.computeHash bytes
contentHash |> BitConverter.ToString

let getThisCompilationCmdLine () =
tcConfig.cmdLineArgs |> String.concat Environment.NewLine

let getThisCompilationGraph () =
let sourceFiles =
inputs
|> Seq.toArray
|> Array.mapi (fun idx (input: ParsedInput) ->
{
Idx = idx
FileName = input.FileName
ParsedInput = input
})

let filePairs = FilePairMap sourceFiles

DependencyResolution.mkGraph filePairs sourceFiles
|> fst
|> Graph.map (fun idx -> idx, getContentHash sourceFiles[idx].FileName)
|> Graph.asString

let getThisCompilationReferences () =
tcConfig.referencedDLLs
|> List.map (fun r -> r.Text, getContentHash r.Text)
|> List.map (fun (name, hash) -> $"{name}: {hash}")
|> String.concat Environment.NewLine

let writeThisTcData (content: string) (tcDataFileName: string) =
let path = tcDataFolderName ++ tcDataFileName
use tcDataFile = FileSystem.OpenFileForWriteShim path
tcDataFile.WriteAllText content

let readPrevTcData (tcDataFileName: string) =
let path = tcDataFolderName ++ tcDataFileName
if FileSystem.FileExistsShim path then
use tcDataFile = FileSystem.OpenFileForReadShim path
tcDataFile.ReadAllText()
else
""

let getPrevCompilationCmdLine() = readPrevTcData cmdFileName
let getPrevCompilationGraph() = readPrevTcData graphFileName
let getPrevCompilationReferences() = readPrevTcData referencesFileName

let writeThisCompilationCmdLine cmdLine = writeThisTcData cmdLine cmdFileName
let writeThisCompilationGraph graph = writeThisTcData graph graphFileName
let writeThisCompilationReferences references = writeThisTcData references referencesFileName

if FileSystem.DirectoryExistsShim tcDataFolderName then
use _ = Activity.start Activity.Events.reuseTcResultsCachePresent []

let prevCompilationCmdLine = getPrevCompilationCmdLine ()
let thisCompilationCmdLine = getThisCompilationCmdLine ()
if prevCompilationCmdLine = thisCompilationCmdLine then

let prevCompilationReferences = getPrevCompilationReferences ()
let thisCompilationReferences = getThisCompilationReferences ()
if prevCompilationReferences = thisCompilationReferences then

let prevCompilationGraph = getPrevCompilationGraph ()
let thisCompilationGraph = getThisCompilationGraph ()
if prevCompilationGraph = thisCompilationGraph then
use _ = Activity.start Activity.Events.reuseTcResultsCacheHit []

() // do nothing, yet
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheMissed []

writeThisCompilationGraph thisCompilationGraph
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheMissed []

writeThisCompilationReferences thisCompilationReferences
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheMissed []

writeThisCompilationCmdLine thisCompilationCmdLine
else
use _ = Activity.start Activity.Events.reuseTcResultsCacheAbsent []

let _ = FileSystem.DirectoryCreateShim tcDataFolderName
writeThisCompilationCmdLine (getThisCompilationCmdLine())
writeThisCompilationGraph (getThisCompilationGraph())
writeThisCompilationReferences (getThisCompilationReferences())
10 changes: 10 additions & 0 deletions src/Compiler/Driver/ReuseTcResults/ReuseTcResultsDriver.fsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module internal FSharp.Compiler.ReuseTcResults.ReuseTcResultsDriver

open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.Syntax


val TryReuseTypecheckingResults:
tcConfig: TcConfig ->
inputs: ParsedInput seq ->
unit
2 changes: 1 addition & 1 deletion src/Compiler/Driver/fsc.fs
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ let main1
)

tcConfigB.exiter <- exiter
tcConfigB.cmdLineArgs <- argv
tcConfigB.cmdLineArgs <- argv |> Array.filter (fun a -> a.StartsWith "-r:" |> not)

// Preset: --optimize+ -g --tailcalls+ (see 4505)
SetOptimizeSwitch tcConfigB OptionSwitch.On
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/FSharp.Compiler.Service.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@
<Compile Include="Driver\GraphChecking\GraphProcessing.fsi" />
<Compile Include="Driver\GraphChecking\GraphProcessing.fs" />
<Content Include="Driver\GraphChecking\Docs.md" />
<Compile Include="Driver\ReuseTcResults\ReuseTcResultsDriver.fsi" />
<Compile Include="Driver\ReuseTcResults\ReuseTcResultsDriver.fs" />
<Compile Include="Driver\ParseAndCheckInputs.fsi" />
<Compile Include="Driver\ParseAndCheckInputs.fs" />
<Compile Include="Driver\ScriptClosure.fsi" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ open Xunit
open FSharp.Compiler.Diagnostics
open FSharp.Test.Compiler
open TestFramework
open FSharp.Test

type Activities() =

let tempDir = DirectoryInfo (createTemporaryDirectory "temp")
let tempDir = DirectoryInfo (createTemporaryDirectory "temp") |> Some
let tempName = getTemporaryFileName()

let actualActivities = List<string>()
Expand All @@ -36,7 +37,7 @@ type Activities() =

let cUnit =
Fsx "42"
|> withOutputDirectory (Some tempDir)
|> withOutputDirectory tempDir
|> withName tempName

cUnit
Expand All @@ -47,7 +48,7 @@ type Activities() =

let cUnit =
Fsx "43"
|> withOutputDirectory (Some tempDir)
|> withOutputDirectory tempDir
|> withName tempName

cUnit
Expand All @@ -68,7 +69,7 @@ type Activities() =

let cUnit =
Fsx "42"
|> withOutputDirectory (Some tempDir)
|> withOutputDirectory tempDir
|> withName tempName

cUnit
Expand All @@ -87,7 +88,49 @@ type Activities() =
Assert.Equal<List<string>>(expectedActivities, actualActivities)

[<Fact>]
let ``Recompilation with unchanged sources and command line``() =
let ``Recompilation with changed references``() =
let expectedActivities = List<string> [
Activity.Events.reuseTcResultsCacheAbsent
Activity.Events.reuseTcResultsCachePresent
Activity.Events.reuseTcResultsCacheMissed
]

let reference =
FSharp "module Old"
|> withName "ref"

let cUnit =
Fsx "42"
|> withReferences [ reference ]
|> withOutputDirectory tempDir
|> withName tempName

cUnit
|> withReuseTypecheckingResults
|> compile
|> shouldSucceed
|> ignore

let reference =
FSharp "module New"
|> withName "ref"

let cUnit =
Fsx "42"
|> withReferences [ reference ]
|> withOutputDirectory tempDir
|> withName tempName

cUnit
|> withReuseTypecheckingResults
|> compile
|> shouldSucceed
|> ignore

Assert.Equal<List<string>>(expectedActivities, actualActivities)

[<Fact>]
let ``Recompilation with everything same``() =
let expectedActivities = List<string> [
Activity.Events.reuseTcResultsCacheAbsent
Activity.Events.reuseTcResultsCachePresent
Expand All @@ -96,7 +139,7 @@ type Activities() =

let cUnit =
Fsx "42"
|> withOutputDirectory (Some tempDir)
|> withOutputDirectory tempDir
|> withName tempName

cUnit
Expand Down
Loading

0 comments on commit 6df7695

Please sign in to comment.