Skip to content

Reduce unnecessary heap allocations and improve efficiency#2

Merged
Treit merged 3 commits intomainfrom
u/perf-improvements
Mar 30, 2026
Merged

Reduce unnecessary heap allocations and improve efficiency#2
Treit merged 3 commits intomainfrom
u/perf-improvements

Conversation

@Treit
Copy link
Copy Markdown
Owner

@Treit Treit commented Mar 30, 2026

Addresses several sources of unnecessary allocations and redundant work across the analyzer, URL helper, and report generator.

CSharpAnalyzer: eliminate double-traversal of type ancestors in FunctionWalker.AddFunction, cache path separator strings outside the LINQ predicate, remove unnecessary .ToList() materialization on the file enumerable, and switch ProjectResolver from Directory.GetFiles to Directory.EnumerateFiles so it stops at the first match rather than collecting all results into an array.

AdoUrlHelper: replace Split('/').Last() with LastIndexOf-based slicing in GetDefaultBranch, and replace TakeWhile/Where/ToArray LINQ chain with a simple loop for the visualstudio.com path.

HtmlReportGenerator: accept IEnumerable in BuildRepoStats to avoid a redundant .ToList() at the call site, use string interpolation instead of concatenation in AppendRepoFunctionTable, and rewrite GetShortFileName to use Span-based scanning instead of Split + Join.

Mike Treit (from Dev Box) and others added 3 commits March 30, 2026 11:18
Eliminate redundant ancestor enumeration in FunctionWalker.AddFunction
by traversing TypeDeclarationSyntax ancestors once instead of twice.

Cache path separator strings outside the LINQ Where predicate in
CSharpAnalyzer so they are not re-allocated per file.

Remove unnecessary .ToList() call on csFiles enumerable since the
foreach loop does not require a materialized list.

Switch ProjectResolver from Directory.GetFiles (allocates full array)
to Directory.EnumerateFiles (lazy, stops at first match).

Replace Split('/').Last() with LastIndexOf-based slicing in
GetDefaultBranch to avoid allocating a throwaway string array.

Replace LINQ TakeWhile/Where/ToArray chain with a simple loop in
ParseRemoteUrl for the visualstudio.com code path.

Avoid double materialization in BuildRepoStats by accepting
IEnumerable and calling ToList once inside the method instead of at
the call site.

Use string interpolation instead of string concatenation with + in
AppendRepoFunctionTable header generation.

Rewrite GetShortFileName to use Span-based scanning instead of
Split + Join to find the last two path segments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Seal all 9 non-static classes (CSharpAnalyzer, FunctionMetrics,
AnalysisResult, AnalysisMetadata, Thresholds, RepoInfo,
AnalysisSummary, LanguageStats, HtmlReportGenerator) to enable
JIT devirtualization.

Add StringComparison.Ordinal to all string Contains, EndsWith,
and StartsWith calls in AdoUrlHelper that were using the slower
culture-sensitive overload on ASCII-only literals.

Use SourceText.From(Stream) instead of File.ReadAllText for Roslyn
parsing to avoid allocating the entire file content as a managed
string.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Treit Treit merged commit b09e77c into main Mar 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant