Skip to content

Instantly share code, notes, and snippets.

@RobThree
Last active March 25, 2025 01:30
Show Gist options
  • Save RobThree/af3d098be7d730da18ab59d81ffb4d2a to your computer and use it in GitHub Desktop.
Save RobThree/af3d098be7d730da18ab59d81ffb4d2a to your computer and use it in GitHub Desktop.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace IshaFatima;
internal class Program
{
private static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Benchmarks>();
}
}
[MemoryDiagnoser]
public class Benchmarks
{
[Benchmark(Baseline = true)]
public void IfElseBenchmark()
=> IfElse(Random.Shared.Next(63));
public static string IfElse(int roleId)
{
if (roleId == 1) return "A";
else if (roleId == 2) return "B";
else if (roleId == 3) return "C";
else if (roleId == 4) return "D";
else if (roleId == 5) return "E";
else if (roleId == 6) return "F";
else if (roleId == 7) return "G";
else if (roleId == 8) return "H";
else if (roleId == 9) return "I";
else if (roleId == 10) return "J";
else if (roleId == 11) return "K";
else if (roleId == 12) return "L";
else if (roleId == 13) return "M";
else if (roleId == 14) return "N";
else if (roleId == 15) return "O";
else if (roleId == 16) return "P";
else if (roleId == 17) return "Q";
else if (roleId == 18) return "R";
else if (roleId == 19) return "S";
else if (roleId == 20) return "T";
else if (roleId == 21) return "U";
else if (roleId == 22) return "V";
else if (roleId == 23) return "W";
else if (roleId == 24) return "X";
else if (roleId == 25) return "Y";
else if (roleId == 26) return "Z";
else if (roleId == 27) return "a";
else if (roleId == 28) return "b";
else if (roleId == 29) return "c";
else if (roleId == 30) return "d";
else if (roleId == 31) return "e";
else if (roleId == 32) return "f";
else if (roleId == 33) return "g";
else if (roleId == 34) return "h";
else if (roleId == 35) return "i";
else if (roleId == 36) return "j";
else if (roleId == 37) return "k";
else if (roleId == 38) return "l";
else if (roleId == 39) return "m";
else if (roleId == 40) return "n";
else if (roleId == 41) return "o";
else if (roleId == 42) return "p";
else if (roleId == 43) return "q";
else if (roleId == 44) return "r";
else if (roleId == 45) return "s";
else if (roleId == 46) return "t";
else if (roleId == 47) return "u";
else if (roleId == 48) return "v";
else if (roleId == 49) return "w";
else if (roleId == 50) return "x";
else if (roleId == 51) return "y";
else if (roleId == 52) return "z";
else if (roleId == 53) return "0";
else if (roleId == 54) return "1";
else if (roleId == 55) return "2";
else if (roleId == 56) return "3";
else if (roleId == 57) return "4";
else if (roleId == 58) return "5";
else if (roleId == 59) return "6";
else if (roleId == 60) return "7";
else if (roleId == 61) return "8";
else if (roleId == 62) return "9";
return "Unknown";
}
[Benchmark]
public void SwitchExpressionBenchmark()
=> SwitchExpression(Random.Shared.Next(63));
public static string SwitchExpression(int roleId)
=> roleId switch
{
1 => "A",
2 => "B",
3 => "C",
4 => "D",
5 => "E",
6 => "F",
7 => "G",
8 => "H",
9 => "I",
10 => "J",
11 => "K",
12 => "L",
13 => "M",
14 => "N",
15 => "O",
16 => "P",
17 => "Q",
18 => "R",
19 => "S",
20 => "T",
21 => "U",
22 => "V",
23 => "W",
24 => "X",
25 => "Y",
26 => "Z",
27 => "a",
28 => "b",
29 => "c",
30 => "d",
31 => "e",
32 => "f",
33 => "g",
34 => "h",
35 => "i",
36 => "j",
37 => "k",
38 => "l",
39 => "m",
40 => "n",
41 => "o",
42 => "p",
43 => "q",
44 => "r",
45 => "s",
46 => "t",
47 => "u",
48 => "v",
49 => "w",
50 => "x",
51 => "y",
52 => "z",
53 => "0",
54 => "1",
55 => "2",
56 => "3",
57 => "4",
58 => "5",
59 => "6",
60 => "7",
61 => "8",
62 => "9",
_ => "Unknown"
};
[Benchmark]
public void SwitchStatementBenchmark()
=> SwitchStatement(Random.Shared.Next(63));
public static string SwitchStatement(int roleId)
{
switch (roleId)
{
case 1: return "A";
case 2: return "B";
case 3: return "C";
case 4: return "D";
case 5: return "E";
case 6: return "F";
case 7: return "G";
case 8: return "H";
case 9: return "I";
case 10: return "J";
case 11: return "K";
case 12: return "L";
case 13: return "M";
case 14: return "N";
case 15: return "O";
case 16: return "P";
case 17: return "Q";
case 18: return "R";
case 19: return "S";
case 20: return "T";
case 21: return "U";
case 22: return "V";
case 23: return "W";
case 24: return "X";
case 25: return "Y";
case 26: return "Z";
case 27: return "a";
case 28: return "b";
case 29: return "c";
case 30: return "d";
case 31: return "e";
case 32: return "f";
case 33: return "g";
case 34: return "h";
case 35: return "i";
case 36: return "j";
case 37: return "k";
case 38: return "l";
case 39: return "m";
case 40: return "n";
case 41: return "o";
case 42: return "p";
case 43: return "q";
case 44: return "r";
case 45: return "s";
case 46: return "t";
case 47: return "u";
case 48: return "v";
case 49: return "w";
case 50: return "x";
case 51: return "y";
case 52: return "z";
case 53: return "0";
case 54: return "1";
case 55: return "2";
case 56: return "3";
case 57: return "4";
case 58: return "5";
case 59: return "6";
case 60: return "7";
case 61: return "8";
case 62: return "9";
default: return "Unknown";
}
}
private static readonly Dictionary<int, string> _dictionary = new()
{
{ 1, "A" }, { 2, "B" }, { 3, "C" }, { 4, "D" }, { 5, "E" },
{ 6, "F" }, { 7, "G" }, { 8, "H" }, { 9, "I" }, { 10, "J" },
{ 11, "K" }, { 12, "L" }, { 13, "M" }, { 14, "N" }, { 15, "O" },
{ 16, "P" }, { 17, "Q" }, { 18, "R" }, { 19, "S" }, { 20, "T" },
{ 21, "U" }, { 22, "V" }, { 23, "W" }, { 24, "X" }, { 25, "Y" },
{ 26, "Z" }, { 27, "a" }, { 28, "b" }, { 29, "c" }, { 30, "d" },
{ 31, "e" }, { 32, "f" }, { 33, "g" }, { 34, "h" }, { 35, "i" },
{ 36, "j" }, { 37, "k" }, { 38, "l" }, { 39, "m" }, { 40, "n" },
{ 41, "o" }, { 42, "p" }, { 43, "q" }, { 44, "r" }, { 45, "s" },
{ 46, "t" }, { 47, "u" }, { 48, "v" }, { 49, "w" }, { 50, "x" },
{ 51, "y" }, { 52, "z" }, { 53, "0" }, { 54, "1" }, { 55, "2" },
{ 56, "3" }, { 57, "4" }, { 58, "5" }, { 59, "6" }, { 60, "7" },
{ 61, "8" }, { 62, "9" }
};
[Benchmark]
public void DictionaryBenchmark()
=> Dictionary(Random.Shared.Next(63));
public static string Dictionary(int roleId)
=> _dictionary.TryGetValue(roleId, out var role) ? role : "Unknown";
}

