diff options
author | Jan Kotas <jkotas@microsoft.com> | 2015-12-27 11:23:48 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2015-12-27 11:24:57 +0300 |
commit | e264fcb9c69a6671c4d455b1fa12675b97d9a3e1 (patch) | |
tree | 0516086d3e27613f8803e24ab3c3133fa465dc96 /src/ILCompiler | |
parent | bf8670422b294df760e54639c68a40b738ab4eda (diff) |
Improve performance of MethodIL provider
- Explicitly use memory mapped files for Ecma metadata reader. System.Reflection.Metadata has
heuristic that tries to save virtual address space. This heuristic does not work well for us
since it can make IL access very slow (call to OS for each method IL query). Explicitly using
memory mapped files gives us reliably the desired performance characteristics.
- Implement caching in MethodILProvider.
- Refactor command line parsing - move TypeSystemContext instantiation from the driver .exe into the compiler
These performance improvements bring hello world native compilation from multiple seconds back to sub second range (with release build of RyuJIT and NGened compiler).
Diffstat (limited to 'src/ILCompiler')
-rw-r--r-- | src/ILCompiler/desktop/project.json | 1 | ||||
-rw-r--r-- | src/ILCompiler/src/Program.cs | 111 | ||||
-rw-r--r-- | src/ILCompiler/src/project.json | 3 |
3 files changed, 42 insertions, 73 deletions
diff --git a/src/ILCompiler/desktop/project.json b/src/ILCompiler/desktop/project.json index f12cfd123..b9a3083ec 100644 --- a/src/ILCompiler/desktop/project.json +++ b/src/ILCompiler/desktop/project.json @@ -6,6 +6,7 @@ "System.Diagnostics.Debug": "4.0.10", "System.IO": "4.0.10", "System.IO.FileSystem": "4.0.0", + "System.IO.MemoryMappedFiles": "4.0.0-beta-23419", "System.Collections": "4.0.10", "System.Text.Encoding": "4.0.10", "System.Runtime.InteropServices": "4.0.20", diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs index f9c6a206a..d91e44bfc 100644 --- a/src/ILCompiler/src/Program.cs +++ b/src/ILCompiler/src/Program.cs @@ -5,11 +5,9 @@ using System; using System.IO; using System.Collections.Generic; using System.Reflection; -using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; using Internal.CommandLine; @@ -17,18 +15,12 @@ namespace ILCompiler { internal class Program { - private bool _help; - - private string _outputPath; + private CompilationOptions _options; private Dictionary<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - private string _systemModuleName = "System.Private.CoreLib"; - - private CompilationOptions _options; - - private CompilerTypeSystemContext _compilerTypeSystemContext; + private bool _help; private Program() { @@ -40,11 +32,38 @@ namespace ILCompiler Console.WriteLine(); Console.WriteLine("-help Display this usage message (Short form: -?)"); Console.WriteLine("-out Specify output file name"); - Console.WriteLine("-dgmllog Dump dgml log of dependency graph to specified file"); - Console.WriteLine("-fulllog Generate full dependency log graph"); Console.WriteLine("-reference Reference metadata from the specified assembly (Short form: -r)"); } + private void InitializeDefaultOptions() + { + _options = new CompilationOptions(); + + _options.InputFilePaths = _inputFilePaths; + _options.ReferenceFilePaths = _referenceFilePaths; + + _options.SystemModuleName = "System.Private.CoreLib"; + +#if FXCORE + // We could offer this as a command line option, but then we also need to + // load a different RyuJIT, so this is a future nice to have... + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + _options.TargetOS = TargetOS.Windows; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + _options.TargetOS = TargetOS.Linux; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + _options.TargetOS = TargetOS.OSX; + else + throw new NotImplementedException(); +#else + _options.TargetOS = TargetOS.Windows; +#endif + + _options.TargetArchitecture = TargetArchitecture.X64; + } + + // TODO: Use System.CommandLine for command line parsing + // https://github.com/dotnet/corert/issues/568 private void ParseCommandLine(string[] args) { var parser = new CommandLineParser(args); @@ -66,7 +85,7 @@ namespace ILCompiler case "o": case "out": - _outputPath = parser.GetStringValue(); + _options.OutputFilePath = parser.GetStringValue(); break; case "dgmllog": @@ -95,7 +114,7 @@ namespace ILCompiler break; case "systemmodule": - _systemModuleName = parser.GetStringValue(); + _options.SystemModuleName = parser.GetStringValue(); break; default: @@ -104,48 +123,18 @@ namespace ILCompiler } } - private EcmaModule GetEntryPointModule() - { - EcmaModule mainModule = null; - foreach (var inputFile in _inputFilePaths) - { - EcmaModule module = _compilerTypeSystemContext.GetModuleFromPath(inputFile.Value); - if (module.PEReader.PEHeaders.IsExe) - { - if (mainModule != null) - throw new CommandLineException("Multiple entrypoint modules"); - mainModule = module; - } - } - return mainModule; - } - private void SingleFileCompilation() { - List<MethodDesc> rootMethods = new List<MethodDesc>(); - MethodDesc entryPointMethod = null; - - EcmaModule entryPointModule = GetEntryPointModule(); - if (entryPointModule != null) - { - int entryPointToken = entryPointModule.PEReader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress; - entryPointMethod = entryPointModule.GetMethod(MetadataTokens.EntityHandle(entryPointToken)); - } - - Compilation compilation = new Compilation(_compilerTypeSystemContext, _options); + Compilation compilation = new Compilation(_options); compilation.Log = _options.Verbose ? Console.Out : TextWriter.Null; - compilation.OutputPath = _outputPath; - if (_options.IsCppCodeGen) - { - // Don't set Out when using object writer which is handled by LLVM. - compilation.Out = new StreamWriter(File.Create(_outputPath)); - } - compilation.CompileSingleFile(entryPointMethod); + compilation.CompileSingleFile(); } private int Run(string[] args) { + InitializeDefaultOptions(); + ParseCommandLine(args); if (_help) @@ -154,34 +143,12 @@ namespace ILCompiler return 1; } - if (_inputFilePaths.Count == 0) + if (_options.InputFilePaths.Count == 0) throw new CommandLineException("No input files specified"); - if (_outputPath == null) + if (_options.OutputFilePath == null) throw new CommandLineException("Output filename must be specified (/out <file>)"); - TargetOS targetOS; -#if FXCORE - // We could offer this as a command line option, but then we also need to - // load a different RyuJIT, so this is a future nice to have... - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - targetOS = TargetOS.Windows; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - targetOS = TargetOS.Linux; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - targetOS = TargetOS.OSX; - else - throw new NotImplementedException(); -#else - targetOS = TargetOS.Windows; -#endif - - _compilerTypeSystemContext = new CompilerTypeSystemContext(new TargetDetails(TargetArchitecture.X64, targetOS)); - _compilerTypeSystemContext.InputFilePaths = _inputFilePaths; - _compilerTypeSystemContext.ReferenceFilePaths = _referenceFilePaths; - - _compilerTypeSystemContext.SetSystemModule(_compilerTypeSystemContext.GetModuleForSimpleName(_systemModuleName)); - // For now, we can do single file compilation only // TODO: Multifile SingleFileCompilation(); diff --git a/src/ILCompiler/src/project.json b/src/ILCompiler/src/project.json index a194def8c..14b5ead41 100644 --- a/src/ILCompiler/src/project.json +++ b/src/ILCompiler/src/project.json @@ -6,6 +6,7 @@ "System.Diagnostics.Debug": "4.0.10", "System.IO": "4.0.10", "System.IO.FileSystem": "4.0.0", + "System.IO.MemoryMappedFiles": "4.0.0-beta-23419", "System.Collections": "4.0.10", "System.Text.Encoding": "4.0.10", "System.Runtime.InteropServices": "4.0.20", @@ -20,7 +21,7 @@ "System.Reflection.Metadata": "1.0.22", "System.Runtime.InteropServices.RuntimeInformation": "4.0.0-beta-23409", "Microsoft.DotNet.RyuJit": "1.0.2-prerelease-00002", - "Microsoft.DotNet.ObjectWriter": "1.0.3-prerelease-00001", + "Microsoft.DotNet.ObjectWriter": "1.0.3-prerelease-00001" }, "frameworks": { "dotnet": { |