Fix perf issue in LineTrackingStringbuffer.ScanLines.
I noticed several hundred ms spent in this method from a customer profile. Primarilly, the method was doing a linear scan of all lines trying to find one that contained the requested position. I changed this to a binary search, but kept/improved the optimization around checking next/previous lines before instigating the search.
Note, there was also a bug where the old code did:
else if (absoluteIndex > _currentLine.Index && _currentLine.Index + 1 < _lines.Count)
but it should have been coparing absoluteIndex with _currentLine.Start
\n\nCommit migrated from 32a0f28708
This commit is contained in:
parent
7eca4ab2ec
commit
069b409dd4
|
|
@ -82,25 +82,51 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
{
|
{
|
||||||
TextLine selected = null;
|
TextLine selected = null;
|
||||||
|
|
||||||
if (_currentLine != null)
|
if (_currentLine == null)
|
||||||
{
|
|
||||||
if (_currentLine.Contains(absoluteIndex))
|
|
||||||
{
|
|
||||||
// This index is on the last read line
|
|
||||||
selected = _currentLine;
|
|
||||||
}
|
|
||||||
else if (absoluteIndex > _currentLine.Index && _currentLine.Index + 1 < _lines.Count)
|
|
||||||
{
|
|
||||||
// This index is ahead of the last read line
|
|
||||||
selected = ScanLines(absoluteIndex, _currentLine.Index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Have we found a line yet?
|
|
||||||
if (selected == null)
|
|
||||||
{
|
{
|
||||||
// Scan from line 0
|
// Scan from line 0
|
||||||
selected = ScanLines(absoluteIndex, 0);
|
selected = ScanLines(absoluteIndex, 0, _lines.Count);
|
||||||
|
}
|
||||||
|
else if (absoluteIndex >= _currentLine.End)
|
||||||
|
{
|
||||||
|
if (_currentLine.Index + 1 < _lines.Count)
|
||||||
|
{
|
||||||
|
// This index is after the last read line
|
||||||
|
var nextLine = _lines[_currentLine.Index + 1];
|
||||||
|
|
||||||
|
// Optimization to not search if it's the common case where the line after _currentLine is being requested.
|
||||||
|
if (nextLine.Contains(absoluteIndex))
|
||||||
|
{
|
||||||
|
selected = nextLine;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selected = ScanLines(absoluteIndex, _currentLine.Index, _lines.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (absoluteIndex < _currentLine.Start)
|
||||||
|
{
|
||||||
|
if (_currentLine.Index > 0)
|
||||||
|
{
|
||||||
|
// This index is before the last read line
|
||||||
|
var prevLine = _lines[_currentLine.Index - 1];
|
||||||
|
|
||||||
|
// Optimization to not search if it's the common case where the line before _currentLine is being requested.
|
||||||
|
if (prevLine.Contains(absoluteIndex))
|
||||||
|
{
|
||||||
|
selected = prevLine;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selected = ScanLines(absoluteIndex, 0, _currentLine.Index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This index is on the last read line
|
||||||
|
selected = _currentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(selected == null || selected.Contains(absoluteIndex));
|
Debug.Assert(selected == null || selected.Contains(absoluteIndex));
|
||||||
|
|
@ -108,18 +134,31 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextLine ScanLines(int absoluteIndex, int startPos)
|
private TextLine ScanLines(int absoluteIndex, int startLineIndex, int endLineIndex)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _lines.Count; i++)
|
// binary search for the line containing absoluteIndex
|
||||||
{
|
var lowIndex = startLineIndex;
|
||||||
var idx = (i + startPos) % _lines.Count;
|
var highIndex = _lines.Count;
|
||||||
Debug.Assert(idx >= 0 && idx < _lines.Count);
|
|
||||||
|
|
||||||
if (_lines[idx].Contains(absoluteIndex))
|
while (lowIndex != highIndex)
|
||||||
|
{
|
||||||
|
var midIndex = (lowIndex + highIndex) / 2;
|
||||||
|
var midLine = _lines[midIndex];
|
||||||
|
|
||||||
|
if (absoluteIndex >= midLine.End)
|
||||||
{
|
{
|
||||||
return _lines[idx];
|
lowIndex = midIndex + 1;
|
||||||
|
}
|
||||||
|
else if (absoluteIndex < midLine.Start)
|
||||||
|
{
|
||||||
|
highIndex = midIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return midLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue