-
Notifications
You must be signed in to change notification settings - Fork 344
Description
I was most surprised by our experience in #837, so I've done a little bit of bench-marking of the relative performance of various ways Duration does some of its stuff - and also threw-in Decimal as an alternative to BigInteger.
The results look like this:
Method | Mean | Error | StdDev | Gen 0 | Allocated |
------------------------------ |----------:|-----------:|----------:|-------:|----------:|
DurationFromNanosecondsLong | 39.98 ns | 0.8061 ns | 0.8626 ns | - | 0 B |
DurationFromNanosecondsBigInt | 518.35 ns | 10.2473 ns | 9.0840 ns | 0.0391 | 124 B |
ConstructBigInt | 493.81 ns | 4.9034 ns | 4.3467 ns | 0.0448 | 144 B |
ConstructLong | 36.76 ns | 0.5417 ns | 0.5067 ns | - | 0 B |
ConstructDecimal | 254.47 ns | 2.8259 ns | 2.6433 ns | - | 0 B |
The two 'DurationFromxxx' methods are using NodaTime's Duration constructors, and the three 'Construct' methods are really the innards of the Duration.FromNanoseconds methods, implemented with BigInt, long and Decimal respectively.
I have not bothered to check any of this for correctness - obviously BigInteger goes places that long doesn't, but it's very slow getting there.
I guess, though I haven't tried it, that many uses of BigInteger could be got rid of if there was a desire to do this - this would be a very direct trade-off of clean, simple code against performance. With a 12:1 perf advantage this might feel worthwhile?
This isn't just pointless micro-bench-marking, there are clearly situations that run through these paths are lot, and even if in #837 the threshold between fast and slow gets tweaked to avoid the slow path more often, it's still going to be very slow when you do hit it.