String Equal Performance Benchmark - .NET Core 8
This article dives into a specific piece of code written in C#, which is designed to benchmark string comparison
methods. Let's break down the provided code snippet to understand its purpose and functionality.
Benchmarking 🚀
BenchmarkDotNet is a popular .NET library used for benchmarking code performance. The [Benchmark]
attribute is used to mark methods that should be included in the benchmarking process. This library provides accurate measurements by running the code multiple times and analyzing the results.
Start Benchmark
The code defines a class Benchy.cs
😊 with three methods, each performing a different type of string comparison. The class uses the [MemoryDiagnoser]
attribute to measure memory usage and [Benchmark]
attributes to evaluate performance.
Within the Benchy
class, there are two fields, compare1
and compare2
, both initialized to the string "my_compare"
. These fields are used for comparison in the benchmark methods.
[MemoryDiagnoser]
[SimpleJob(runtimeMoniker: RuntimeMoniker.Net80)]
public class Benchy
{
private readonly string compare1 = "my_compare";
private readonly string compare2 = "my_compare";
// Benchmark methods
}
Benchmarking Methods
Description: This method compares two strings using the equality operator (==)
.
public bool DirectEqual()
{
return compare1 == compare2;
}
Description: This method converts both strings to lowercase
before comparison.
[Benchmark]
public bool ToLower()
{
return compare1.ToLower() == compare2.ToLower();
}
Description: This method uses string.Equals
for comparison, which is often more reliable and slightly more optimized than the equality operator.
public bool CompareEqual()
{
return string.Equals(compare1, compare2);
}
Description: This method uses string.Equals
with StringComparison.OrdinalIgnoreCase
to perform a case-insensitive comparison.
public bool CompareEqualWithIgnoreCase()
{
return string.Equals(compare1, compare2, StringComparison.OrdinalIgnoreCase);
}
Full Code Overview
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
namespace StringEqualBenchDemo
{
[MemoryDiagnoser]
[SimpleJob(runtimeMoniker: RuntimeMoniker.Net80)]
public class Benchy
{
private readonly string compare1 = "my_compare";
private readonly string compare2 = "my_compare";
[Benchmark(Baseline = true)]
public bool DirectEqual()
{
return compare1 == compare2;
}
[Benchmark]
public bool ToLower()
{
return compare1.ToLower() == compare2.ToLower();
}
[Benchmark]
public bool CompareEqual()
{
return string.Equals(compare1, compare2);
}
[Benchmark]
public bool CompareEqualWithIgnoreCase()
{
return string.Equals(compare1, compare2, StringComparison.OrdinalIgnoreCase);
}
}
}
Results
| Method | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
|--------------------------- |-----------:|----------:|----------:|------:|--------:|----------:|------------:|
| DirectEqual | 0.2531 ns | 0.0236 ns | 0.0221 ns | 1.01 | 0.12 | - | NA |
| ToLower | 22.4630 ns | 0.2692 ns | 0.2387 ns | 89.38 | 7.58 | - | NA |
| CompareEqual | 0.0274 ns | 0.0136 ns | 0.0114 ns | 0.11 | 0.04 | - | NA |
| CompareEqualWithIgnoreCase | 1.1919 ns | 0.0334 ns | 0.0312 ns | 4.74 | 0.42 | - | NA |
Benchmark Results Summary
DirectEqual:
- Mean Time:
0.2531 ns
- Ratio: 1.00 (baseline)
- Allocated Memory:
N/A
- Mean Time:
ToLower:
- Mean Time:
22.4630 ns
- Ratio:
89.38 times slower
thanDirectEqual
- Allocated Memory:
N/A
- Mean Time:
CompareEqual:
- Mean Time:
0.0274 ns
- Ratio:
0.11
(much faster thanDirectEqual
) - Allocated Memory:
N/A
- Mean Time:
CompareEqualWithIgnoreCase:
- Mean Time:
1.1919 ns
- Ratio:
4.74 times slower
thanDirectEqual
- Allocated Memory:
N/A
- Mean Time:
Conclusion
This summary highlights the performance of different methods, showing their relative execution times and how they compare to each other.