Skip to content

Commit ef98b0c

Browse files
authored
Merge pull request #4324 from MDoerner/BetterParseTimeLogging
Fix massive parser slowdown
2 parents 8cc20e1 + d0c1a53 commit ef98b0c

File tree

11 files changed

+283
-5
lines changed

11 files changed

+283
-5
lines changed

Rubberduck.Main/Root/RubberduckIoCInstaller.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,9 @@ private void RegisterParsingEngine(IWindsorContainer container)
842842
container.Register(Component.For<IStringParser>()
843843
.ImplementedBy<TokenStreamParserStringParserAdapterWithPreprocessing>()
844844
.LifestyleSingleton());
845+
container.Register(Component.For<ITokenStreamParser>()
846+
.ImplementedBy<VBATokenStreamParser>()
847+
.LifestyleSingleton());
845848
container.Register(Component.For<IModuleParser>()
846849
.ImplementedBy<ModuleParser>()
847850
.DependsOn(Dependency.OnComponent("codePaneSourceCodeProvider", typeof(CodePaneSourceCodeHandler)),
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Diagnostics;
2+
using NLog;
3+
4+
namespace Rubberduck.Parsing.Common
5+
{
6+
public class ParsingStageTimer
7+
{
8+
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
9+
10+
public static ParsingStageTimer StartNew()
11+
{
12+
var timer = new ParsingStageTimer();
13+
timer.Start();
14+
return timer;
15+
}
16+
17+
private readonly Stopwatch _stopwatch = new Stopwatch();
18+
19+
public void Start() => _stopwatch.Start();
20+
public void Stop() => _stopwatch.Stop();
21+
public void Restart() => _stopwatch.Restart();
22+
23+
public void Log(string message)
24+
{
25+
Logger.Debug(message, _stopwatch.ElapsedMilliseconds);
26+
}
27+
}
28+
}

Rubberduck.Parsing/Rubberduck.Parsing.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
<Compile Include="Binding\Bindings\ParenthesizedDefaultBinding.cs" />
145145
<Compile Include="Binding\TypeBindingContext.cs" />
146146
<Compile Include="Binding\ExpressionClassification.cs" />
147+
<Compile Include="Common\ParsingStageTimer.cs" />
147148
<Compile Include="ComReflection\ComLibraryProvider.cs" />
148149
<Compile Include="ComReflection\IComLibraryProvider.cs" />
149150
<Compile Include="ComReflection\ISerializableProjectBuilder.cs" />

Rubberduck.Parsing/VBA/ComReferenceLoading/COMReferenceSynchronizerBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Runtime.InteropServices;
77
using System.Threading;
88
using NLog;
9+
using Rubberduck.Parsing.Common;
910
using Rubberduck.Parsing.ComReflection;
1011
using Rubberduck.Parsing.VBA.Extensions;
1112
using Rubberduck.VBEditor;
@@ -68,6 +69,8 @@ protected COMReferenceSynchronizerBase(RubberduckParserState state, IParserState
6869

6970
public void SyncComReferences(CancellationToken token)
7071
{
72+
var parsingStageTimer = ParsingStageTimer.StartNew();
73+
7174
LastSyncOfCOMReferencesLoadedReferences = false;
7275
_unloadedCOMReferences.Clear();
7376
RefreshReferencedByProjectId();
@@ -94,6 +97,9 @@ public void SyncComReferences(CancellationToken token)
9497
{
9598
UnloadComReference(reference);
9699
}
100+
101+
parsingStageTimer.Stop();
102+
parsingStageTimer.Log("Loaded and unloaded referenced libraries in {0}ms.");
97103
}
98104

99105
private Dictionary<string, List<ReferenceInfo>> ReferencedByProjectId()

Rubberduck.Parsing/VBA/DeclarationResolving/DeclarationResolveRunner.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Linq;
45
using System.Threading;
56
using System.Threading.Tasks;
7+
using Rubberduck.Parsing.Common;
68
using Rubberduck.Parsing.VBA.ComReferenceLoading;
79
using Rubberduck.VBEditor;
810

@@ -29,6 +31,8 @@ public override void ResolveDeclarations(IReadOnlyCollection<QualifiedModuleName
2931
return;
3032
}
3133

34+
var parsingStageTimer = ParsingStageTimer.StartNew();
35+
3236
_projectDeclarations.Clear();
3337
token.ThrowIfCancellationRequested();
3438

@@ -56,6 +60,9 @@ public override void ResolveDeclarations(IReadOnlyCollection<QualifiedModuleName
5660
_parserStateManager.SetStatusAndFireStateChanged(this, ParserState.ResolverError, token);
5761
throw;
5862
}
63+
64+
parsingStageTimer.Stop();
65+
parsingStageTimer.Log("Resolved user declaration in {0}ms.");
5966
}
6067
}
6168
}

