-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add generation of structured object file dumps (#73913)
The compiler can currently emit an XML file with everything that was emitted into the output object file. This works and it's easily human readable. But the captured information is not very structured and cannot be used to generate aggregate information like 'this assembly contributed X bytes". This adds another dumper format similar to what we do for MIBC and others: it's ECMA-335 based and uses ldtoken/ldstr/ldc to encode the data. This can be used to build better tools. There's currently none but ILDASM, but it would be good to have it for 7.0. Good hackathon project.
- Loading branch information
1 parent
06339dc
commit 00f34fb
Showing
7 changed files
with
253 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MstatObjectDumper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.IO; | ||
using System.Reflection.Metadata; | ||
using System.Reflection.Metadata.Ecma335; | ||
|
||
using Internal.Text; | ||
using Internal.TypeSystem; | ||
|
||
using ILCompiler.DependencyAnalysis; | ||
|
||
using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; | ||
using AssemblyName = System.Reflection.AssemblyName; | ||
using System.Collections.Generic; | ||
using static ILCompiler.DependencyAnalysis.ObjectNode; | ||
|
||
namespace ILCompiler | ||
{ | ||
public class MstatObjectDumper : ObjectDumper | ||
{ | ||
private const int VersionMajor = 1; | ||
private const int VersionMinor = 0; | ||
|
||
private readonly string _fileName; | ||
private readonly TypeSystemMetadataEmitter _emitter; | ||
|
||
private readonly InstructionEncoder _types = new InstructionEncoder(new BlobBuilder()); | ||
|
||
private Dictionary<MethodDesc, (string MangledName, int Size, int GcInfoSize)> _methods = new(); | ||
private Dictionary<MethodDesc, int> _methodEhInfo = new(); | ||
private Dictionary<string, int> _blobs = new(); | ||
|
||
private Utf8StringBuilder _utf8StringBuilder = new Utf8StringBuilder(); | ||
|
||
public MstatObjectDumper(string fileName, TypeSystemContext context) | ||
{ | ||
_fileName = fileName; | ||
var asmName = new AssemblyName(Path.GetFileName(fileName)); | ||
asmName.Version = new Version(VersionMajor, VersionMinor); | ||
_emitter = new TypeSystemMetadataEmitter(asmName, context); | ||
_emitter.AllowUseOfAddGlobalMethod(); | ||
} | ||
|
||
internal override void Begin() | ||
{ | ||
} | ||
|
||
protected override void DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData) | ||
{ | ||
string mangledName = null; | ||
if (node is ISymbolNode symbol) | ||
{ | ||
_utf8StringBuilder.Clear(); | ||
symbol.AppendMangledName(mangler, _utf8StringBuilder); | ||
mangledName = _utf8StringBuilder.ToString(); | ||
} | ||
|
||
switch (node) | ||
{ | ||
case EETypeNode eeType: | ||
SerializeSimpleEntry(_types, eeType.Type, mangledName, objectData); | ||
break; | ||
case IMethodBodyNode methodBody: | ||
var codeInfo = (INodeWithCodeInfo)node; | ||
_methods.Add(methodBody.Method, (mangledName, objectData.Data.Length, codeInfo.GCInfo.Length)); | ||
break; | ||
case MethodExceptionHandlingInfoNode ehInfoNode: | ||
_methodEhInfo.Add(ehInfoNode.Method, objectData.Data.Length); | ||
break; | ||
default: | ||
string nodeName = GetObjectNodeName(node); | ||
if (!_blobs.TryGetValue(nodeName, out int size)) | ||
size = 0; | ||
_blobs[nodeName] = size + objectData.Data.Length; | ||
break; | ||
} | ||
} | ||
|
||
private void SerializeSimpleEntry(InstructionEncoder encoder, TypeSystemEntity entity, string mangledName, ObjectData blob) | ||
{ | ||
encoder.OpCode(ILOpCode.Ldtoken); | ||
encoder.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(entity)); | ||
encoder.LoadString(_emitter.GetUserStringHandle(mangledName)); | ||
encoder.LoadConstantI4(blob.Data.Length); | ||
} | ||
|
||
internal override void End() | ||
{ | ||
var methods = new InstructionEncoder(new BlobBuilder()); | ||
foreach (var m in _methods) | ||
{ | ||
methods.OpCode(ILOpCode.Ldtoken); | ||
methods.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(m.Key)); | ||
methods.LoadString(_emitter.GetUserStringHandle(m.Value.MangledName)); | ||
methods.LoadConstantI4(m.Value.Size); | ||
methods.LoadConstantI4(m.Value.GcInfoSize); | ||
methods.LoadConstantI4(_methodEhInfo.GetValueOrDefault(m.Key)); | ||
} | ||
|
||
var blobs = new InstructionEncoder(new BlobBuilder()); | ||
foreach (var b in _blobs) | ||
{ | ||
blobs.LoadString(_emitter.GetUserStringHandle(b.Key)); | ||
blobs.LoadConstantI4(b.Value); | ||
} | ||
|
||
_emitter.AddGlobalMethod("Methods", methods, 0); | ||
_emitter.AddGlobalMethod("Types", _types, 0); | ||
_emitter.AddGlobalMethod("Blobs", blobs, 0); | ||
|
||
using (var fs = File.OpenWrite(_fileName)) | ||
_emitter.SerializeToStream(fs); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/XmlObjectDumper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.IO; | ||
using System.Security.Cryptography; | ||
using System.Xml; | ||
|
||
using Internal.Text; | ||
|
||
using ILCompiler.DependencyAnalysis; | ||
|
||
using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; | ||
|
||
namespace ILCompiler | ||
{ | ||
public class XmlObjectDumper : ObjectDumper | ||
{ | ||
private readonly string _fileName; | ||
private SHA256 _sha256; | ||
private XmlWriter _writer; | ||
|
||
public XmlObjectDumper(string fileName) | ||
{ | ||
_fileName = fileName; | ||
} | ||
|
||
internal override void Begin() | ||
{ | ||
var settings = new XmlWriterSettings | ||
{ | ||
CloseOutput = true, | ||
Indent = true, | ||
}; | ||
|
||
_sha256 = SHA256.Create(); | ||
_writer = XmlWriter.Create(File.CreateText(_fileName), settings); | ||
_writer.WriteStartElement("ObjectNodes"); | ||
} | ||
|
||
protected override void DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData) | ||
{ | ||
string name = null; | ||
|
||
_writer.WriteStartElement(GetObjectNodeName(node)); | ||
|
||
var symbolNode = node as ISymbolNode; | ||
if (symbolNode != null) | ||
{ | ||
Utf8StringBuilder sb = new Utf8StringBuilder(); | ||
symbolNode.AppendMangledName(mangler, sb); | ||
name = sb.ToString(); | ||
_writer.WriteAttributeString("Name", name); | ||
} | ||
|
||
_writer.WriteAttributeString("Length", objectData.Data.Length.ToStringInvariant()); | ||
_writer.WriteAttributeString("Hash", HashData(objectData.Data)); | ||
_writer.WriteEndElement(); | ||
|
||
var nodeWithCodeInfo = node as INodeWithCodeInfo; | ||
if (nodeWithCodeInfo != null) | ||
{ | ||
_writer.WriteStartElement("GCInfo"); | ||
_writer.WriteAttributeString("Name", name); | ||
_writer.WriteAttributeString("Length", nodeWithCodeInfo.GCInfo.Length.ToStringInvariant()); | ||
_writer.WriteAttributeString("Hash", HashData(nodeWithCodeInfo.GCInfo)); | ||
_writer.WriteEndElement(); | ||
} | ||
} | ||
|
||
private string HashData(byte[] data) | ||
{ | ||
return BitConverter.ToString(_sha256.ComputeHash(data)).Replace("-", "").ToLower(); | ||
} | ||
|
||
internal override void End() | ||
{ | ||
_writer.WriteEndElement(); | ||
_writer.Dispose(); | ||
_writer = null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.