Skip to content

Instantly share code, notes, and snippets.

@bbowyersmyth
Last active January 25, 2016 22:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbowyersmyth/6603b5ee69c7037a6404 to your computer and use it in GitHub Desktop.
Save bbowyersmyth/6603b5ee69c7037a6404 to your computer and use it in GitHub Desktop.
StartsWithAlignedUnaligned
using BenchmarkDotNet;
using BenchmarkDotNet.Tasks;
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
namespace ConsoleApplication2
{
[BenchmarkTask(platform: BenchmarkPlatform.X64, jitVersion: BenchmarkJitVersion.RyuJit)]
public class StringCompare
{
// Equal comparisons
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 23, 24, 25, 31, 32,
// 33, 39, 40, 41, 47, 48, 49, 55, 56, 57, 63, 64, 65,
// 95, 96, 97, 100, 127, 128, 129, 255, 256, 257, 511, 512)]
// Not-Equal comparisons
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)]
[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)]
public int Length = 0;
string _string;
string _startsWith;
string _equals;
[Setup]
public void Setup()
{
_string = new string('a', 512);
// Equal comparisons
//_startsWith = new string('a', Length);
//_equals = new string(_startsWith.ToCharArray());
// Not-Equal comparisons
_startsWith = new string('a', 17);
var notEquals = _startsWith.ToCharArray();
notEquals[Length] = 'X';
_equals = new string(notEquals);
}
[Benchmark]
public bool StartsWithAligned()
{
return StartsWithAligned(_startsWith, StringComparison.Ordinal);
}
[Benchmark]
public bool StartsWithUnaligned()
{
return StartsWith(_startsWith, StringComparison.Ordinal);
}
public Boolean StartsWith(String value, StringComparison comparisonType)
{
if ((Object)value == null)
{
throw new ArgumentNullException("value");
}
if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
{
throw new ArgumentException("NotSupported_StringComparison", "comparisonType");
}
if ((Object)_string == (Object)value)
{
return true;
}
if (value.Length == 0)
{
return true;
}
switch (comparisonType)
{
case StringComparison.CurrentCulture:
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None);
case StringComparison.CurrentCultureIgnoreCase:
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase);
case StringComparison.InvariantCulture:
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None);
case StringComparison.InvariantCultureIgnoreCase:
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase);
case StringComparison.Ordinal:
if (_string.Length < value.Length || _string[0] != value[0])
{
return false;
}
return (value.Length == 1) ?
true : // First char is the same and thats all there is to compare
StartsWithOrdinalUnaligned(_string, value, value.Length);
case StringComparison.OrdinalIgnoreCase:
if (_string.Length < value.Length)
{
return false;
}
return true;
default:
throw new ArgumentException("NotSupported_StringComparison", "comparisonType");
}
}
public Boolean StartsWithAligned(String value, StringComparison comparisonType)
{
if ((Object)value == null)
{
throw new ArgumentNullException("value");
}
if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
{
throw new ArgumentException("NotSupported_StringComparison", "comparisonType");
}
if ((Object)_string == (Object)value)
{
return true;
}
if (value.Length == 0)
{
return true;
}
switch (comparisonType)
{
case StringComparison.CurrentCulture:
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None);
case StringComparison.CurrentCultureIgnoreCase:
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase);
case StringComparison.InvariantCulture:
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None);
case StringComparison.InvariantCultureIgnoreCase:
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase);
case StringComparison.Ordinal:
if (_string.Length < value.Length || _string[0] != value[0])
{
return false;
}
return (value.Length == 1) ?
true : // First char is the same and thats all there is to compare
StartsWithOrdinalAligned(_string, value, value.Length);
case StringComparison.OrdinalIgnoreCase:
if (_string.Length < value.Length)
{
return false;
}
return true;
default:
throw new ArgumentException("NotSupported_StringComparison", "comparisonType");
}
}
private unsafe bool StartsWithOrdinalUnaligned(string strA, string strB, int length)
{
fixed (char* ap = strA)
fixed (char* bp = strB)
{
char* a = ap;
char* b = bp;
while (length >= 12)
{
if (*(long*)a != *(long*)b) goto ReturnFalse;
if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
length -= 12; a += 12; b += 12;
}
while (length >= 2)
{
if (*(int*)a != *(int*)b) goto ReturnFalse;
length -= 2; a += 2; b += 2;
}
return length == 0 | *a == *b;
ReturnFalse:
return false;
}
}
private unsafe bool StartsWithOrdinalAligned(string strA, string strB, int length)
{
fixed (char* ap = strA)
fixed (char* bp = strB)
{
char* a = ap;
char* b = bp;
if (length >= 2)
{
if (*(int*)a != *(int*)b) goto ReturnFalse;
length -= 2; a += 2; b += 2;
}
while (length >= 12)
{
if (*(long*)a != *(long*)b) goto ReturnFalse;
if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
length -= 12; a += 12; b += 12;
}
while (length >= 2)
{
if (*(int*)a != *(int*)b) goto ReturnFalse;
length -= 2; a += 2; b += 2;
}
return length == 0 | *a == *b;
ReturnFalse:
return false;
}
}
}
}
@bbowyersmyth
Copy link
Author

