-
Notifications
You must be signed in to change notification settings - Fork 387
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In order to better compare the performance between the existing v6 and the one with the [Fractions](https://github.com/danm-de/Fractions) I've been using these benchmarks. They are not _very polished_ (and I haven't had the time for the string-related stuff) but they do the trick. You don't have to merge them if you don't want to, but at least they are here (so I can reference the code). I'll probably add the results from my local runs in a comment (or more like a bunch of comments) later on (my previous results got wiped by the build script 😆) - but I was hoping that we could update the packages and add net9.0 to the list of targets first (there are [lots of a cool stuff](danm-de/Fractions#90) in net9). PS I'm not sure if that old `gh-action` would still work or not, but even adding the results by hand ([here?](https://github.com/angularsen/UnitsNet/tree/gh-pages/benchmarks/)) is an option. Here's what I did for the [Fractions](https://github.com/danm-de/Fractions/blob/master/benchmarks/Readme.md) (the `Readme.md` was 90% AI generated).
- Loading branch information
Showing
35 changed files
with
1,917 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Licensed under MIT No Attribution, see LICENSE file at the root. | ||
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet. | ||
|
||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace UnitsNet.Benchmark; | ||
|
||
public static class BenchmarkHelpers | ||
{ | ||
public static string[] GetRandomAbbreviations<TQuantity>(this Random random, UnitAbbreviationsCache abbreviations, int nbAbbreviations) | ||
{ | ||
return random.GetItems(abbreviations.GetAllUnitAbbreviationsForQuantity(typeof(TQuantity)).ToArray(), nbAbbreviations); | ||
} | ||
|
||
public static (TQuantity Quantity, TUnit Unit)[] GetRandomConversions<TQuantity, TUnit>(this Random random, double value, TUnit[] options, | ||
int nbConversions) | ||
where TQuantity : IQuantity<TUnit> | ||
where TUnit : struct, Enum | ||
{ | ||
var quantities = GetRandomQuantities<TQuantity, TUnit>(random, value, options, nbConversions); | ||
TUnit[] units = random.GetItems(options, nbConversions); | ||
return quantities.Zip(units, (quantity, unit) => (quantity, unit)).ToArray(); | ||
} | ||
|
||
public static IEnumerable<TQuantity> GetRandomQuantities<TQuantity, TUnit>(this Random random, double value, TUnit[] units, int nbQuantities) | ||
where TQuantity : IQuantity<TUnit> where TUnit : struct, Enum | ||
{ | ||
IEnumerable<TQuantity> quantities = random.GetItems(units, nbQuantities).Select(unit => (TQuantity)Quantity.From(value, unit)); | ||
return quantities; | ||
} | ||
|
||
#if !NET | ||
/// <summary>Creates an array populated with items chosen at random from the provided set of choices.</summary> | ||
/// <param name="random">The random number generator used to select items.</param> | ||
/// <param name="choices">The items to use to populate the array.</param> | ||
/// <param name="length">The length of array to return.</param> | ||
/// <typeparam name="T">The type of array.</typeparam> | ||
/// <exception cref="T:System.ArgumentException"> | ||
/// <paramref name="choices" /> is empty.</exception> | ||
/// <exception cref="T:System.ArgumentNullException"> | ||
/// <paramref name="choices" /> is <see langword="null" />.</exception> | ||
/// <exception cref="T:System.ArgumentOutOfRangeException"> | ||
/// <paramref name="length" /> is not zero or a positive number.</exception> | ||
/// <returns>An array populated with random items.</returns> | ||
public static T[] GetItems<T>(this Random random, T[] choices, int length) | ||
{ | ||
return GetItems<T>(random, new ReadOnlySpan<T>(choices), length); | ||
} | ||
|
||
/// <summary> | ||
/// Generates an array of specified length with items chosen at random from the provided set of choices. | ||
/// </summary> | ||
/// <typeparam name="T">The type of the items.</typeparam> | ||
/// <param name="random">The random number generator used to select items.</param> | ||
/// <param name="choices">The set of items to choose from.</param> | ||
/// <param name="length">The length of the resulting array.</param> | ||
/// <returns>An array of randomly selected items.</returns> | ||
/// <exception cref="ArgumentException">Thrown when <paramref name="choices"/> is empty.</exception> | ||
public static T[] GetItems<T>(this Random random, ReadOnlySpan<T> choices, int length) | ||
{ | ||
T[] array = new T[length]; | ||
GetItems<T>(random, choices, array.AsSpan<T>()); | ||
return array; | ||
} | ||
|
||
/// <summary>Fills the elements of a specified span with items chosen at random from the provided set of choices.</summary> | ||
/// <param name="random">The random number generator used to select items.</param> | ||
/// <param name="choices">The items to use to populate the span.</param> | ||
/// <param name="destination">The span to be filled with items.</param> | ||
/// <typeparam name="T">The type of span.</typeparam> | ||
/// <exception cref="T:System.ArgumentException"> | ||
/// <paramref name="choices" /> is empty.</exception> | ||
public static void GetItems<T>(this Random random, ReadOnlySpan<T> choices, Span<T> destination) | ||
{ | ||
for (int index = 0; index < destination.Length; ++index) | ||
destination[index] = choices[random.Next(choices.Length)]; | ||
} | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using BenchmarkDotNet.Attributes; | ||
using BenchmarkDotNet.Jobs; | ||
|
||
namespace UnitsNet.Benchmark.Comparisons; | ||
|
||
[MemoryDiagnoser] | ||
[ShortRunJob(RuntimeMoniker.Net48)] | ||
[ShortRunJob(RuntimeMoniker.Net80)] | ||
public class ComparisonBenchmarks | ||
{ | ||
private static readonly Mass Tolerance = Mass.FromNanograms(1); | ||
|
||
public static IEnumerable<object[]> Operands() | ||
{ | ||
// equal value and unit | ||
yield return [Mass.From(42, Mass.BaseUnit), Mass.From(42, Mass.BaseUnit)]; | ||
// equal value and unit | ||
yield return [Mass.FromGrams(42), Mass.FromGrams(42)]; | ||
// zero in another unit | ||
yield return [Mass.Zero, Mass.FromGrams(0)]; | ||
// same quantity in another unit | ||
yield return [Mass.FromGrams(42), Mass.FromMilligrams(42000)]; | ||
// same quantity in another unit (in reverse) | ||
yield return [Mass.FromMilligrams(42000), Mass.FromGrams(42)]; | ||
// different value and same unit | ||
yield return [Mass.FromGrams(42), Mass.FromGrams(42.1)]; | ||
// huge values, same unit | ||
yield return [Mass.FromGrams(-1e37), Mass.FromGrams(1 / 1e12)]; | ||
// huge values, different units | ||
yield return [Mass.FromGrams(-1e37), Mass.FromMilligrams(1 / 1e12)]; | ||
// Math.PI, same unit | ||
yield return [Mass.FromGrams(Math.PI), Mass.FromGrams(Math.PI)]; | ||
// Math.PI, different units | ||
yield return [Mass.FromGrams(Math.PI), Mass.FromMilligrams(Math.PI)]; | ||
// very close fractions, same units | ||
yield return [Mass.FromGrams(12.3456789987654321), Mass.FromGrams(12.3456789987654322)]; | ||
} | ||
|
||
[Benchmark] | ||
[ArgumentsSource(nameof(Operands))] | ||
public bool Equals(Mass a, Mass b) | ||
{ | ||
return a.Equals(b); | ||
} | ||
|
||
[Benchmark] | ||
[ArgumentsSource(nameof(Operands))] | ||
public bool EqualsTolerance(Mass a, Mass b) | ||
{ | ||
return a.Equals(b, Tolerance); | ||
} | ||
|
||
[Benchmark] | ||
[ArgumentsSource(nameof(Operands))] | ||
public bool GetHashCode(Mass a, Mass b) | ||
{ | ||
return a.GetHashCode() == b.GetHashCode(); | ||
} | ||
|
||
[Benchmark] | ||
[ArgumentsSource(nameof(Operands))] | ||
public int CompareTo(Mass a, Mass b) | ||
{ | ||
return a.CompareTo(b); | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
UnitsNet.Benchmark/Conversions/FromString/ParseUnitBenchmarks.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
using System; | ||
using BenchmarkDotNet.Attributes; | ||
using BenchmarkDotNet.Jobs; | ||
using UnitsNet.Units; | ||
|
||
namespace UnitsNet.Benchmark.Conversions.FromString; | ||
|
||
[MemoryDiagnoser] | ||
[SimpleJob(RuntimeMoniker.Net48)] | ||
[SimpleJob(RuntimeMoniker.Net80)] | ||
public class ParseUnitBenchmarks | ||
{ | ||
private readonly Random _random = new(42); | ||
private string[] _densityUnits; | ||
private string[] _massUnits; | ||
private string[] _pressureUnits; | ||
private string[] _volumeFlowUnits; | ||
private string[] _volumeUnits = []; | ||
|
||
[Params(1000)] | ||
public int NbAbbreviations { get; set; } | ||
|
||
[GlobalSetup(Target = nameof(ParseMassUnit))] | ||
public void PrepareMassUnits() | ||
{ | ||
_massUnits = _random.GetItems(["mg", "g", "kg", "lbs", "Mlbs"], NbAbbreviations); | ||
} | ||
|
||
[GlobalSetup(Target = nameof(ParseVolumeUnit))] | ||
public void PrepareVolumeUnits() | ||
{ | ||
_volumeUnits = _random.GetItems(["ml", "l", "L", "cm³", "m³"], NbAbbreviations); | ||
} | ||
|
||
[GlobalSetup(Target = nameof(ParseDensityUnit))] | ||
public void PrepareDensityUnits() | ||
{ | ||
_densityUnits = _random.GetRandomAbbreviations<DensityUnit>(UnitsNetSetup.Default.UnitAbbreviations, NbAbbreviations); | ||
} | ||
|
||
[GlobalSetup(Target = nameof(ParsePressureUnit))] | ||
public void PreparePressureUnits() | ||
{ | ||
_pressureUnits = _random.GetRandomAbbreviations<PressureUnit>(UnitsNetSetup.Default.UnitAbbreviations, NbAbbreviations); | ||
} | ||
|
||
[GlobalSetup(Target = nameof(ParseVolumeFlowUnit))] | ||
public void PrepareVolumeFlowUnits() | ||
{ | ||
_volumeFlowUnits = _random.GetRandomAbbreviations<VolumeFlowUnit>(UnitsNetSetup.Default.UnitAbbreviations, NbAbbreviations); | ||
} | ||
|
||
[Benchmark(Baseline = true)] | ||
public MassUnit ParseMassUnit() | ||
{ | ||
MassUnit unit = default; | ||
foreach (var unitToParse in _massUnits) | ||
{ | ||
unit = Mass.ParseUnit(unitToParse); | ||
} | ||
|
||
return unit; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public VolumeUnit ParseVolumeUnit() | ||
{ | ||
VolumeUnit unit = default; | ||
foreach (var unitToParse in _volumeUnits) | ||
{ | ||
unit = Volume.ParseUnit(unitToParse); | ||
} | ||
|
||
return unit; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public DensityUnit ParseDensityUnit() | ||
{ | ||
DensityUnit unit = default; | ||
foreach (var unitToParse in _densityUnits) | ||
{ | ||
unit = Density.ParseUnit(unitToParse); | ||
} | ||
|
||
return unit; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public PressureUnit ParsePressureUnit() | ||
{ | ||
PressureUnit unit = default; | ||
foreach (var unitToParse in _pressureUnits) | ||
{ | ||
unit = Pressure.ParseUnit(unitToParse); | ||
} | ||
|
||
return unit; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public VolumeFlowUnit ParseVolumeFlowUnit() | ||
{ | ||
VolumeFlowUnit unit = default; | ||
foreach (var unitToParse in _volumeFlowUnits) | ||
{ | ||
unit = VolumeFlow.ParseUnit(unitToParse); | ||
} | ||
|
||
return unit; | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
UnitsNet.Benchmark/Conversions/FromString/TryParseInvalidUnitBenchmarks.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// Licensed under MIT No Attribution, see LICENSE file at the root. | ||
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet. | ||
|
||
using System; | ||
using System.Linq; | ||
using System.Text; | ||
using BenchmarkDotNet.Attributes; | ||
using BenchmarkDotNet.Jobs; | ||
using UnitsNet.Units; | ||
|
||
namespace UnitsNet.Benchmark.Conversions.FromString; | ||
|
||
[MemoryDiagnoser] | ||
[SimpleJob(RuntimeMoniker.Net48)] | ||
[SimpleJob(RuntimeMoniker.Net80)] | ||
public class TryParseInvalidUnitBenchmarks | ||
{ | ||
private readonly Random _random = new(42); | ||
private string[] _invalidUnits = []; | ||
|
||
[Params(1000)] | ||
public int NbAbbreviations { get; set; } | ||
|
||
[GlobalSetup] | ||
public void Setup() | ||
{ | ||
_invalidUnits = Enumerable.Range(0, NbAbbreviations).Select(_ => GenerateInvalidUnit()).ToArray(); | ||
} | ||
|
||
private string GenerateInvalidUnit() | ||
{ | ||
var sb = new StringBuilder(); | ||
var length = _random.Next(1, 10); | ||
for (var i = 0; i < length; i++) | ||
{ | ||
sb.Append((char)_random.Next('a', 'z')); | ||
} | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
|
||
[Benchmark(Baseline = true)] | ||
public bool TryParseMassUnit() | ||
{ | ||
var success = true; | ||
foreach (var unitToParse in _invalidUnits) | ||
{ | ||
success = Mass.TryParseUnit(unitToParse, out MassUnit _); | ||
} | ||
|
||
return success; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public bool TryParseVolumeUnit() | ||
{ | ||
var success = true; | ||
foreach (var unitToParse in _invalidUnits) | ||
{ | ||
success = Volume.TryParseUnit(unitToParse, out _); | ||
} | ||
|
||
return success; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public bool ParseDensityUnit() | ||
{ | ||
var success = true; | ||
foreach (var unitToParse in _invalidUnits) | ||
{ | ||
success = Density.TryParseUnit(unitToParse, out _); | ||
} | ||
|
||
return success; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public bool ParsePressureUnit() | ||
{ | ||
var success = true; | ||
foreach (var unitToParse in _invalidUnits) | ||
{ | ||
success = Pressure.TryParseUnit(unitToParse, out _); | ||
} | ||
|
||
return success; | ||
} | ||
|
||
[Benchmark(Baseline = false)] | ||
public bool ParseVolumeFlowUnit() | ||
{ | ||
var success = true; | ||
foreach (var unitToParse in _invalidUnits) | ||
{ | ||
success = VolumeFlow.TryParseUnit(unitToParse, out _); | ||
} | ||
|
||
return success; | ||
} | ||
} |
Oops, something went wrong.