diff --git a/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs b/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs index 6dd82b004..4a1f90059 100644 --- a/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs +++ b/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs @@ -23,14 +23,28 @@ public void Setup() } [Benchmark] - public EmitResult Compile() + public EmitResult CompileSingleThreaded() { var syntaxTree = SyntaxTree.Parse(this.Input.Code, Path.GetFullPath(this.Input.Path)); var compilation = Compilation.Create( syntaxTrees: ImmutableArray.Create(syntaxTree), metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) - .ToImmutableArray()); + .ToImmutableArray(), + useMultithreading: false); + return compilation.Emit(peStream: this.peStream); + } + + [Benchmark] + public EmitResult CompileMultiThreaded() + { + var syntaxTree = SyntaxTree.Parse(this.Input.Code, Path.GetFullPath(this.Input.Path)); + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(syntaxTree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .ToImmutableArray(), + useMultithreading: true); return compilation.Emit(peStream: this.peStream); } } diff --git a/src/Draco.Compiler/Api/Compilation.cs b/src/Draco.Compiler/Api/Compilation.cs index de35c071f..9036432af 100644 --- a/src/Draco.Compiler/Api/Compilation.cs +++ b/src/Draco.Compiler/Api/Compilation.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Threading.Tasks; using Draco.Compiler.Api.Diagnostics; using Draco.Compiler.Api.Semantics; using Draco.Compiler.Api.Syntax; @@ -45,13 +46,16 @@ public sealed class Compilation : IBinderProvider /// The path of the root module. /// The output path. /// The output assembly name. + /// True, if multithreading should be used. /// The constructed . public static Compilation Create( ImmutableArray syntaxTrees, ImmutableArray? metadataReferences = null, string? rootModulePath = null, string? outputPath = null, - string? assemblyName = null) => new( + string? assemblyName = null, + bool useMultithreading = true) => new( + useMultithreading: useMultithreading, syntaxTrees: syntaxTrees, metadataReferences: metadataReferences, rootModulePath: rootModulePath, @@ -67,6 +71,11 @@ public static Compilation Create( .Concat(this.GlobalDiagnosticBag) .ToImmutableArray(); + /// + /// True, if threading is utilized by the compilation. + /// + public bool UseMultithreading { get; } + /// /// The trees that are being compiled. /// @@ -148,6 +157,7 @@ public static Compilation Create( // Main ctor with all state private Compilation( + bool useMultithreading, ImmutableArray syntaxTrees, ImmutableArray? metadataReferences, string? rootModulePath = null, @@ -162,6 +172,7 @@ private Compilation( IntrinsicSymbols? intrinsicSymbols = null, BinderCache? binderCache = null) { + this.UseMultithreading = useMultithreading; this.SyntaxTrees = syntaxTrees; this.MetadataReferences = metadataReferences ?? ImmutableArray.Empty; this.RootModulePath = Path.TrimEndingDirectorySeparator(rootModulePath ?? string.Empty); @@ -205,6 +216,7 @@ public Compilation UpdateSyntaxTree(SyntaxTree? oldTree, SyntaxTree? newTree) } return new Compilation( + useMultithreading: this.UseMultithreading, syntaxTrees: newSyntaxTrees.ToImmutable(), metadataReferences: this.MetadataReferences, rootModulePath: this.RootModulePath, @@ -306,6 +318,31 @@ public EmitResult Emit( Diagnostics: ImmutableArray.Empty); } + internal Task RunOnThread(Action action) + { + if (this.UseMultithreading) + { + return Task.Run(action); + } + else + { + action(); + return Task.CompletedTask; + } + } + + internal Task RunOnThread(Func func) + { + if (this.UseMultithreading) + { + return Task.Run(func); + } + else + { + return Task.FromResult(func()); + } + } + internal ModuleSymbol GetModuleForSyntaxTree(SyntaxTree tree) { var filePath = SplitPath.FromFilePath(tree.SourceText.Path?.LocalPath ?? string.Empty); diff --git a/src/Draco.Compiler/Api/Semantics/SemanticModel.cs b/src/Draco.Compiler/Api/Semantics/SemanticModel.cs index 58ac85c4d..80ca79d70 100644 --- a/src/Draco.Compiler/Api/Semantics/SemanticModel.cs +++ b/src/Draco.Compiler/Api/Semantics/SemanticModel.cs @@ -83,13 +83,13 @@ private ImmutableArray GetDiagnostics(SourceSpan? span = null) case CompilationUnitSyntax: case FunctionDeclarationSyntax: { - tasks.Add(Task.Run(() => containingSymbol?.Bind(this))); + tasks.Add(this.compilation.RunOnThread(() => containingSymbol?.Bind(this))); break; } // NOTE: Only globals need binding case VariableDeclarationSyntax when containingSymbol is SourceModuleSymbol containingModule: { - tasks.Add(Task.Run(() => + tasks.Add(this.compilation.RunOnThread(() => { // We need to search for this global var globalSymbol = containingModule.Members