Two 17 character strings that differ at index n:

Method n AvrTime StdDev op/s
StartsWithAligned 1 9.3472 ns 0.0527 ns 106,986,314.74
StartsWithUnaligned 1 9.5353 ns 0.4255 ns 105,009,881.74
StartsWithAligned 2 9.3379 ns 0.0862 ns 107,096,548.11
StartsWithUnaligned 2 9.3866 ns 0.0399 ns 106,536,426.10
StartsWithAligned 3 9.3080 ns 0.0795 ns 107,439,364.95
StartsWithUnaligned 3 9.2883 ns 0.0182 ns 107,662,024.79
StartsWithAligned 4 9.3222 ns 0.0071 ns 107,270,425.72
StartsWithUnaligned 4 9.4437 ns 0.2591 ns 105,943,615.59
StartsWithAligned 5 9.3539 ns 0.0928 ns 106,914,605.32
StartsWithUnaligned 5 9.3269 ns 0.0360 ns 107,218,140.99
StartsWithAligned 6 9.4828 ns 0.1954 ns 105,484,176.60
StartsWithUnaligned 6 9.3796 ns 0.0345 ns 106,614,911.73
StartsWithAligned 7 9.3796 ns 0.0278 ns 106,614,749.20
StartsWithUnaligned 7 9.4314 ns 0.2391 ns 106,074,027.33
StartsWithAligned 8 9.3732 ns 0.0282 ns 106,687,917.44
StartsWithUnaligned 8 9.3219 ns 0.0755 ns 107,278,468.59
StartsWithAligned 9 9.3161 ns 0.0462 ns 107,342,580.74
StartsWithUnaligned 9 9.3091 ns 0.0601 ns 107,424,677.29
StartsWithAligned 10 9.4216 ns 0.1984 ns 106,170,087.24
StartsWithUnaligned 10 9.5813 ns 0.4857 ns 104,544,279.46
StartsWithAligned 11 9.3979 ns 0.0214 ns 106,407,072.09
StartsWithUnaligned 11 9.2943 ns 0.0219 ns 107,593,414.72
StartsWithAligned 12 9.6444 ns 0.1185 ns 103,698,060.81
StartsWithUnaligned 12 9.5616 ns 0.1869 ns 104,611,358.74
StartsWithAligned 13 9.3589 ns 0.1005 ns 106,858,688.85
StartsWithUnaligned 13 9.7793 ns 0.3857 ns 102,361,147.69
StartsWithAligned 14 9.5057 ns 0.2779 ns 105,259,016.15
StartsWithUnaligned 14 9.3710 ns 0.0705 ns 106,716,255.53
StartsWithAligned 15 9.3124 ns 0.0708 ns 107,388,045.83
StartsWithUnaligned 15 9.4636 ns 0.0698 ns 105,671,860.98
StartsWithAligned 16 9.4976 ns 0.1649 ns 105,310,420.25
StartsWithUnaligned 16 9.5106 ns 0.2583 ns 105,197,468.78

