Skip to content

Commit

Permalink
Performance improvement in DistanceFrom, by giving the JIT more info …
Browse files Browse the repository at this point in the history
…allowing it to not reload from memory and perform bounds checks five times.
  • Loading branch information
DanHarltey committed May 28, 2024
1 parent 28864d6 commit 0d930bd
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 16 deletions.
28 changes: 17 additions & 11 deletions src/Fastenshtein/Levenshtein.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ public partial class Levenshtein
* WARRING this class is performance critical (Speed).
*/

private readonly string storedValue;
private readonly int[] costs;
private readonly string _storedValue;
private readonly int[] _costs;

/// <summary>
/// Creates a new instance with a value to test other values against
/// </summary>
/// <param Name="value">Value to compare other values to.</param>
public Levenshtein(string value)
{
this.storedValue = value;
_storedValue = value;
// Create matrix row
this.costs = new int[this.storedValue.Length];
_costs = new int[value.Length];
}

/// <summary>
/// gets the length of the stored value that is tested against
/// </summary>
public int StoredLength => this.storedValue.Length;
public int StoredLength => _storedValue.Length;

/// <summary>
/// Compares a value to the stored value.
Expand All @@ -36,15 +36,21 @@ public Levenshtein(string value)
/// <returns>Difference. 0 complete match.</returns>
public int DistanceFrom(string value)
{
if (costs.Length == 0)
// copying to local variables allows JIT to remove bounds checks, as it understands they can not change
var costs = _costs;
var storedValue = _storedValue;

if (costs.Length == 0
// this will never be ture, however it allows the JIT to remove a bounds check
|| costs.Length != storedValue.Length)
{
return value.Length;
}

// Add indexing for insertion to first row
for (int i = 0; i < this.costs.Length;)
for (int i = 0; i < costs.Length;)
{
this.costs[i] = ++i;
costs[i] = ++i;
}

for (int i = 0; i < value.Length; i++)
Expand All @@ -56,14 +62,14 @@ public int DistanceFrom(string value)
// cache value for inner loop to avoid index lookup and bonds checking, profiled this is quicker
char value1Char = value[i];

for (int j = 0; j < this.storedValue.Length; j++)
for (int j = 0; j < storedValue.Length; j++)
{
int currentCost = cost;

// assigning this here reduces the array reads we do, improvement of the old version
cost = costs[j];

if (value1Char != this.storedValue[j])
if (value1Char != storedValue[j])
{
if (previousCost < currentCost)
{
Expand All @@ -87,7 +93,7 @@ public int DistanceFrom(string value)
}
}

return this.costs[this.costs.Length - 1];
return costs[costs.Length - 1];
}
}
}
10 changes: 5 additions & 5 deletions tests/Fastenshtein.Tests/Fastenshtein.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="6.0.0">
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.5" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="xunit" Version="2.8.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down

0 comments on commit 0d930bd

Please sign in to comment.