63 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 19.745 ns 0.1915 ns 0.1698 ns 1.00 - NA
SwitchExpression 15.116 ns 0.1985 ns 0.1759 ns 0.77 - NA
SwitchStatement 15.069 ns 0.2882 ns 0.2695 ns 0.76 - NA
Dictionary 7.272 ns 0.1470 ns 0.1303 ns 0.37 - NA

For those interested in what the above code compiles to:

I am currently looking where the break-even point is (at my machine / cpu architecture)

53 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 19.092 ns 0.1104 ns 0.0978 ns 1.00 - NA
SwitchExpression 15.164 ns 0.1568 ns 0.1467 ns 0.79 - NA
SwitchStatement 15.377 ns 0.1195 ns 0.0998 ns 0.81 - NA
Dictionary 7.376 ns 0.1252 ns 0.1110 ns 0.39 - NA

43 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 18.251 ns 0.2457 ns 0.2298 ns 1.00 - NA
SwitchExpression 15.166 ns 0.1731 ns 0.1619 ns 0.83 - NA
SwitchStatement 15.150 ns 0.1096 ns 0.0916 ns 0.83 - NA
Dictionary 7.496 ns 0.1763 ns 0.1649 ns 0.41 - NA

33 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 16.974 ns 0.0991 ns 0.0828 ns 1.00 - NA
SwitchExpression 15.208 ns 0.1701 ns 0.1591 ns 0.90 - NA
SwitchStatement 15.097 ns 0.1499 ns 0.1328 ns 0.89 - NA
Dictionary 7.413 ns 0.1098 ns 0.0973 ns 0.44 - NA

