diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index fc7526041..2810eb948 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -1209,6 +1209,7 @@ namespace ICSharpCode.Decompiler.CSharp
EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentTypeDefinition == typeDef);
+ var watch = System.Diagnostics.Stopwatch.StartNew();
try
{
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
@@ -1361,6 +1362,11 @@ namespace ICSharpCode.Decompiler.CSharp
{
throw new DecompilerException(module, typeDef, innerException);
}
+ finally
+ {
+ watch.Stop();
+ Instrumentation.DecompilerEventSource.Log.DoDecompileTypeDefinition(typeDef.FullName, watch.ElapsedMilliseconds);
+ }
}
enum EnumValueDisplayMode
@@ -1447,43 +1453,52 @@ namespace ICSharpCode.Decompiler.CSharp
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == method);
- var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
- var methodDecl = typeSystemAstBuilder.ConvertEntity(method);
- int lastDot = method.Name.LastIndexOf('.');
- if (method.IsExplicitInterfaceImplementation && lastDot >= 0)
- {
- methodDecl.Name = method.Name.Substring(lastDot + 1);
- }
- FixParameterNames(methodDecl);
- var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
- if (!settings.LocalFunctions && LocalFunctionDecompiler.LocalFunctionNeedsAccessibilityChange(method.ParentModule.PEFile, (MethodDefinitionHandle)method.MetadataToken))
- {
- // if local functions are not active and we're dealing with a local function,
- // reduce the visibility of the method to private,
- // otherwise this leads to compile errors because the display classes have lesser accessibility.
- // Note: removing and then adding the static modifier again is necessary to set the private modifier before all other modifiers.
- methodDecl.Modifiers &= ~(Modifiers.Internal | Modifiers.Static);
- methodDecl.Modifiers |= Modifiers.Private | (method.IsStatic ? Modifiers.Static : 0);
- }
- if (methodDefinition.HasBody())
- {
- DecompileBody(method, methodDecl, decompileRun, decompilationContext);
- }
- else if (!method.IsAbstract && method.DeclaringType.Kind != TypeKind.Interface)
- {
- methodDecl.Modifiers |= Modifiers.Extern;
- }
- if (method.SymbolKind == SymbolKind.Method && !method.IsExplicitInterfaceImplementation && methodDefinition.HasFlag(System.Reflection.MethodAttributes.Virtual) == methodDefinition.HasFlag(System.Reflection.MethodAttributes.NewSlot))
+ var watch = System.Diagnostics.Stopwatch.StartNew();
+ try
{
- SetNewModifier(methodDecl);
+ var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
+ var methodDecl = typeSystemAstBuilder.ConvertEntity(method);
+ int lastDot = method.Name.LastIndexOf('.');
+ if (method.IsExplicitInterfaceImplementation && lastDot >= 0)
+ {
+ methodDecl.Name = method.Name.Substring(lastDot + 1);
+ }
+ FixParameterNames(methodDecl);
+ var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
+ if (!settings.LocalFunctions && LocalFunctionDecompiler.LocalFunctionNeedsAccessibilityChange(method.ParentModule.PEFile, (MethodDefinitionHandle)method.MetadataToken))
+ {
+ // if local functions are not active and we're dealing with a local function,
+ // reduce the visibility of the method to private,
+ // otherwise this leads to compile errors because the display classes have lesser accessibility.
+ // Note: removing and then adding the static modifier again is necessary to set the private modifier before all other modifiers.
+ methodDecl.Modifiers &= ~(Modifiers.Internal | Modifiers.Static);
+ methodDecl.Modifiers |= Modifiers.Private | (method.IsStatic ? Modifiers.Static : 0);
+ }
+ if (methodDefinition.HasBody())
+ {
+ DecompileBody(method, methodDecl, decompileRun, decompilationContext);
+ }
+ else if (!method.IsAbstract && method.DeclaringType.Kind != TypeKind.Interface)
+ {
+ methodDecl.Modifiers |= Modifiers.Extern;
+ }
+ if (method.SymbolKind == SymbolKind.Method && !method.IsExplicitInterfaceImplementation && methodDefinition.HasFlag(System.Reflection.MethodAttributes.Virtual) == methodDefinition.HasFlag(System.Reflection.MethodAttributes.NewSlot))
+ {
+ SetNewModifier(methodDecl);
+ }
+ if (IsCovariantReturnOverride(method))
+ {
+ RemoveAttribute(methodDecl, KnownAttribute.PreserveBaseOverrides);
+ methodDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual);
+ methodDecl.Modifiers |= Modifiers.Override;
+ }
+ return methodDecl;
}
- if (IsCovariantReturnOverride(method))
+ finally
{
- RemoveAttribute(methodDecl, KnownAttribute.PreserveBaseOverrides);
- methodDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual);
- methodDecl.Modifiers |= Modifiers.Override;
+ watch.Stop();
+ Instrumentation.DecompilerEventSource.Log.DoDecompileMethod(method.FullName, watch.ElapsedMilliseconds);
}
- return methodDecl;
}
private bool IsCovariantReturnOverride(IEntity entity)
@@ -1684,6 +1699,7 @@ namespace ICSharpCode.Decompiler.CSharp
EntityDeclaration DoDecompile(IField field, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == field);
+ var watch = System.Diagnostics.Stopwatch.StartNew();
try
{
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
@@ -1746,6 +1762,11 @@ namespace ICSharpCode.Decompiler.CSharp
{
throw new DecompilerException(module, field, innerException);
}
+ finally
+ {
+ watch.Stop();
+ Instrumentation.DecompilerEventSource.Log.DoDecompileField(field.FullName, watch.ElapsedMilliseconds);
+ }
}
internal static bool IsFixedField(IField field, out IType type, out int elementCount)
@@ -1768,6 +1789,7 @@ namespace ICSharpCode.Decompiler.CSharp
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == property);
+ var watch = System.Diagnostics.Stopwatch.StartNew();
try
{
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
@@ -1822,11 +1844,17 @@ namespace ICSharpCode.Decompiler.CSharp
{
throw new DecompilerException(module, property, innerException);
}
+ finally
+ {
+ watch.Stop();
+ Instrumentation.DecompilerEventSource.Log.DoDecompileProperty(property.FullName, watch.ElapsedMilliseconds);
+ }
}
EntityDeclaration DoDecompile(IEvent ev, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == ev);
+ var watch = System.Diagnostics.Stopwatch.StartNew();
try
{
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
@@ -1862,6 +1890,11 @@ namespace ICSharpCode.Decompiler.CSharp
{
throw new DecompilerException(module, ev, innerException);
}
+ finally
+ {
+ watch.Stop();
+ Instrumentation.DecompilerEventSource.Log.DoDecompileEvent(ev.FullName, watch.ElapsedMilliseconds);
+ }
}
#region Sequence Points
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 7ebd56f7c..2c31e5b87 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -100,6 +100,7 @@
+
diff --git a/ICSharpCode.Decompiler/Instrumentation/DecompilerEventSource.cs b/ICSharpCode.Decompiler/Instrumentation/DecompilerEventSource.cs
new file mode 100644
index 000000000..aaacec5f9
--- /dev/null
+++ b/ICSharpCode.Decompiler/Instrumentation/DecompilerEventSource.cs
@@ -0,0 +1,59 @@
+// Copyright (c) 2021 Christoph Wille
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System.Diagnostics.Tracing;
+
+namespace ICSharpCode.Decompiler.Instrumentation
+{
+ [EventSource(Name = "ICSharpCode.Decompiler")]
+ public sealed class DecompilerEventSource : EventSource
+ {
+ [Event(1, Level = EventLevel.Informational)]
+ public void DoDecompileEvent(string eventName, long elapsedMilliseconds)
+ {
+ WriteEvent(1, eventName, elapsedMilliseconds);
+ }
+
+ [Event(2, Level = EventLevel.Informational)]
+ public void DoDecompileProperty(string propertyName, long elapsedMilliseconds)
+ {
+ WriteEvent(2, propertyName, elapsedMilliseconds);
+ }
+
+ [Event(3, Level = EventLevel.Informational)]
+ public void DoDecompileField(string fieldName, long elapsedMilliseconds)
+ {
+ WriteEvent(3, fieldName, elapsedMilliseconds);
+ }
+
+ [Event(4, Level = EventLevel.Informational)]
+ public void DoDecompileTypeDefinition(string typeDefName, long elapsedMilliseconds)
+ {
+ WriteEvent(4, typeDefName, elapsedMilliseconds);
+ }
+
+ [Event(5, Level = EventLevel.Informational)]
+ public void DoDecompileMethod(string methodName, long elapsedMilliseconds)
+ {
+ WriteEvent(5, methodName, elapsedMilliseconds);
+ }
+
+ public static DecompilerEventSource Log = new DecompilerEventSource();
+ }
+
+}