Skip to content

Commit 253b5a8

Browse files
Benchmark trigonometry against precision, and stop discarding the allocations (#167) (#850)
Both halves of what #167 asked for. CommonFunctionsInterVersion had no trigonometric case at any precision. EvalTrig and EvalTrigPrecise evaluate sin(1) + cos(1) + tan(1) at the default hundred digits and at five hundred. Both build their nodes on every call: an Entity caches its own Evaled, so the obvious form of this benchmark measures a dictionary lookup rather than any arithmetic. Which is what EvalEasy has been measuring since that cache landed, and why it reads two nanoseconds. Left as it is so the column history stays comparable, with the trap written down. The class has carried [MemoryDiagnoser] all along, so the allocation figure was collected on every run and then dropped, because Program.cs asked for Mean, Error and StdDev and nothing else. It now asks for Allocated too.
1 parent 5a55cb5 commit 253b5a8

3 files changed

Lines changed: 50 additions & 1 deletion

File tree

‎Sources/AngouriMath/Docs/WhatsNew/version_performance_control.md‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,32 @@ on a path that does not exist and had not run since 2026-01-02 -- ninety-eight m
2121
requests went unmeasured. Fixed in
2222
[#775](https://github.com/asc-community/AngouriMath/issues/775).
2323

24+
**Allocation is reported alongside the timings** from the column after the 1620th. The
25+
benchmark class has carried `[MemoryDiagnoser]` all along, so the figure was measured on every
26+
run and then discarded, because the reporting code asked for `Mean`, `Error` and `StdDev` and
27+
nothing else. Asked for by [#167](https://github.com/asc-community/AngouriMath/issues/167).
28+
29+
**`EvalTrig` and `EvalTrigPrecise`** are new in the same column and are the other half of
30+
[#167](https://github.com/asc-community/AngouriMath/issues/167): what arbitrary precision costs
31+
in trigonometry. Both evaluate `sin(1) + cos(1) + tan(1)`, the first at the default hundred
32+
digits and the second at five hundred. Measured while writing them, on one machine, so treat
33+
these as the shape rather than as the numbers:
34+
35+
| digits | per evaluation |
36+
|---|---|
37+
| 100 (default) | 3.8 ms |
38+
| 200 | 10.2 ms |
39+
| 500 | 25.4 ms |
40+
| 1000 | 146 ms |
41+
42+
**Read `EvalEasy` with care.** It evaluates one `Entity` instance, and an `Entity` caches its
43+
own `Evaled`, so from the moment that cache landed the row stopped measuring evaluation and
44+
started measuring a lookup -- which is what the fall to single-digit nanoseconds is, not a
45+
speed-up of the arithmetic. Measured directly: a hundred thousand evaluations of one instance
46+
take a millisecond in total, while a thousand evaluations of freshly built nodes take a second.
47+
The row is kept as it is so the column history stays comparable, and the two trigonometric
48+
benchmarks build their expression afresh on every call for exactly this reason.
49+
2450
| Method | [331st](https://github.com/asc-community/AngouriMath/commit/10e6e5a90e7270336b68dc5fd6aa36f3e0e65d2b) | [380th](https://github.com/asc-community/AngouriMath/commit/73ae36488ddb863c1d6f35db5ed2f5dcf1484a26) | [391st](https://github.com/asc-community/AngouriMath/commit/c7e08e6936bfdc2373377bec81ffd160e406244f) | [410th](https://github.com/asc-community/AngouriMath/commit/20814936bc740a9f410af4a4368e9895eab7aaf7) | [483rd](https://github.com/asc-community/AngouriMath/commit/355963dcdf0ff9da568e9f1144ad2b7b68c19584) | [520th](https://github.com/asc-community/AngouriMath/commit/70aa71acb73307c9f7df0aac006faae31b06058c) | [690th](https://github.com/asc-community/AngouriMath/commit/5cc894939cb3657f0aa7ef5a25fd55011058929f) | [826th](https://github.com/asc-community/AngouriMath/commit/87e33ec3590a95dd4ec59ff5c1f77064a64196d1) | [914th](https://github.com/asc-community/AngouriMath/commit/6134338df083a908369b6bcfb69e70a4269ec51b) | [920th](https://github.com/asc-community/AngouriMath/commit/501a0a3a9b2e07cddf92c4446b73ad6e2748253a) | [1034th](https://github.com/asc-community/AngouriMath/commit/a3f48b47795b2dc2b3435152989a6e15639a65b4) | [1066th](https://github.com/asc-community/AngouriMath/commit/a33746651f56a380b6c17913aa844f162f258d8c) | [1090th](https://github.com/asc-community/AngouriMath/commit/9530c5b04484e98023941f7693bbeb1a3282cee6) | [1446th](https://github.com/asc-community/AngouriMath/commit/2abb2b537c03977281f3fc2cab1da2c78c36a5f5) | [1620th](https://github.com/asc-community/AngouriMath/commit/e05d71797f53a9ac7dbdad6075cd7302a91036e7) |
2551
|---------------- |--------------:|---------------:|---------------:|--------------:|----------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|-----------------:|--------------:|
2652
| ParseEasy | 28,599 | 73,669 | 134,120 | 44,328 | 54,675 | 21,722 | 32,212 | 32,138 | 34,702 | 32,199 | 33,008 | 27,483 | 33,043 | 34,664 | 11,760 ns |

‎Sources/Tests/DotnetBenchmark/CommonFunctionsInterVersion.cs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using AngouriMath.Extensions;
1212
using BenchmarkDotNet.Attributes;
1313
using BenchmarkDotNet.Exporters.Csv;
14+
using PeterO.Numbers;
1415

1516
namespace DotnetBenchmark
1617
{
@@ -52,9 +53,29 @@ public class CommonFunctionsInterVersion
5253
private static readonly Entity toSolveHard = "(sin(cos(x) + sin(x) + c) + sqr(sin(cos(x) + sin(x) + c)) + a)4 + (sin(cos(x) + sin(x) + c) + sqr(sin(cos(x) + sin(x) + c)) + a) + b";
5354

5455
// Testing evaluation
56+
// NB: evalEasy is one instance and an Entity caches its own Evaled, so from the
57+
// moment that cache was added this stopped measuring evaluation and started
58+
// measuring a dictionary lookup -- which is why the row reads single-digit
59+
// nanoseconds. Kept as it is so the column history stays comparable; the two
60+
// benchmarks below build their expression afresh each call for that reason.
5561
[Benchmark] public void EvalEasy() => evalEasy.EvalNumerical();
5662
private static readonly Entity evalEasy = "1 + 2 + log(2, 3) + sqrt(4) - 4 ^ 7 + e * pi";
5763

64+
// Testing trigonometry against precision, which is what #167 asked for. Building
65+
// the nodes is included in the measurement and costs microseconds against
66+
// milliseconds of arithmetic, so it does not move the number; evaluating a cached
67+
// instance instead would move it to zero.
68+
[Benchmark] public void EvalTrig()
69+
=> (MathS.Sin(1) + MathS.Cos(1) + MathS.Tan(1)).EvalNumerical();
70+
71+
[Benchmark] public void EvalTrigPrecise()
72+
{
73+
using var _ = MathS.Settings.DecimalPrecisionContext.Set(fiveHundredDigits);
74+
(MathS.Sin(1) + MathS.Cos(1) + MathS.Tan(1)).EvalNumerical();
75+
}
76+
private static readonly EContext fiveHundredDigits =
77+
new(500, ERounding.HalfUp, -500, 5000, false);
78+
5879
// Testing compilation
5980
[Benchmark] public void CompileEasy() => toCompileEasy.Compile<Complex, Complex>("x");
6081
private static readonly Entity toCompileEasy = "x + x / 2 + sin(x)";

‎Sources/Tests/DotnetBenchmark/Program.cs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ public static void Main(string[] args)
7676
arg switch
7777
{
7878
"RAMUsageTest" => GetReportByBenchmark(typeof(RAMUsageTest), "Gen 0", "Gen 1", "Gen 2", "Allocated"),
79-
"CommonFunctionsInterVersion" => GetReportByBenchmark(typeof(CommonFunctionsInterVersion), "Mean", "Error", "StdDev"),
79+
// Allocated: the class has carried [MemoryDiagnoser] all along, so the
80+
// figure was being collected on every run and then dropped here.
81+
"CommonFunctionsInterVersion" => GetReportByBenchmark(typeof(CommonFunctionsInterVersion), "Mean", "Error", "StdDev", "Allocated"),
8082
// Allocated as well as Mean: the regressions this one exists to catch
8183
// show up in allocation and are invisible in the timings.
8284
"TransformationLayer" => GetReportByBenchmark(typeof(TransformationLayer), "Mean", "Error", "StdDev", "Allocated"),

0 commit comments

Comments
 (0)