Change PerfEventSource to be able to use 'using'. (dotnet/coreclr#26981)
authorAnubhav Srivastava <SrivastavaAnubhav@users.noreply.github.com>
Wed, 2 Oct 2019 21:04:51 +0000 (14:04 -0700)
committerFadi Hanna <fadim@microsoft.com>
Wed, 2 Oct 2019 21:04:51 +0000 (14:04 -0700)
* Change and reorganize PerfEventSource to be able to use using.

Commit migrated from https://github.com/dotnet/coreclr/commit/4e680b3d82effacd72d8394eee9cf01b501b9207

src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs
src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs
src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs
src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/PerfEventSource.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
src/coreclr/src/tools/crossgen2/crossgen2/Program.cs

index 3a9eed3..f2c705b 100644 (file)
@@ -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
index 94568ae..b952714 100644 (file)
@@ -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");
index f51f150..18187a1 100644 (file)
@@ -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<DependencyContextType> 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<DependencyContextType> 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<DependencyContextType> node, string reason, DependencyNodeCore<DependencyContextType> reason1, DependencyNodeCore<DependencyContextType> reason2)
index dbbb0c8..604855d 100644 (file)
@@ -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;
 
 /// <summary>
-/// Performance events releated to the dependency graph.
+/// Performance events specific to the dependency graph.
 /// </summary>
 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();
     }
+
 }
index 238cce4..fa9ca6c 100644 (file)
@@ -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;
 
 /// <summary>
@@ -9,30 +10,97 @@ using System.Diagnostics.Tracing;
 /// </summary>
 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); }
     }
 }
index 0994170..eb5e6b3 100644 (file)
@@ -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<DependencyNodeCore<NodeFactory>> obj)
         {
-            foreach (DependencyNodeCore<NodeFactory> 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<NodeFactory> 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");
+                    }
                 }
             }
         }
index 8648151..0cbdd5c 100644 (file)
@@ -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<string, string> inputFilePaths = new Dictionary<string, string>();
-            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<string, string> inputFilePaths = new Dictionary<string, string>();
+                    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<ModuleDesc> referenceableModules = new List<ModuleDesc>();
-            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<ICompilationRootProvider> compilationRoots = new List<ICompilationRootProvider>();
-            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<ModuleDesc> referenceableModules = new List<ModuleDesc>();
+                    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<EcmaModule> inputModules = new List<EcmaModule>();
+                    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<ICompilationRootProvider> compilationRoots = new List<ICompilationRootProvider>();
+                    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<EcmaModule> inputModules = new List<EcmaModule>();
 
-                List<ModuleDesc> versionBubbleModules = new List<ModuleDesc>();
-                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<ModuleDesc> versionBubbleModules = new List<ModuleDesc>();
+                        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;
         }