Rubberduck.Parsing/VBA/DeclarationResolving/DeclarationResolveRunnerBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Rubberduck.Parsing.VBA.DeclarationResolving
1515
public abstract class DeclarationResolveRunnerBase : IDeclarationResolveRunner
1616
{
1717
protected readonly ConcurrentDictionary<string, Declaration> _projectDeclarations = new ConcurrentDictionary<string, Declaration>();
18-
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
18+
protected static readonly Logger Logger = LogManager.GetCurrentClassLogger();
1919

2020
protected readonly RubberduckParserState _state;
2121
protected readonly IParserStateManager _parserStateManager;

Rubberduck.Parsing/VBA/Parsing/ParseRunner.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Threading;
55
using System.Threading.Tasks;
6+
using Rubberduck.Parsing.Common;
67
using Rubberduck.VBEditor;
78

89
namespace Rubberduck.Parsing.VBA.Parsing
@@ -29,6 +30,8 @@ public override void ParseModules(IReadOnlyCollection<QualifiedModuleName> modul
2930

3031
token.ThrowIfCancellationRequested();
3132

33+
var parsingStageTimer = ParsingStageTimer.StartNew();
34+
3235
var options = new ParallelOptions();
3336
options.CancellationToken = token;
3437
options.MaxDegreeOfParallelism = _maxDegreeOfParserParallelism;
@@ -49,6 +52,9 @@ public override void ParseModules(IReadOnlyCollection<QualifiedModuleName> modul
4952
StateManager.SetStatusAndFireStateChanged(this, ParserState.Error, token);
5053
throw;
5154
}
55+
56+
parsingStageTimer.Stop();
57+
parsingStageTimer.Log("Parsed user modules in {0}ms.");
5258
}
5359
}
5460
}

Rubberduck.Parsing/VBA/Parsing/TokenStreamParserBase.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,25 @@ private IParseTree ParseWithFallBack(string moduleName, CommonTokenStream tokenS
4444
{
4545
try
4646
{
47-
return ParseLl(moduleName, tokenStream, codeKind);
47+
return ParseSll(moduleName, tokenStream, codeKind);
4848
}
4949
catch (ParsePassSyntaxErrorException syntaxErrorException)
5050
{
5151
var message = $"SLL mode failed while parsing the {codeKind} version of module {moduleName} at symbol {syntaxErrorException.OffendingSymbol.Text} at L{syntaxErrorException.LineNumber}C{syntaxErrorException.Position}. Retrying using LL.";
5252
LogAndReset(tokenStream, message, syntaxErrorException);
53-
return ParseSll(moduleName, tokenStream, codeKind);
53+
return ParseLl(moduleName, tokenStream, codeKind);
5454
}
5555
catch (Exception exception)
5656
{
5757
var message = $"SLL mode failed while parsing the {codeKind} version of module {moduleName}. Retrying using LL.";
5858
LogAndReset(tokenStream, message, exception);
59-
return ParseSll(moduleName, tokenStream, codeKind);
59+
return ParseLl(moduleName, tokenStream, codeKind);
6060
}
6161
}
6262

63-
private void LogAndReset(CommonTokenStream tokenStream, string logWarnMessage, Exception exception)
63+
//This method is virtual only because a CommonTokenStream cannot be mocked in tests
64+
//and there is no interface for it or a base class that has the Reset member.
65+
protected virtual void LogAndReset(CommonTokenStream tokenStream, string logWarnMessage, Exception exception)
6466
{
6567
Logger.Warn(logWarnMessage);
6668
Logger.Debug(exception);

Rubberduck.Parsing/VBA/ReferenceManagement/ReferenceResolveRunnerBase.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading;
66
using Antlr4.Runtime.Tree;
77
using NLog;
8+
using Rubberduck.Parsing.Common;
89
using Rubberduck.Parsing.Symbols;
910
using Rubberduck.Parsing.VBA.Extensions;
1011
using Rubberduck.Parsing.VBA.Parsing;
@@ -75,21 +76,40 @@ public void ResolveReferences(IReadOnlyCollection<QualifiedModuleName> toResolve
7576
PerformPreResolveCleanup(_toResolve.AsReadOnly(), token);
7677
token.ThrowIfCancellationRequested();
7778

79+
var parsingStageTimer = ParsingStageTimer.StartNew();
80+
7881
ExecuteCompilationPasses(_toResolve.AsReadOnly(), token);
7982
token.ThrowIfCancellationRequested();
8083

84+
parsingStageTimer.Stop();
85+
parsingStageTimer.Log("Executed compilation passes in {0}ms.");
86+
parsingStageTimer.Restart();
87+
8188
AddSupertypesForDocumentModules(_toResolve.AsReadOnly(), _state);
8289
token.ThrowIfCancellationRequested();
8390

91+
parsingStageTimer.Stop();
92+
parsingStageTimer.Log("Added supertypes for document modules in {0}ms.");
93+
8494
var parseTreesToResolve = _state.ParseTrees.Where(kvp => _toResolve.Contains(kvp.Key)).ToList();
8595
token.ThrowIfCancellationRequested();
8696

97+
parsingStageTimer.Restart();
98+
8799
ResolveReferences(parseTreesToResolve, token);
88100
token.ThrowIfCancellationRequested();
89101

102+
parsingStageTimer.Stop();
103+
parsingStageTimer.Log("Resolved references in {0}ms.");
104+
parsingStageTimer.Restart();
105+
90106
AddModuleToModuleReferences(_state.DeclarationFinder, token);
91107
token.ThrowIfCancellationRequested();
92108

109+
parsingStageTimer.Stop();
110+
parsingStageTimer.Log("Determined module to module references in {0}ms.");
111+
parsingStageTimer.Restart();
112+
93113
AddNewUndeclaredVariablesToDeclarations();
94114
AddNewUnresolvedMemberDeclarations();
95115

0 commit comments

Comments
 (0)