-
Notifications
You must be signed in to change notification settings - Fork 789
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
[Experimental]
[WIP]
Transparent Compiler
#15179
Conversation
[Experimental][WIP]
Transparent Compiler[Experimental]
[WIP]
Transparent Compiler
This looks awesome and absolutely should work! |
I added some basic synthetic project benchmarks (results in the description). Looks promising so far. In the DependencyChain project where each file depends on the previous one the performance is similar to IncrementalBuilder, but with less allocations and memory consumed. In the other scenarios where we can leverage graph checking by either parallelization or skipping unneeded work we can see the expected time savings. There is significantly more Completed Work Items. If it has no other side effects then it probably won't bother us but might need to look into that... |
@0101 let me know when you think this API is pretty stable and I'll give it a run in FSAC. |
Status updateAfter the latest tweaks it seems to work with Giraffe solution. Which is the simplest one I found that contains some real world useful code :) So if someone has some smaller projects like that, you could already try it out. It doesn't quite work with VisualFSharp solution yet, but I'll be now looking at what are the missing pieces for that... |
There's some special logic around having FSharp.Core as a project in a solution. You may want to try using it on FSharp.Compiler.Service.sln in a fresh working copy, it doesn't contain that project reference. |
Yeah I'm hoping to do that, but not sure exactly how yet. So far my idea was to enable the SyntheticProject / workflow builder to load real projects from disk and then work with them in a similar way. |
@0101 please post the latest and greatest benchmark results before merging - practice shows it will be helpful for future reference. |
Current results for the Giraffe benchmarkNote that this is with checking all preceding files - not skipping ones that we don't depend on.
|
Thanks for sharing these numbers @0101! Great work! |
@0101 Shall this be merged, or are there any pending changes? |
@vzarytovskii I want to improve the tests as pointed out by Smaug123, but it can also be done separately. |
Up to you, but if you ask me, we should merge now to not end up in a never ending cycle of fixing small things and never merging. |
I've tried to update our FCS fork and also found some instability, seemingly related to requests cancelation. My theory is it may be #16348 to blame, but I haven't an opportunity to look into it further yet. It seems that the previous approach from #16137 works as expected (though, some access to metadata is not guarded with cancellation tokens). @0101 Could you try to check if reverting #16348 would improve stability of the tests? |
@auduchinok fwiw (not really related to this PR per se), once this is merged, I will be rewriting NodeBuilder to state machines (pretty much cancellable task), so cancellation will change a bit there. |
I wouldn't expect that to be a problem, since the tests don't run in parallel. I just didn't spend much effort on writing the tests properly, so I still want to do that first. |
I have a counter-opinion, but I commit very rarely to this repo so downweight it accordingly. I consider flaky tests to be seriously bad (like "drop everything and fix this; if nothing else just delete the test" bad). Their effect is to very rapidly cause people to distrust all the tests, they greatly increase the friction of contributing, and they essentially prevent most automation on the repo (such as the not rocket science rule); and the reputation of a project "having flaky tests" is extremely hard to reverse. To my surprise, Dan Luu has not actually written directly about this, but he has written on broken builds and the normalisation of deviance. |
|
||
let processStateUpdate post (key: KeyData<_, _>, action: StateUpdate<_>) = | ||
task { | ||
do! Task.Delay 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Task.Delay
with 0 ms is a special case and just returns Task.CompletedTask
.
Task.Yield ()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, yeah, that's what I wanted. Wonder if it's actually necessary.
* Name resolution: keep type vars in subsequent checks (#16456) * Keep typars produced in name resolution * Better debug errors * Unwrap measure type vars * Undo check declarations change * Fix reported range * Undo occurrence change * Skip path typars * Add test * More freshen typar APIs properly * Fantomas * Cleanup * Add release notes * 123 --------- Co-authored-by: Vlad Zarytovskii <vzaritovsky@hotmail.com> * Build benchmarks in CI (#16518) * Remove profiling startpoint project * Add bench build job * Up * up * up --------- Co-authored-by: Kevin Ransom (msft) <codecutter@hotmail.com> * More ValueOption in compiler: part 1 (#16323) * More ValueOption in compiler: part 1 * release notes * Update CheckComputationExpressions.fs * release notes * `[Experimental]` `[WIP]` Transparent Compiler (#15179) * Track CheckDeclarations.CheckModuleSignature activity. (#16534) * Add Computation Expression Benchmarks (#16541) * add benchmarks for various usages of CEs * refactor * move CE source files to dedicated ce folder * Update Roslyn to a version which uses Immutable v7 (#16545) * revert #16326 (addition of XliffTasks reference) (#16548) * updated devcontainer image (#16551) * Add higher-order-function-based API for working with untyped AST (#16462) * Add module-based API for working with untyped AST * Fantomas * tryPickUntil → tryPickDownTo * Don't need that * Thread path while walking * Update comment * Simplify * Expose `Ast.fold` and `Ast.tryPick`. * Expose `SyntaxNode.(|Attributes|)`. * Ensure a few more syntax node cases get hit. * Update FCS release notes * Update surface area * Add back `foldWhile`; add `exists`, `tryNode` * Put `Ast.foldWhile` back in. * Add `Ast.exists`. * Add `Ast.tryNode`. * `SyntaxTraversal.Traverse` → `Ast.tryPick`… * Replace uses of `SyntaxTraversal.Traverse` in `FSharpParseFileResults` with the appropriate function from the `Ast` module: `exists`, `tryPick`, `tryNode`. * Update surface area * Need that * Just to be safe * Add `Ast.tryPickLast` * Handle multiple args mid-pipeline * Before, no signature help was offered in a case like this: ```fsharp [1..10] |> List.fold (fun acc _ -> acc) ‸ |> List.filter (fun x -> x > 3) ``` The service will now offer help for the `state` parameter when the cursor ‸ is in that location. * `*` instead of error * `FSharpParseFileResults.TryRangeOfFunctionOrMethodBeingApplied` was previously returning the range of the (zero-width) `SynExpr.ArbitraryAfterError`. It now returns the range of the `*` (`op_Multiply`) instead. * Update surface area * Fmt * Missed in merge * Add VS release notes entry * # → ### * Add ryPick tests * Add a few more tests * \n * Bump release notes * Fmt * `Ast` → `ParsedInput` * Use `ParsedInput` as the main AST type. * Move the `position` parameter rightward. * Update surface area * Less `function` * Update untyped AST docs * Add basic examples for `ParsedInput` module functions. * Merge the existing `SyntaxVisitorBase` docs into the new file. * Clean up doc comments --------- Co-authored-by: Vlad Zarytovskii <vzaritovsky@hotmail.com> * Move paren entries to appropriate releases (#16561) * [main] Update dependencies from dotnet/source-build-reference-packages (#16532) * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240115.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24059.3 -> To Version 9.0.0-alpha.1.24065.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240116.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24059.3 -> To Version 9.0.0-alpha.1.24066.1 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240117.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24059.3 -> To Version 9.0.0-alpha.1.24067.1 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240117.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24059.3 -> To Version 9.0.0-alpha.1.24067.1 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240117.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24059.3 -> To Version 9.0.0-alpha.1.24067.1 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240117.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24059.3 -> To Version 9.0.0-alpha.1.24067.1 --------- Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: Vlad Zarytovskii <vzaritovsky@hotmail.com> * Attempt to make links from single identifier module names. (#16550) * Add scenarios where parentheses are around module name. * Address problem tighter to nameof usage. * Restore missing commit and inline nameof ident check. * Add release note entry. * rewrite SizeOfValueInfo in Optimizer.fs to be tail-recursive (#16559) * rewrite SizeOfValueInfo in Optimizer.fs to be tail-recursive * use Brians rewrite into one local function * stringbuilder is not threadsafe (#16557) * Array postfix notation in fsharp core api (#16564) * changed array types to postfix form in all signatures * changed array types to postfix form in the implementation files * Revert 16348 (#16536) * Improve AsyncMemoize tests * relax test condition * Revert "Cancellable: set token from node/async in features code (#16348)" This reverts commit d4e3b26. * remove UsingToken * remove UsingToken * test improvement * relax test condition * use thread-safe collections when collecting events from AsyncMemoize * fix flaky test * release note * Small code reshuffle for diff minimization (#16569) * Moving code around * Small code reshuffle for diff minimization * wat * Refactor parens API (#16461) * Refactor parens API * Remove `UnnecessaryParentheses.getUnnecessaryParentheses`. * Expose `SynExpr.shouldBeParenthesizedInContext`. * Expose `SynPat.shouldBeParenthesizedInContext`. * Expose `SyntaxTraversal.TraverseAll`. * Fantomas * Use `ParsedInput.fold` * Tests * Update surface area * Clean up sigs & comments * Update release notes * Remove redundant async * Remove stubs (no longer needed) * Preserve original stacktrace in state machines if available (#16568) * Preserve original stacktrace in state machines if available * Update release notes * Automated command ran: fantomas Co-authored-by: vzarytovskii <1260985+vzarytovskii@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * check reportErrors and feature support at top level (#16549) * Align DU case augmentation with previous behavior in EraseUnions (#16571) * Align DU case augment with previous behavior in EraseUnions * Update 8.0.300.md * modify tests * Refresh debug surface area (#16573) * Remove superfluous rec keywords and untangle some functions (#16544) * remove some superfluous rec keywords and untangle two functions that aren't mutually recursive. * Don't throw on invalid input in Graph construction (#16575) * More ValueOption in compiler: part 2 (#16567) * More ValueOption in complier: part 2 * Update release notes * extra optimization * extra optimization 2 * fantomas * Update dependencies from https://github.com/dotnet/arcade build 20240123.2 (#16579) Microsoft.DotNet.Arcade.Sdk From Version 8.0.0-beta.24060.4 -> To Version 8.0.0-beta.24073.2 Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com> * [main] Update dependencies from dotnet/source-build-reference-packages (#16574) * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240122.5 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24067.1 -> To Version 9.0.0-alpha.1.24072.5 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20240123.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.24067.1 -> To Version 9.0.0-alpha.1.24073.1 --------- Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com> * Improve AsyncMemoize tests (#16580) --------- Co-authored-by: Eugene Auduchinok <eugene.auduchinok@gmail.com> Co-authored-by: Vlad Zarytovskii <vzaritovsky@hotmail.com> Co-authored-by: Petr <psfinaki@users.noreply.github.com> Co-authored-by: Kevin Ransom (msft) <codecutter@hotmail.com> Co-authored-by: Petr Pokorny <petrpokorny@microsoft.com> Co-authored-by: Florian Verdonck <florian.verdonck@outlook.com> Co-authored-by: dawe <dawedawe@posteo.de> Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com> Co-authored-by: Martin <29605222+Martin521@users.noreply.github.com> Co-authored-by: Brian Rourke Boll <brianrourkeboll@users.noreply.github.com> Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: Jakub Majocha <1760221+majocha@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Transparent Compiler
Synopsis
This is an attempt to replace the current
BackgroundCompiler
(powered byIncrementalBuilder
) with a new system that will be easier to understand and change and that will also be in line with #11976Issues with current Background Compiler
What bothers me a lot with current
IncrementalBuilder
/GraphNode
/BoundModel
system is the opaqueness of the workflow. It's often difficult to follow the code because it suddenly calls a graph node, which contains a computation which was constructed at some prior point but now there's no link to the actual code that will be executed. Hence the name Transparent compiler and the attempt to make this better 😄 (mostly I had no good idea for what to call this).How is this different
The idea is to replace the
GraphNode
with a sort of cache/memoization, so that the computation can be accessed from anywhere given the correct key/input. Instead of having to have a reference to a pre-constructed graph which needs to be stored and updated.So the resulting code should look mostly as if we're calculating everything from scratch for every single request - hopefully simple and with no mis-direction - except some intermediate steps (and the whole result as well) will be cached/memoized.
Will this work?
🤷 I don't know, but I want to try.
Goals
Functional goals
Non-functional goals
Possible future benefits
Technical details
Caching / memoization
We need to deal with concurrency and cancellation and we don't want to repeat the same computations. To do this we use a similar system that was already implemented in
GraphNode
, but never used. The cache will store aTask
(ornode
, still to be decided) and will serialize all requests withaan async lock which makes sure to only start the computation once and keep track of request count to see if it should be canceled.MailboxProcessor
API
We need a new format for parsing/checking requests that will contain everything needed to perform the operations. The major difference to the current API is replacing
FSharpProjectOptions.SourceFiles
file, which is now just a string with path, with a record that will also have aVersion
(which we will fully rely on when caching) and aGetSource: unit -> Task<ISourceText>
which we will call if we need to get the contents.The output/results should remain the same.
Transition from current background compiler
The new API is a superset of the old one so we can keep all the old code and switch between them with a configuration flag. This way we can offer it to early adopters for testing with a way to switch back if it doesn't work properly.
Also during development
TransparentCompilerkeeps it's own instance of
BackgroundCompiler` and uses it for workflows that are not yet implemented, so it can be tested before completing everything.Status
It's a work in progress. Feel free to have a look and give any kind of feedback!
You can also check out this branch, build it and try it out (in VS, it can be enabled in F# advanced options). It should more or less work for F#-only solutions that don't do anything fancy.
Some of the things that still need to be done:
AsyncMemoize
FSharpChecker
TcInfo
s from files processed in parallelitemKeyStore
and other stuff fromTcInfoExtras
TcIntermediate
results in ParseAndCheckFileInProject if availableNodeToTypeCheck
AsyncMemoize
?
Add some types aroundAsyncMemoize
to prevent accidentally using the wrong key vs. computation inputneed it for diagnostics scopes?
Get rid ofNodeCode
and use justTask
(maybe cancellable task builder?)More efficient implementation ofdon't need itleafSequence
too hard?
Figure out mergingTcInfo
s from files processed in parallel without callbacksSome preliminary synthetic benchmarks