23 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 16.198 ns 0.3217 ns 0.3009 ns 1.00 - NA
SwitchExpression 14.916 ns 0.2451 ns 0.2292 ns 0.92 - NA
SwitchStatement 14.970 ns 0.1420 ns 0.1185 ns 0.92 - NA
Dictionary 7.540 ns 0.1794 ns 0.1591 ns 0.47 - NA

13 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 14.486 ns 0.0990 ns 0.0878 ns 1.00 - NA
SwitchExpression 14.597 ns 0.2887 ns 0.2559 ns 1.01 - NA
SwitchStatement 14.353 ns 0.1049 ns 0.0876 ns 0.99 - NA
Dictionary 8.066 ns 0.1625 ns 0.1520 ns 0.56 - NA

10 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 13.201 ns 0.1169 ns 0.1037 ns 1.00 - NA
SwitchExpression 13.860 ns 0.0684 ns 0.0571 ns 1.05 - NA
SwitchStatement 13.923 ns 0.0796 ns 0.0622 ns 1.05 - NA
Dictionary 8.342 ns 0.1522 ns 0.1271 ns 0.63 - NA

8 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 11.746 ns 0.0853 ns 0.0798 ns 1.00 - NA
SwitchExpression 13.447 ns 0.2353 ns 0.2201 ns 1.14 - NA
SwitchStatement 13.331 ns 0.0925 ns 0.0865 ns 1.13 - NA
Dictionary 8.676 ns 0.0608 ns 0.0507 ns 0.74 - NA

6 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 10.866 ns 0.0749 ns 0.0701 ns 1.00 - NA
SwitchExpression 13.170 ns 0.1041 ns 0.0870 ns 1.21 - NA
SwitchStatement 13.183 ns 0.1063 ns 0.0942 ns 1.21 - NA
Dictionary 8.968 ns 0.1235 ns 0.1095 ns 0.83 - NA

4 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 8.194 ns 0.0712 ns 0.0666 ns 1.00 - NA
SwitchExpression 12.046 ns 0.1117 ns 0.0990 ns 1.47 - NA
SwitchStatement 12.682 ns 0.0872 ns 0.0728 ns 1.55 - NA
Dictionary 10.707 ns 0.1579 ns 0.1477 ns 1.31 - NA

3 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 6.667 ns 0.1066 ns 0.0997 ns 1.00 - NA
SwitchExpression 7.145 ns 0.1266 ns 0.1122 ns 1.07 - NA
SwitchStatement 7.215 ns 0.1189 ns 0.1112 ns 1.08 - NA
Dictionary 11.609 ns 0.1410 ns 0.1318 ns 1.74 - NA

2 elements

Method Mean Error StdDev Ratio Allocated Alloc Ratio
IfElse 1.749 ns 0.0468 ns 0.0438 ns 1.00 - NA
SwitchExpression 2.906 ns 0.0421 ns 0.0373 ns 1.66 - NA
SwitchStatement 2.947 ns 0.0744 ns 0.0696 ns 1.69 - NA
Dictionary 12.457 ns 0.1740 ns 0.1628 ns 7.13 - NA

image

So, why is the dictionary so incredibly fast in this specific case? I am making an educated guess here, but I'm quite sure it's because the int is the key and doesn't need hashing. So while the dictionary may perform better over ~5 items, this is NOT a given. As soon as the dictionary is something like a string or other type, hashing will move the break-even point down the line. There will be other factors at play here like CPU architecture, AoT vs JIT compilation etc. so don't take any of this as a rule of thumb or anything.

Another thing to note is that I've kept in the "Unknown" case in all above benchmarks. That means that it's influence in the first benchmark is 1/62 but in the last benchmark 1/2. Given that it will take a different branch it will likely disproportionally skew the results.

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