Results for when strings match:

Method Len AvrTime StdDev op/s
StartsWithAligned 1 5.7927 ns 0.0089 ns 172,630,279.87
StartsWithUnaligned 1 5.7988 ns 0.0830 ns 172,473,087.50
StartsWithAligned 2 8.5271 ns 0.2598 ns 117,344,879.04
StartsWithUnaligned 2 7.8332 ns 0.2196 ns 127,728,393.60
StartsWithAligned 3 8.4023 ns 0.0687 ns 119,019,811.87
StartsWithUnaligned 3 7.5934 ns 0.0278 ns 131,694,575.22
StartsWithAligned 4 8.1277 ns 0.0415 ns 123,037,416.75
StartsWithUnaligned 4 8.1417 ns 0.0426 ns 122,827,260.87
StartsWithAligned 5 8.1466 ns 0.0257 ns 122,751,258.02
StartsWithUnaligned 5 8.3764 ns 0.3690 ns 119,534,701.27
StartsWithAligned 6 8.9566 ns 0.3640 ns 111,771,121.60
StartsWithUnaligned 6 9.3773 ns 0.0594 ns 106,643,559.26
StartsWithAligned 7 8.6744 ns 0.0541 ns 115,284,888.89
StartsWithUnaligned 7 9.2638 ns 0.0266 ns 107,948,057.53
StartsWithAligned 8 9.3125 ns 0.0612 ns 107,385,981.78
StartsWithUnaligned 8 9.8789 ns 0.0190 ns 101,225,963.86
StartsWithAligned 9 9.5387 ns 0.3983 ns 104,955,206.31
StartsWithUnaligned 9 9.9194 ns 0.0937 ns 100,818,786.84
StartsWithAligned 10 9.8529 ns 0.0792 ns 101,497,156.14
StartsWithUnaligned 10 10.7562 ns 0.0939 ns 92,974,234.10
StartsWithAligned 11 9.8216 ns 0.0774 ns 101,821,101.17
StartsWithUnaligned 11 10.9966 ns 0.4093 ns 91,019,154.45
StartsWithAligned 15 9.2742 ns 0.3309 ns 107,915,532.86
StartsWithUnaligned 15 8.6826 ns 0.0407 ns 115,173,983.04
StartsWithAligned 16 9.2816 ns 0.0160 ns 107,739,916.17
StartsWithUnaligned 16 9.3460 ns 0.0878 ns 107,003,830.09
StartsWithAligned 17 9.2953 ns 0.0177 ns 107,581,601.54
StartsWithUnaligned 17 9.3452 ns 0.0487 ns 107,008,699.53
StartsWithAligned 23 10.9744 ns 0.0366 ns 91,121,838.28
StartsWithUnaligned 23 11.6024 ns 0.0270 ns 86,189,245.23
StartsWithAligned 24 13.1254 ns 0.1098 ns 76,191,611.54
StartsWithUnaligned 24 9.6031 ns 0.0585 ns 104,135,260.38
StartsWithAligned 25 11.6931 ns 0.1633 ns 85,531,388.54
StartsWithUnaligned 25 9.3568 ns 0.0063 ns 106,874,412.06
StartsWithAligned 31 11.3196 ns 0.4826 ns 88,447,137.36
StartsWithUnaligned 31 11.3633 ns 0.3223 ns 88,049,635.87
StartsWithAligned 32 11.5901 ns 0.0850 ns 86,283,433.52
StartsWithUnaligned 32 12.0059 ns 0.0925 ns 83,295,356.47
StartsWithAligned 33 12.2163 ns 0.0623 ns 81,859,519.08
StartsWithUnaligned 33 12.6535 ns 0.0788 ns 79,031,405.83
StartsWithAligned 39 11.3829 ns 0.0385 ns 87,851,943.10
StartsWithUnaligned 39 11.0655 ns 0.0466 ns 90,372,194.70
StartsWithAligned 40 11.6891 ns 0.0487 ns 85,551,082.94
StartsWithUnaligned 40 11.9136 ns 0.0593 ns 83,939,056.82
StartsWithAligned 41 11.8895 ns 0.4430 ns 84,184,229.40
StartsWithUnaligned 41 12.1548 ns 0.4511 ns 82,346,182.44
StartsWithAligned 47 14.2190 ns 0.0681 ns 70,329,406.63
StartsWithUnaligned 47 14.9808 ns 0.2963 ns 66,769,482.76
StartsWithAligned 48 15.3591 ns 0.1005 ns 65,109,929.89
StartsWithUnaligned 48 12.5232 ns 0.2576 ns 79,873,908.96
StartsWithAligned 49 15.3925 ns 0.0702 ns 64,967,417.27
StartsWithUnaligned 49 11.8795 ns 0.0144 ns 84,178,421.94
StartsWithAligned 55 13.4768 ns 0.1104 ns 74,205,086.60
StartsWithUnaligned 55 14.3148 ns 0.2919 ns 69,876,910.89
StartsWithAligned 56 14.6217 ns 0.0413 ns 68,391,874.84
StartsWithUnaligned 56 14.9728 ns 0.0985 ns 66,789,530.33
StartsWithAligned 57 14.8867 ns 0.4522 ns 67,214,747.10
StartsWithUnaligned 57 14.8643 ns 0.0944 ns 67,277,082.73
StartsWithAligned 63 13.6865 ns 0.0917 ns 73,066,643.42
StartsWithUnaligned 63 14.0020 ns 0.8517 ns 71,589,271.36
StartsWithAligned 64 13.9684 ns 0.0811 ns 71,591,585.60
StartsWithUnaligned 64 14.5534 ns 0.3092 ns 68,732,858.25
StartsWithAligned 65 14.9300 ns 0.8635 ns 67,131,715.03
StartsWithUnaligned 65 14.3018 ns 0.0815 ns 69,922,592.71
StartsWithAligned 95 19.0827 ns 0.2972 ns 52,411,805.47
StartsWithUnaligned 95 20.0528 ns 0.9323 ns 49,938,487.08
StartsWithAligned 96 20.0837 ns 0.0690 ns 49,791,937.61
StartsWithUnaligned 96 17.6106 ns 0.7158 ns 56,845,512.02
StartsWithAligned 97 20.2618 ns 0.3631 ns 49,364,476.09
StartsWithUnaligned 97 17.2411 ns 0.0865 ns 58,001,974.46
StartsWithAligned 100 18.0239 ns 0.5767 ns 55,519,482.17
StartsWithUnaligned 100 18.0825 ns 0.0965 ns 55,303,115.65
StartsWithAligned 127 20.3935 ns 0.0486 ns 49,035,440.42
StartsWithUnaligned 127 23.3620 ns 1.4493 ns 42,918,805.68
StartsWithAligned 128 21.7078 ns 0.1095 ns 46,067,214.55
StartsWithUnaligned 128 22.2612 ns 0.1563 ns 44,922,603.68
StartsWithAligned 129 21.5939 ns 0.0943 ns 46,310,014.02
StartsWithUnaligned 129 22.4548 ns 0.4300 ns 44,544,712.83
StartsWithAligned 255 32.5054 ns 0.2134 ns 30,764,971.96
StartsWithUnaligned 255 32.6387 ns 0.1909 ns 30,639,177.52
StartsWithAligned 256 32.6157 ns 0.1203 ns 30,660,384.35
StartsWithUnaligned 256 33.7692 ns 0.4389 ns 29,616,119.63
StartsWithAligned 257 32.5238 ns 0.1913 ns 30,747,451.90
StartsWithUnaligned 257 33.4615 ns 0.0368 ns 29,885,146.96
StartsWithAligned 511 65.7710 ns 1.4750 ns 15,209,301.98
StartsWithUnaligned 511 74.0477 ns 1.5174 ns 13,508,607.59
StartsWithAligned 512 66.0537 ns 0.6586 ns 15,140,193.46
StartsWithUnaligned 512 76.0744 ns 4.2045 ns 13,171,035.15

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment