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(); + } + +}