Skip to content

Commit d3062d1

Browse files
committed
Support testing analyzer edit performance
1 parent 35cd929 commit d3062d1

2 files changed

Lines changed: 108 additions & 0 deletions

File tree

StyleCop.Analyzers/StyleCopTester/Program.cs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,51 @@ private static async Task MainAsync(string[] args, CancellationToken cancellatio
124124

125125
Console.WriteLine($"Found {allDiagnostics.Length} diagnostics in {stopwatch.ElapsedMilliseconds}ms");
126126

127+
bool testDocuments = args.Contains("/editperf");
128+
if (testDocuments)
129+
{
130+
var projectPerformance = new Dictionary<ProjectId, double>();
131+
var documentPerformance = new Dictionary<DocumentId, DocumentAnalyzerPerformance>();
132+
foreach (var projectId in solution.ProjectIds)
133+
{
134+
Project project = solution.GetProject(projectId);
135+
if (project.Language != LanguageNames.CSharp)
136+
{
137+
continue;
138+
}
139+
140+
foreach (var documentId in project.DocumentIds)
141+
{
142+
var currentDocumentPerformance = await TestDocumentPerformanceAsync(analyzers, project, documentId, force, cancellationToken).ConfigureAwait(false);
143+
Console.WriteLine($"{documentId}: {currentDocumentPerformance.EditsPerSecond:0.00}");
144+
documentPerformance.Add(documentId, currentDocumentPerformance);
145+
}
146+
147+
double sumOfDocumentAverages = 0;
148+
foreach (var documentId in project.DocumentIds)
149+
{
150+
sumOfDocumentAverages += documentPerformance[documentId].EditsPerSecond;
151+
}
152+
153+
if (sumOfDocumentAverages != 0)
154+
{
155+
projectPerformance[project.Id] = sumOfDocumentAverages / project.DocumentIds.Count;
156+
}
157+
}
158+
159+
foreach (var projectId in solution.ProjectIds)
160+
{
161+
double averageEditsInProject;
162+
if (!projectPerformance.TryGetValue(projectId, out averageEditsInProject))
163+
{
164+
continue;
165+
}
166+
167+
Project project = solution.GetProject(projectId);
168+
Console.WriteLine($"{project.Name} ({project.DocumentIds.Count} documents): {averageEditsInProject:0.00} edits per second");
169+
}
170+
}
171+
127172
foreach (var group in allDiagnostics.GroupBy(i => i.Id).OrderBy(i => i.Key, StringComparer.OrdinalIgnoreCase))
128173
{
129174
Console.WriteLine($" {group.Key}: {group.Count()} instances");
@@ -157,6 +202,45 @@ private static async Task MainAsync(string[] args, CancellationToken cancellatio
157202
}
158203
}
159204

205+
private static async Task<DocumentAnalyzerPerformance> TestDocumentPerformanceAsync(ImmutableArray<DiagnosticAnalyzer> analyzers, Project project, DocumentId documentId, bool force, CancellationToken cancellationToken)
206+
{
207+
var supportedDiagnosticsSpecificOptions = new Dictionary<string, ReportDiagnostic>();
208+
if (force)
209+
{
210+
foreach (var analyzer in analyzers)
211+
{
212+
foreach (var diagnostic in analyzer.SupportedDiagnostics)
213+
{
214+
// make sure the analyzers we are testing are enabled
215+
supportedDiagnosticsSpecificOptions[diagnostic.Id] = ReportDiagnostic.Default;
216+
}
217+
}
218+
}
219+
220+
// Report exceptions during the analysis process as errors
221+
supportedDiagnosticsSpecificOptions.Add("AD0001", ReportDiagnostic.Error);
222+
223+
// update the project compilation options
224+
var modifiedSpecificDiagnosticOptions = supportedDiagnosticsSpecificOptions.ToImmutableDictionary().SetItems(project.CompilationOptions.SpecificDiagnosticOptions);
225+
var modifiedCompilationOptions = project.CompilationOptions.WithSpecificDiagnosticOptions(modifiedSpecificDiagnosticOptions);
226+
227+
var stopwatch = Stopwatch.StartNew();
228+
const int iterations = 10;
229+
for (int i = 0; i < iterations; i++)
230+
{
231+
var processedProject = project.WithCompilationOptions(modifiedCompilationOptions);
232+
233+
Compilation compilation = await processedProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
234+
CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, new CompilationWithAnalyzersOptions(new AnalyzerOptions(ImmutableArray.Create<AdditionalText>()), null, true, false));
235+
236+
SyntaxTree tree = await project.GetDocument(documentId).GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
237+
await compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(tree, cancellationToken).ConfigureAwait(false);
238+
await compilationWithAnalyzers.GetAnalyzerSemanticDiagnosticsAsync(compilation.GetSemanticModel(tree), null, cancellationToken).ConfigureAwait(false);
239+
}
240+
241+
return new DocumentAnalyzerPerformance(iterations / stopwatch.Elapsed.TotalSeconds);
242+
}
243+
160244
private static void WriteDiagnosticResults(ImmutableArray<Tuple<ProjectId, Diagnostic>> diagnostics, string fileName)
161245
{
162246
var orderedDiagnostics =
@@ -498,5 +582,18 @@ private static void PrintHelp()
498582
Console.WriteLine("/apply Write code fix changes back to disk");
499583
Console.WriteLine("/force Force an analyzer to be enabled, regardless of the configured rule set(s) for the solution");
500584
}
585+
586+
private struct DocumentAnalyzerPerformance
587+
{
588+
public DocumentAnalyzerPerformance(double editsPerSecond)
589+
{
590+
this.EditsPerSecond = editsPerSecond;
591+
}
592+
593+
public double EditsPerSecond
594+
{
595+
get;
596+
}
597+
}
501598
}
502599
}

StyleCop.Analyzers/StyleCopTester/Properties/launchSettings.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
"VisualStudioVersion": "$(VisualStudioVersion)",
1111
"VSINSTALLDIR": "$(VSAPPIDDIR)\\..\\..\\"
1212
}
13+
},
14+
"StyleCopAnalyzers.sln /stats /editperf": {
15+
"commandName": "Project",
16+
"commandLineArgs": "..\\..\\StyleCopAnalyzers.sln /stats /editperf",
17+
"workingDirectory": "$(MSBuildProjectDirectory)",
18+
"environmentVariables": {
19+
"MSBuildSDKsPath": "$(MSBuildSDKsPath)",
20+
"MSBuildExtensionsPath": "$(MSBuildExtensionsPath)",
21+
"VisualStudioVersion": "$(VisualStudioVersion)",
22+
"VSINSTALLDIR": "$(VSAPPIDDIR)\\..\\..\\"
23+
}
1324
}
1425
}
1526
}

0 commit comments

Comments
 (0)