From 3b3764d2500b82861cb865bc7c69a2951cee8f21 Mon Sep 17 00:00:00 2001 From: Anubhav Srivastava Date: Wed, 2 Oct 2019 14:04:51 -0700 Subject: [PATCH] Change PerfEventSource to be able to use 'using'. (dotnet/coreclr#26981) * Change and reorganize PerfEventSource to be able to use using. Commit migrated from https://github.com/dotnet/coreclr/commit/4e680b3d82effacd72d8394eee9cf01b501b9207 --- .../tools/ReadyToRun.SuperIlc/ParallelRunner.cs | 2 +- .../ReadyToRun.SuperIlc/PerfEventSourceListener.cs | 25 +- .../DependencyAnalyzer.cs | 50 ++-- .../PerfEventSource.cs | 55 +++- .../Compiler/PerfEventSource.cs | 88 ++++++- .../Compiler/ReadyToRunCodegenCompilation.cs | 104 ++++---- .../src/tools/crossgen2/crossgen2/Program.cs | 283 +++++++++++---------- 7 files changed, 367 insertions(+), 240 deletions(-) diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs b/src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs index 3a9eed3..f2c705b 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs +++ b/src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs @@ -270,7 +270,7 @@ public sealed class ParallelRunner } while (freeSlot == null); - freeSlot.Launch(processInfo, jittedMethods, index, totalCount, progressIndex, failureCount); + freeSlot.Launch(processInfo, jittedMethods, index + 1, totalCount, progressIndex, failureCount); } // We have launched all the commands, now wait for all processes to finish diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs b/src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs index 94568ae..b952714 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs +++ b/src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs @@ -24,7 +24,8 @@ public sealed class PerfEventSourceListener private double _loadingMsec = 0; private double _graphProcessingMsec = 0; private double _emittingMsec = 0; - private double _jitMsec = 0; + private double _jitMsec = 0; // Wall clock time spent JITing methods + private double _totalJitMsec = 0; // CPU time spent JITing methods (sum of all threads) private double _dependencyAnalysisMsec = 0; private int _methodsJitted = 0; private int nodesAddedToMarkStack = 0; @@ -100,10 +101,7 @@ public sealed class PerfEventSourceListener traceEventSession.Source.Dynamic.AddCallbackForProviderEvent(providerName, "Jit/Start", delegate (TraceEvent traceEvent) { if (_doneWarmup.WaitOne(0)) - { _jitMsec -= traceEvent.TimeStampRelativeMSec; - _methodsJitted++; - } }); traceEventSession.Source.Dynamic.AddCallbackForProviderEvent(providerName, "Jit/Stop", delegate (TraceEvent traceEvent) { @@ -111,6 +109,21 @@ public sealed class PerfEventSourceListener _jitMsec += traceEvent.TimeStampRelativeMSec; }); + traceEventSession.Source.Dynamic.AddCallbackForProviderEvent(providerName, "JitMethod/Start", delegate (TraceEvent traceEvent) + { + if (_doneWarmup.WaitOne(0)) + { + _totalJitMsec -= traceEvent.TimeStampRelativeMSec; + ++_methodsJitted; + } + }); + traceEventSession.Source.Dynamic.AddCallbackForProviderEvent(providerName, "JitMethod/Stop", delegate (TraceEvent traceEvent) + { + if (_doneWarmup.WaitOne(0)) + _totalJitMsec += traceEvent.TimeStampRelativeMSec; + }); + + traceEventSession.Source.Dynamic.AddCallbackForProviderEvent(providerName, "DependencyAnalysis/Start", delegate (TraceEvent traceEvent) { if (_doneWarmup.WaitOne(0)) @@ -146,7 +159,9 @@ public sealed class PerfEventSourceListener writer.Indent++; writer.WriteLine($"Added {nodesAddedToMarkStack / _totalRealRuns} nodes to mark stack"); writer.WriteLine($"Dependency analysis time: {_dependencyAnalysisMsec / _totalRealRuns:F2} ms"); - writer.WriteLine($"JIT time: {_jitMsec / _totalRealRuns:F2} ms ({_methodsJitted / _totalRealRuns} methods JITed)"); + writer.WriteLine($"Wall clock JIT time: {_jitMsec / _totalRealRuns:F2} ms"); + writer.WriteLine($"Total JIT time: {_totalJitMsec / _totalRealRuns:F2} ms (sum of all threads)"); + writer.WriteLine($"{_methodsJitted/ _totalRealRuns} methods JITed"); writer.Indent--; writer.WriteLine($"Emitting time: {_emittingMsec / _totalRealRuns:F2} ms"); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs index f51f150..18187a1 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs @@ -250,35 +250,37 @@ namespace ILCompiler.DependencyAnalysisFramework public override void ComputeMarkedNodes() { - PerfEventSource.Log.GraphProcessingStart(); - if (_markingCompleted) - return; - - do + using (PerfEventSource.StartStopEvents.GraphProcessingEvents()) { - // Run mark stack algorithm as much as possible - PerfEventSource.Log.DependencyAnalysisStart(); - ProcessMarkStack(); - PerfEventSource.Log.DependencyAnalysisStop(); - - // Compute all dependencies which were not ready during the ProcessMarkStack step - ComputeDependencies(_deferredStaticDependencies); - foreach (DependencyNodeCore node in _deferredStaticDependencies) + if (_markingCompleted) + return; + + do { - Debug.Assert(node.StaticDependenciesAreComputed); - GetStaticDependenciesImpl(node); - } + // Run mark stack algorithm as much as possible + using (PerfEventSource.StartStopEvents.DependencyAnalysisEvents()) + { + ProcessMarkStack(); + } - _deferredStaticDependencies.Clear(); - } while (_markStack.Count != 0); + // Compute all dependencies which were not ready during the ProcessMarkStack step + ComputeDependencies(_deferredStaticDependencies); + foreach (DependencyNodeCore node in _deferredStaticDependencies) + { + Debug.Assert(node.StaticDependenciesAreComputed); + GetStaticDependenciesImpl(node); + } - if (_resultSorter != null) - _markedNodes.Sort(_resultSorter); + _deferredStaticDependencies.Clear(); + } while (_markStack.Count != 0); - _markedNodesFinal = _markedNodes.ToImmutableArray(); - _markedNodes = null; - _markingCompleted = true; - PerfEventSource.Log.GraphProcessingStop(); + if (_resultSorter != null) + _markedNodes.Sort(_resultSorter); + + _markedNodesFinal = _markedNodes.ToImmutableArray(); + _markedNodes = null; + _markingCompleted = true; + } } private bool AddToMarkStack(DependencyNodeCore node, string reason, DependencyNodeCore reason1, DependencyNodeCore reason2) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs index dbbb0c8..604855d 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs @@ -2,30 +2,67 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Diagnostics.Tracing; /// -/// Performance events releated to the dependency graph. +/// Performance events specific to the dependency graph. /// namespace ILCompiler.DependencyAnalysisFramework { - // The event IDs here must not collide with the ones used by ReadyToRunPerfEventSource.cs [EventSource(Name = "Microsoft-ILCompiler-Perf")] - class PerfEventSource : EventSource + public class PerfEventSource : EventSource { + private PerfEventSource() { } + + public static PerfEventSource Log = new PerfEventSource(); + + public struct StartStopEvents : IDisposable + { + private Action _stopAction; + + private StartStopEvents(Action stopAction) + { + _stopAction = stopAction; + } + + public void Dispose() + { + _stopAction?.Invoke(); + } + + public static StartStopEvents GraphProcessingEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.GraphProcessingStart(); + return new StartStopEvents(Log.GraphProcessingStop); + } + + public static StartStopEvents DependencyAnalysisEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.DependencyAnalysisStart(); + return new StartStopEvents(Log.DependencyAnalysisStop); + } + } + + // The event IDs here must not collide with the ones used by ReadyToRunPerfEventSource.cs [Event(1001, Level = EventLevel.Informational)] - public void GraphProcessingStart() { WriteEvent(1001); } + private void GraphProcessingStart() { WriteEvent(1001); } [Event(1002, Level = EventLevel.Informational)] - public void GraphProcessingStop() { WriteEvent(1002); } + private void GraphProcessingStop() { WriteEvent(1002); } [Event(1003, Level = EventLevel.Informational)] - public void DependencyAnalysisStart() { WriteEvent(1003); } + private void DependencyAnalysisStart() { WriteEvent(1003); } [Event(1004, Level = EventLevel.Informational)] - public void DependencyAnalysisStop() { WriteEvent(1004); } + private void DependencyAnalysisStop() { WriteEvent(1004); } [Event(1005, Level = EventLevel.Informational)] public void AddedNodeToMarkStack() { WriteEvent(1005); } - - public static PerfEventSource Log = new PerfEventSource(); } + } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/PerfEventSource.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/PerfEventSource.cs index 238cce4..fa9ca6c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/PerfEventSource.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/PerfEventSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Diagnostics.Tracing; /// @@ -9,30 +10,97 @@ using System.Diagnostics.Tracing; /// namespace ILCompiler { - // The event IDs here must not collide with the ones used by DependencyAnalysis' PerfEventSource [EventSource(Name = "Microsoft-ILCompiler-Perf")] public class PerfEventSource : EventSource { + private PerfEventSource() { } + + public static PerfEventSource Log = new PerfEventSource(); + + public struct StartStopEvents : IDisposable + { + private Action _stopAction; + + private StartStopEvents(Action stopAction) + { + _stopAction = stopAction; + } + + public void Dispose() + { + _stopAction?.Invoke(); + } + + public static StartStopEvents LoadingEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.LoadingStart(); + return new StartStopEvents(Log.LoadingStop); + } + + public static StartStopEvents EmittingEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.EmittingStart(); + return new StartStopEvents(Log.EmittingStop); + } + + public static StartStopEvents CompilationEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.CompilationStart(); + return new StartStopEvents(Log.CompilationStop); + } + + public static StartStopEvents JitEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.JitStart(); + return new StartStopEvents(Log.JitStop); + } + + public static StartStopEvents JitMethodEvents() + { + if (!Log.IsEnabled()) + return new StartStopEvents(); + + Log.JitMethodStart(); + return new StartStopEvents(Log.JitMethodStop); + } + } + + // The event IDs here must not collide with the ones used by DependencyAnalysis' PerfEventSource [Event(1, Level = EventLevel.Informational)] - public void LoadingStart() { WriteEvent(1); } + private void LoadingStart() { WriteEvent(1); } [Event(2, Level = EventLevel.Informational)] - public void LoadingStop() { WriteEvent(2); } + private void LoadingStop() { WriteEvent(2); } [Event(3, Level = EventLevel.Informational)] - public void EmittingStart() { WriteEvent(3); } + private void EmittingStart() { WriteEvent(3); } [Event(4, Level = EventLevel.Informational)] - public void EmittingStop() { WriteEvent(4); } + private void EmittingStop() { WriteEvent(4); } [Event(5, Level = EventLevel.Informational)] - public void CompilationStart() { WriteEvent(5); } + private void CompilationStart() { WriteEvent(5); } [Event(6, Level = EventLevel.Informational)] - public void CompilationStop() { WriteEvent(6); } + private void CompilationStop() { WriteEvent(6); } [Event(7, Level = EventLevel.Informational)] - public void JitStart() { WriteEvent(7); } + private void JitStart() { WriteEvent(7); } [Event(8, Level = EventLevel.Informational)] - public void JitStop() { WriteEvent(8); } + private void JitStop() { WriteEvent(8); } - public static PerfEventSource Log = new PerfEventSource(); + [Event(9, Level = EventLevel.Informational)] + private void JitMethodStart() { WriteEvent(9); } + [Event(10, Level = EventLevel.Informational)] + private void JitMethodStop() { WriteEvent(10); } } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 0994170..eb5e6b3 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -218,10 +218,11 @@ namespace ILCompiler _dependencyGraph.ComputeMarkedNodes(); var nodes = _dependencyGraph.MarkedNodeList; - PerfEventSource.Log.EmittingStart(); - NodeFactory.SetMarkingComplete(); - ReadyToRunObjectWriter.EmitObject(inputPeReader, outputFile, nodes, NodeFactory); - PerfEventSource.Log.EmittingStop(); + using (PerfEventSource.StartStopEvents.EmittingEvents()) + { + NodeFactory.SetMarkingComplete(); + ReadyToRunObjectWriter.EmitObject(inputPeReader, outputFile, nodes, NodeFactory); + } } } @@ -238,55 +239,56 @@ namespace ILCompiler protected override void ComputeDependencyNodeDependencies(List> obj) { - foreach (DependencyNodeCore dependency in obj) + using (PerfEventSource.StartStopEvents.JitEvents()) { - var methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; - if (methodCodeNodeNeedingCode == null) - { - // To compute dependencies of the shadow method that tracks dictionary - // dependencies we need to ensure there is code for the canonical method body. - var dependencyMethod = (ShadowConcreteMethodNode)dependency; - methodCodeNodeNeedingCode = (MethodWithGCInfo)dependencyMethod.CanonicalMethodNode; - } - - // We might have already compiled this method. - if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed) - continue; - - MethodDesc method = methodCodeNodeNeedingCode.Method; - if (!NodeFactory.CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false)) - { - // Don't drill into methods defined outside of this version bubble - continue; - } - - if (Logger.IsVerbose) - { - string methodName = method.ToString(); - Logger.Writer.WriteLine("Compiling " + methodName); - } - - try - { - PerfEventSource.Log.JitStart(); - _corInfo.CompileMethod(methodCodeNodeNeedingCode); - } - catch (TypeSystemException ex) - { - // If compilation fails, don't emit code for this method. It will be Jitted at runtime - Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); - } - catch (RequiresRuntimeJitException ex) - { - Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); - } - catch (CodeGenerationFailedException ex) when (_resilient) - { - Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); - } - finally + foreach (DependencyNodeCore dependency in obj) { - PerfEventSource.Log.JitStop(); + var methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; + if (methodCodeNodeNeedingCode == null) + { + // To compute dependencies of the shadow method that tracks dictionary + // dependencies we need to ensure there is code for the canonical method body. + var dependencyMethod = (ShadowConcreteMethodNode)dependency; + methodCodeNodeNeedingCode = (MethodWithGCInfo)dependencyMethod.CanonicalMethodNode; + } + + // We might have already compiled this method. + if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed) + continue; + + MethodDesc method = methodCodeNodeNeedingCode.Method; + if (!NodeFactory.CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false)) + { + // Don't drill into methods defined outside of this version bubble + continue; + } + + if (Logger.IsVerbose) + { + string methodName = method.ToString(); + Logger.Writer.WriteLine("Compiling " + methodName); + } + + try + { + using (PerfEventSource.StartStopEvents.JitMethodEvents()) + { + _corInfo.CompileMethod(methodCodeNodeNeedingCode); + } + } + catch (TypeSystemException ex) + { + // If compilation fails, don't emit code for this method. It will be Jitted at runtime + Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); + } + catch (RequiresRuntimeJitException ex) + { + Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); + } + catch (CodeGenerationFailedException ex) when (_resilient) + { + Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); + } } } } diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs index 8648151..0cbdd5c 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs +++ b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs @@ -227,178 +227,181 @@ namespace ILCompiler throw new CommandLineException("Target OS is not supported"); } - PerfEventSource.Log.CompilationStart(); - PerfEventSource.Log.LoadingStart(); - // - // Initialize type system context - // - - SharedGenericsMode genericsMode = SharedGenericsMode.CanonicalReferenceTypes; - - var targetDetails = new TargetDetails(_targetArchitecture, _targetOS, TargetAbi.CoreRT, SimdVectorLength.None); - CompilerTypeSystemContext typeSystemContext = new ReadyToRunCompilerContext(targetDetails, genericsMode); - - // - // TODO: To support our pre-compiled test tree, allow input files that aren't managed assemblies since - // some tests contain a mixture of both managed and native binaries. - // - // See: https://github.com/dotnet/corert/issues/2785 - // - // When we undo this this hack, replace this foreach with - // typeSystemContext.InputFilePaths = _inputFilePaths; - // - Dictionary inputFilePaths = new Dictionary(); - foreach (var inputFile in _inputFilePaths) + using (PerfEventSource.StartStopEvents.CompilationEvents()) { - try + ICompilation compilation; + using (PerfEventSource.StartStopEvents.LoadingEvents()) { - var module = typeSystemContext.GetModuleFromPath(inputFile.Value); - inputFilePaths.Add(inputFile.Key, inputFile.Value); - } - catch (TypeSystemException.BadImageFormatException) - { - // Keep calm and carry on. - } - } - - typeSystemContext.InputFilePaths = inputFilePaths; - typeSystemContext.ReferenceFilePaths = _referenceFilePaths; - - typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(_systemModuleName)); - - if (typeSystemContext.InputFilePaths.Count == 0) - throw new CommandLineException("No input files specified"); - - // - // Initialize compilation group and compilation roots - // + // + // Initialize type system context + // + + SharedGenericsMode genericsMode = SharedGenericsMode.CanonicalReferenceTypes; + + var targetDetails = new TargetDetails(_targetArchitecture, _targetOS, TargetAbi.CoreRT, SimdVectorLength.None); + CompilerTypeSystemContext typeSystemContext = new ReadyToRunCompilerContext(targetDetails, genericsMode); + + // + // TODO: To support our pre-compiled test tree, allow input files that aren't managed assemblies since + // some tests contain a mixture of both managed and native binaries. + // + // See: https://github.com/dotnet/corert/issues/2785 + // + // When we undo this this hack, replace this foreach with + // typeSystemContext.InputFilePaths = _inputFilePaths; + // + Dictionary inputFilePaths = new Dictionary(); + foreach (var inputFile in _inputFilePaths) + { + try + { + var module = typeSystemContext.GetModuleFromPath(inputFile.Value); + inputFilePaths.Add(inputFile.Key, inputFile.Value); + } + catch (TypeSystemException.BadImageFormatException) + { + // Keep calm and carry on. + } + } - // Single method mode? - MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(typeSystemContext); + typeSystemContext.InputFilePaths = inputFilePaths; + typeSystemContext.ReferenceFilePaths = _referenceFilePaths; - var logger = new Logger(Console.Out, _isVerbose); + typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(_systemModuleName)); - List referenceableModules = new List(); - foreach (var inputFile in inputFilePaths) - { - try - { - referenceableModules.Add(typeSystemContext.GetModuleFromPath(inputFile.Value)); - } - catch { } // Ignore non-managed pe files - } + if (typeSystemContext.InputFilePaths.Count == 0) + throw new CommandLineException("No input files specified"); - foreach (var referenceFile in _referenceFilePaths.Values) - { - try - { - referenceableModules.Add(typeSystemContext.GetModuleFromPath(referenceFile)); - } - catch { } // Ignore non-managed pe files - } + // + // Initialize compilation group and compilation roots + // - ProfileDataManager profileDataManager = new ProfileDataManager(logger, referenceableModules); + // Single method mode? + MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(typeSystemContext); - CompilationModuleGroup compilationGroup; - List compilationRoots = new List(); - if (singleMethod != null) - { - // Compiling just a single method - compilationGroup = new SingleMethodCompilationModuleGroup(singleMethod); - compilationRoots.Add(new SingleMethodRootProvider(singleMethod)); - } - else - { - // Either single file, or multifile library, or multifile consumption. - EcmaModule entrypointModule = null; - foreach (var inputFile in typeSystemContext.InputFilePaths) - { - EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value); + var logger = new Logger(Console.Out, _isVerbose); - if (module.PEReader.PEHeaders.IsExe) + List referenceableModules = new List(); + foreach (var inputFile in inputFilePaths) { - if (entrypointModule != null) - throw new Exception("Multiple EXE modules"); - entrypointModule = module; + try + { + referenceableModules.Add(typeSystemContext.GetModuleFromPath(inputFile.Value)); + } + catch { } // Ignore non-managed pe files } - } - List inputModules = new List(); + foreach (var referenceFile in _referenceFilePaths.Values) + { + try + { + referenceableModules.Add(typeSystemContext.GetModuleFromPath(referenceFile)); + } + catch { } // Ignore non-managed pe files + } - foreach (var inputFile in typeSystemContext.InputFilePaths) - { - EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value); - compilationRoots.Add(new ReadyToRunRootProvider(module, profileDataManager)); - inputModules.Add(module); + ProfileDataManager profileDataManager = new ProfileDataManager(logger, referenceableModules); - if (!_isInputVersionBubble) + CompilationModuleGroup compilationGroup; + List compilationRoots = new List(); + if (singleMethod != null) { - break; + // Compiling just a single method + compilationGroup = new SingleMethodCompilationModuleGroup(singleMethod); + compilationRoots.Add(new SingleMethodRootProvider(singleMethod)); } - } + else + { + // Either single file, or multifile library, or multifile consumption. + EcmaModule entrypointModule = null; + foreach (var inputFile in typeSystemContext.InputFilePaths) + { + EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value); + + if (module.PEReader.PEHeaders.IsExe) + { + if (entrypointModule != null) + throw new Exception("Multiple EXE modules"); + entrypointModule = module; + } + } + List inputModules = new List(); - List versionBubbleModules = new List(); - if (_isInputVersionBubble) - { - // In large version bubble mode add reference paths to the compilation group - foreach (string referenceFile in _referenceFilePaths.Values) - { - try + foreach (var inputFile in typeSystemContext.InputFilePaths) { - // Currently SimpleTest.targets has no easy way to filter out non-managed assemblies - // from the reference list. - EcmaModule module = typeSystemContext.GetModuleFromPath(referenceFile); - versionBubbleModules.Add(module); + EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value); + compilationRoots.Add(new ReadyToRunRootProvider(module, profileDataManager)); + inputModules.Add(module); + + if (!_isInputVersionBubble) + { + break; + } } - catch (TypeSystemException.BadImageFormatException ex) + + + List versionBubbleModules = new List(); + if (_isInputVersionBubble) { - Console.WriteLine("Warning: cannot open reference assembly '{0}': {1}", referenceFile, ex.Message); + // In large version bubble mode add reference paths to the compilation group + foreach (string referenceFile in _referenceFilePaths.Values) + { + try + { + // Currently SimpleTest.targets has no easy way to filter out non-managed assemblies + // from the reference list. + EcmaModule module = typeSystemContext.GetModuleFromPath(referenceFile); + versionBubbleModules.Add(module); + } + catch (TypeSystemException.BadImageFormatException ex) + { + Console.WriteLine("Warning: cannot open reference assembly '{0}': {1}", referenceFile, ex.Message); + } + } } - } - } - compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup( - typeSystemContext, inputModules, versionBubbleModules, _includeGenericsFromVersionBubble, - _partial ? profileDataManager : null); - } + compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup( + typeSystemContext, inputModules, versionBubbleModules, _includeGenericsFromVersionBubble, + _partial ? profileDataManager : null); + } - // - // Compile - // + // + // Compile + // - string inputFilePath = ""; - foreach (var input in typeSystemContext.InputFilePaths) - { - inputFilePath = input.Value; - break; - } - CompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(typeSystemContext, compilationGroup, inputFilePath, - ibcTuning: _tuning, - resilient: _resilient); + string inputFilePath = ""; + foreach (var input in typeSystemContext.InputFilePaths) + { + inputFilePath = input.Value; + break; + } + CompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(typeSystemContext, compilationGroup, inputFilePath, + ibcTuning: _tuning, + resilient: _resilient); - string compilationUnitPrefix = ""; - builder.UseCompilationUnitPrefix(compilationUnitPrefix); + string compilationUnitPrefix = ""; + builder.UseCompilationUnitPrefix(compilationUnitPrefix); - ILProvider ilProvider = new ReadyToRunILProvider(); + ILProvider ilProvider = new ReadyToRunILProvider(); - DependencyTrackingLevel trackingLevel = _dgmlLogFileName == null ? - DependencyTrackingLevel.None : (_generateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First); + DependencyTrackingLevel trackingLevel = _dgmlLogFileName == null ? + DependencyTrackingLevel.None : (_generateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First); - builder - .UseILProvider(ilProvider) - .UseBackendOptions(_codegenOptions) - .UseLogger(logger) - .UseDependencyTracking(trackingLevel) - .UseCompilationRoots(compilationRoots) - .UseOptimizationMode(_optimizationMode); + builder + .UseILProvider(ilProvider) + .UseBackendOptions(_codegenOptions) + .UseLogger(logger) + .UseDependencyTracking(trackingLevel) + .UseCompilationRoots(compilationRoots) + .UseOptimizationMode(_optimizationMode); - ICompilation compilation = builder.ToCompilation(); + compilation = builder.ToCompilation(); - PerfEventSource.Log.LoadingStop(); - compilation.Compile(_outputFilePath); - PerfEventSource.Log.CompilationStop(); + } + compilation.Compile(_outputFilePath); + } return 0; } -- 2.7.4