Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Sources/AngouriMath/Docs/WhatsNew/version_performance_control.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,32 @@ on a path that does not exist and had not run since 2026-01-02 -- ninety-eight m
requests went unmeasured. Fixed in
[#775](https://github.com/asc-community/AngouriMath/issues/775).

**Allocation is reported alongside the timings** from the column after the 1620th. The
benchmark class has carried `[MemoryDiagnoser]` all along, so the figure was measured on every
run and then discarded, because the reporting code asked for `Mean`, `Error` and `StdDev` and
nothing else. Asked for by [#167](https://github.com/asc-community/AngouriMath/issues/167).

**`EvalTrig` and `EvalTrigPrecise`** are new in the same column and are the other half of
[#167](https://github.com/asc-community/AngouriMath/issues/167): what arbitrary precision costs
in trigonometry. Both evaluate `sin(1) + cos(1) + tan(1)`, the first at the default hundred
digits and the second at five hundred. Measured while writing them, on one machine, so treat
these as the shape rather than as the numbers:

| digits | per evaluation |
|---|---|
| 100 (default) | 3.8 ms |
| 200 | 10.2 ms |
| 500 | 25.4 ms |
| 1000 | 146 ms |

**Read `EvalEasy` with care.** It evaluates one `Entity` instance, and an `Entity` caches its
own `Evaled`, so from the moment that cache landed the row stopped measuring evaluation and
started measuring a lookup -- which is what the fall to single-digit nanoseconds is, not a
speed-up of the arithmetic. Measured directly: a hundred thousand evaluations of one instance
take a millisecond in total, while a thousand evaluations of freshly built nodes take a second.
The row is kept as it is so the column history stays comparable, and the two trigonometric
benchmarks build their expression afresh on every call for exactly this reason.

| 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) |
|---------------- |--------------:|---------------:|---------------:|--------------:|----------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|-----------------:|--------------:|
| 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 |
Expand Down
21 changes: 21 additions & 0 deletions Sources/Tests/DotnetBenchmark/CommonFunctionsInterVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using AngouriMath.Extensions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Exporters.Csv;
using PeterO.Numbers;

namespace DotnetBenchmark
{
Expand Down Expand Up @@ -52,9 +53,29 @@ public class CommonFunctionsInterVersion
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";

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

// Testing trigonometry against precision, which is what #167 asked for. Building
// the nodes is included in the measurement and costs microseconds against
// milliseconds of arithmetic, so it does not move the number; evaluating a cached
// instance instead would move it to zero.
[Benchmark] public void EvalTrig()
=> (MathS.Sin(1) + MathS.Cos(1) + MathS.Tan(1)).EvalNumerical();

[Benchmark] public void EvalTrigPrecise()
{
using var _ = MathS.Settings.DecimalPrecisionContext.Set(fiveHundredDigits);
(MathS.Sin(1) + MathS.Cos(1) + MathS.Tan(1)).EvalNumerical();
}
private static readonly EContext fiveHundredDigits =
new(500, ERounding.HalfUp, -500, 5000, false);

// Testing compilation
[Benchmark] public void CompileEasy() => toCompileEasy.Compile<Complex, Complex>("x");
private static readonly Entity toCompileEasy = "x + x / 2 + sin(x)";
Expand Down
4 changes: 3 additions & 1 deletion Sources/Tests/DotnetBenchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ public static void Main(string[] args)
arg switch
{
"RAMUsageTest" => GetReportByBenchmark(typeof(RAMUsageTest), "Gen 0", "Gen 1", "Gen 2", "Allocated"),
"CommonFunctionsInterVersion" => GetReportByBenchmark(typeof(CommonFunctionsInterVersion), "Mean", "Error", "StdDev"),
// Allocated: the class has carried [MemoryDiagnoser] all along, so the
// figure was being collected on every run and then dropped here.
"CommonFunctionsInterVersion" => GetReportByBenchmark(typeof(CommonFunctionsInterVersion), "Mean", "Error", "StdDev", "Allocated"),
// Allocated as well as Mean: the regressions this one exists to catch
// show up in allocation and are invisible in the timings.
"TransformationLayer" => GetReportByBenchmark(typeof(TransformationLayer), "Mean", "Error", "StdDev", "Allocated"),
Expand Down
Loading