Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
27ea778
Materialize method comparisons instead of rebuilding them for every a…
MihaZupan Sep 4, 2026
b973865
Analyze file pairs in bounded parallel workers
MihaZupan Sep 4, 2026
bc47d72
Scan disassembly with pooled line buffers
MihaZupan Sep 4, 2026
bcb13f8
Aggregate method metrics while parsing disassembly
MihaZupan Sep 4, 2026
c882924
Store metric values compactly and avoid copying parsed metrics
MihaZupan Sep 4, 2026
bb910ad
Parallelize textual diffs and bypass git for identical files
MihaZupan Sep 4, 2026
a816f75
Reuse parsed methods and aggregate directly for identical file pairs
MihaZupan Sep 4, 2026
f261f89
Preserve symbolic-link semantics in parallel text comparisons
MihaZupan Sep 4, 2026
3533d57
Document large-input analysis and measured optimization results
MihaZupan Sep 4, 2026
e80f9a4
Compute text line counts only for files eligible for the text-only re…
MihaZupan Sep 4, 2026
12fdba8
Document demand-driven text analysis and 16.7x benchmark improvement
MihaZupan Sep 4, 2026
6160a67
Use default PLINQ parallelism for assembly analysis and text comparisons
MihaZupan Sep 5, 2026
eda4266
Use an IO FileInfo alias and explain directory-link handling
MihaZupan Sep 5, 2026
93f7a09
Use an owned buffer and Array.Resize in DisassemblyReader
MihaZupan Sep 5, 2026
88fe6f4
Reuse Utility.ExecuteProcess for analyzer Git commands
MihaZupan Sep 5, 2026
24d313c
Remove redundant stream-length check in FilesEqual
MihaZupan Sep 5, 2026
4577d8d
Remove the redundant byte comparison before Git text analysis
MihaZupan Sep 5, 2026
7f68fc7
Exclude regression harness and README expansion from the PR diff
MihaZupan Sep 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/jit-analyze/DisassemblyReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;

namespace ManagedCodeGen
{
// Return borrowed line spans so the overwhelmingly common instruction lines need no strings.
internal sealed class DisassemblyReader : IDisposable
{
private readonly StreamReader _reader;
private char[] _buffer = new char[32 * 1024];
private int _start;
private int _end;
private bool _skipLF;
private bool _eof;

public DisassemblyReader(string path)
{
_reader = new StreamReader(path);
}

public bool ReadLine(out ReadOnlySpan<char> line)
{
int scanned = 0;
while (true)
{
ReadOnlySpan<char> remaining = _buffer.AsSpan(_start, _end - _start);
if (_skipLF && !remaining.IsEmpty)
{
_skipLF = false;
if (remaining[0] == '\n')
{
_start++;
remaining = remaining.Slice(1);
}
}

int newline = remaining.Slice(scanned).IndexOfAny('\r', '\n');
if (newline >= 0)
{
newline += scanned;
line = remaining.Slice(0, newline);
_skipLF = remaining[newline] == '\r';
_start += newline + 1;
return true;
}

if (_eof)
{
line = remaining;
_start = _end;
return !line.IsEmpty;
}

scanned = remaining.Length;
if (remaining.Length == _buffer.Length)
{
Array.Resize(ref _buffer, checked(_buffer.Length * 2));
}
else
{
remaining.CopyTo(_buffer);
}

_start = 0;
_end = scanned;
int read = _reader.Read(_buffer.AsSpan(_end));
_end += read;
_eof = read == 0;
}
}

public void Dispose() => _reader.Dispose();
}
}
53 changes: 33 additions & 20 deletions src/jit-analyze/MetricCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ static MetricCollection()
}
}

private readonly double[] _values;

[JsonInclude]
private Metric[] metrics;
private Metric[] metrics => s_metrics.Select(m => GetMetric(m.Name)).ToArray();

public MetricCollection()
{
metrics = new Metric[s_metrics.Length];
for (int i = 0; i < s_metrics.Length; i++)
{
metrics[i] = s_metrics[i].Clone();
}
_values = new double[s_metrics.Length];
}

public MetricCollection(MetricCollection other) : this()
Expand All @@ -51,16 +49,27 @@ public MetricCollection(MetricCollection other) : this()

public static IEnumerable<Metric> AllMetrics => s_metrics;

// Materialize display metadata only for reports; analysis uses the compact values directly.
public Metric GetMetric(string metricName)
{
int index;
if (s_metricNameToIndex.TryGetValue(metricName, out index))
{
return metrics[index];
Metric metric = s_metrics[index].Clone();
metric.Value = _values[index];
return metric;
}
return null;
}

public double GetValue(string metricName) => _values[s_metricNameToIndex[metricName]];

public void AddInt(string metricName, int value)
{
int index = s_metricNameToIndex[metricName];
_values[index] = checked((int)_values[index] + value);
}

public static bool ValidateMetric(string name)
{
return s_metricNameToIndex.TryGetValue(name, out _);
Expand Down Expand Up @@ -104,47 +113,51 @@ public override string ToString()

public void Add(MetricCollection other)
{
for (int i = 0; i < metrics.Length; i++)
for (int i = 0; i < _values.Length; i++)
{
metrics[i].Add(other.metrics[i]);
_values[i] += other._values[i];
}
}

public void Add(string metricName, double value)
{
Metric m = GetMetric(metricName);
m.Value += value;
_values[s_metricNameToIndex[metricName]] += value;
}

public void Sub(MetricCollection other)
{
for (int i = 0; i < metrics.Length; i++)
for (int i = 0; i < _values.Length; i++)
{
metrics[i].Sub(other.metrics[i]);
_values[i] -= other._values[i];
}
}

public void Rel(MetricCollection other)
{
for (int i = 0; i < metrics.Length; i++)
for (int i = 0; i < _values.Length; i++)
{
metrics[i].Rel(other.metrics[i]);
_values[i] = (_values[i] - other._values[i]) / other._values[i];
}
}

public void SetValueFrom(MetricCollection other)
public void AddRelativeDifference(MetricCollection diff, MetricCollection baseline)
{
for (int i = 0; i < metrics.Length; i++)
for (int i = 0; i < _values.Length; i++)
{
metrics[i].SetValueFrom(other.metrics[i]);
_values[i] += (diff._values[i] - baseline._values[i]) / baseline._values[i];
}
}

public void SetValueFrom(MetricCollection other)
{
other._values.CopyTo(_values, 0);
}

public bool IsZero()
{
for (int i = 0; i < metrics.Length; i++)
for (int i = 0; i < _values.Length; i++)
{
if (metrics[i].Value != 0) return false;
if (_values[i] != 0) return false;
}
return true;
}
Expand Down
Loading