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
23 changes: 16 additions & 7 deletions Sources/AngouriMath/Core/Transformations/Saturation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,22 @@ internal static class Saturation
/// one, and that is a measurement rather than a preference.</b> It reads like the value a
/// ceiling should refuse — it means the rule's growth was not judged, because its
/// replacement is code rather than a written pattern, so admitting it accepts a rewrite
/// nobody measured. But it is where the rules are: of the sound rules in
/// <see cref="MatchedRules"/>, <b>26 collect, 17 rearrange, 9 expand and 270 are
/// unjudged</b>. A ceiling that refuses the fourth value refuses 84% of the library, and
/// what is left cannot do much — over six expression pairs equal only through a larger
/// intermediate form, the <see cref="RewriteRuleGrowth.Rearranges"/> ceiling proved two,
/// and <see cref="RewriteRuleGrowth.Expands"/> — all nine expanding rules added — proved
/// <i>the same two</i>. The third was proved only with the unjudged rules admitted.
/// nobody measured. But it is where the rules are: of the 324 rules in
/// <see cref="MatchedRules"/>, <b>97 collect, 45 rearrange, 30 expand and 152 are
/// unjudged</b>. A ceiling that refuses the fourth value still refuses 47% of the library,
/// and what is left could not do much when this was written — over six expression pairs
/// equal only through a larger intermediate form, the
/// <see cref="RewriteRuleGrowth.Rearranges"/> ceiling proved two, and
/// <see cref="RewriteRuleGrowth.Expands"/> proved <i>the same two</i>. The third was proved
/// only with the unjudged rules admitted.
/// </para>
/// <para>
/// <b>Those figures moved and this paragraph did not.</b> It read "26 collect, 17
/// rearrange, 9 expand and 270 are unjudged", and 84% — measured before the growth
/// declarations went in, which took the unjudged count from 261 to 152. The argument
/// survives the correction and the arithmetic in it did not, which is the reason to state
/// counts rather than a conclusion drawn from them. <c>RuleAuthoringGuideTest</c> holds all
/// four of these now, so the next time they move this remark fails with them.
/// </para>
/// <para>
/// So the dial that matters is not how far a rule may enlarge; it is whether rules nobody
Expand Down
64 changes: 64 additions & 0 deletions Sources/AngouriMath/Docs/WhatsNew/version_performance_control.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,70 @@ honest reason -- a compiled delegate over `Complex` has nothing to put on the he

---

## The 1915th, and every release beside it on one machine

The first column measured by `Sources/Utils/benchmark_key_commits.sh` reaching all five entries in
`key-commits.txt`. Every figure below is the same benchmark against a different kernel, run on one
machine within one hour — which is what the four release-pair sections further down had to
approximate by measuring two commits at a time.

`v2.1.0` and `v2.2.0` are in it for the first time. They did not build before #1178: the benchmark
project carried cases reaching internals those kernels had not exposed, so the whole project failed
to compile and took the row with it, while the case that runs uses nothing but the public API.

### Allocation

| benchmark | v2.1.0 | v2.2.0 | v2.3.0 | v2.4.0 | 1915th |
|---|--:|--:|--:|--:|--:|
| `CompileEasy` | 16,519 | 16,309 | 16,206 | 11,003 | 10,970 |
| `CompileHard` | 38,542 | 38,089 | 38,355 | 20,396 | 20,434 |
| `Derivate` | 52,823 | 52,823 | 52,823 | 52,823 | 52,823 |
| `EvalTrig` | 1,341,377 | 1,341,377 | 1,341,377 | 1,341,377 | 1,341,377 |
| `EvalTrigPrecise` | 12,742,205 | 12,742,205 | 12,742,205 | 12,742,205 | 12,742,205 |
| `ParseEasy` | 18,061 | 18,061 | 18,061 | 18,109 | 18,104 |
| `ParseHard` | 3,498,137 | 3,498,137 | 3,522,409 | 3,522,457 | 3,531,201 |
| `SimplifyEasy` | 128,564 | 128,564 | 128,100 | 128,100 | 128,100 |
| `SimplifyHard` | 3,733,136,616 | 3,749,449,104 | 3,620,748,288 | 3,632,015,744 | 3,655,695,192 |
| `SolveEasy` | 20,220,106 | 20,234,998 | 8,852,269 | 8,853,671 | 8,853,834 |
| `SolveEasyMedium` | 80,184 | 95,873 | 95,791 | 97,193 | 97,335 |
| `SolveHard` | 1,356,525,608 | 1,486,580,536 | 1,431,859,752 | 1,446,799,616 | 1,450,058,720 |
| `SolveMedium` | 554,368 | 658,259 | 658,099 | 661,963 | 662,923 |
| `SolveMediumHard` | 155,191,480 | 171,395,096 | 162,305,664 | 164,549,808 | 165,055,344 |

Bytes allocated. `EvalEasy`, `RunEasy`, `RunMedium` and `RunHard` allocate nothing in every column
and are left out.

**Since 2.4.0, the Simplify and Solve family is up between 0.15% and 0.65%** — `SimplifyHard`
+0.65%, `SolveMediumHard` +0.31%, `SolveHard` +0.23%. Small, consistent in sign, and real: see the
next section for why 0.65% is far above the noise on those particular rows. It is well inside
`PerformanceGate`'s 3% and is not a reason to hold a release; it is a reason not to claim the period
was free. The likeliest cause is the definedness conditions added in #1176 and #1177, which give
every cancelled quotient a larger condition tree to carry.

`CompileEasy` and `CompileHard` are flat against 2.4.0 and roughly **half** what they were at 2.3.0.

### The determinism claim, measured

This file says allocation is deterministic — "the same commit measured twice gives the same bytes".
The five columns above were run **twice**, and that is true for the large benchmarks and false for
the small compile ones:

| same commit, two runs | run 1 | run 2 | apart |
|---|--:|--:|--:|
| `SolveHard` @ v2.1.0 | 1,356,524,520 | 1,356,525,608 | **0.00008%** |
| `SimplifyHard` @ v2.1.0 | 3,733,177,488 | 3,733,136,616 | **0.001%** |
| `CompileEasy` @ v2.1.0 | 16,280 | 16,519 | **1.47%** |
| `CompileEasy` @ v2.3.0 | 16,510 | 16,206 | **1.84%** |

So the rule this file states holds where it matters most and needs a rider: **the compile
benchmarks have an allocation floor of about 2%.** That is worth knowing precisely because
`PerformanceGate` fails at 3% — for `CompileEasy` that is one and a half noise-widths of margin, not
the comfortable threshold the number suggests. A `CompileEasy` allocation move under 2% is not
evidence; the same move on `SolveHard` is evidence a thousand times over.

Timings from the same run are in the generated table and are deliberately not reproduced here, for
the reason the next section gives.

## The 1844th: what this file's timings can and cannot support

The column for 2.4.0. Seventy-five commits from the 1769th, carrying the rule-set exchange --
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ public void ReplacementAPatternOrCode()
Stated(152, rules.Count(rule => rule.Growth is RewriteRuleGrowth.Unknown),
"how many rules sit at Unknown growth");

// The rest of the census, because `Saturation.RulesUpTo` argues from it in prose and
// the figures it quoted had gone stale by a factor of four -- "26 collect, 17
// rearrange, 9 expand and 270 unjudged", measured before the growth declarations
// went in. The argument survived; the arithmetic did not. A number a remark reasons
// from belongs somewhere that fails when it moves.
Stated(97, rules.Count(rule => rule.Growth is RewriteRuleGrowth.Collects),
"how many rules are declared Collects");
Stated(45, rules.Count(rule => rule.Growth is RewriteRuleGrowth.Rearranges),
"how many rules are declared Rearranges");
Stated(30, rules.Count(rule => rule.Growth is RewriteRuleGrowth.Expands),
"how many rules are declared Expands");

// And the two the document names. By their own names rather than by what the prose
// calls them: the first is `squared-sine-and-cosine-of-one-argument-sum-to-one` and
// the prose calls it the Pythagorean identity, which is right and is not what to
Expand Down
11 changes: 11 additions & 0 deletions Sources/Utils/benchmark_key_commits.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ echo "measuring:"; echo "$commits" | sed 's/^/ /'

for commit in $commits; do
resolved=$(git -C "$repository" rev-parse --short "$commit" 2>/dev/null)

# A branch name resolves to whatever this checkout's copy of it points at, which is not
# necessarily the tip. In a worktree the local `master` belongs to whichever checkout last
# moved it: this measured a `master` five days behind its remote and reported it as `master`,
# and only the SHA printed beside the row gave it away. Say so rather than quietly measure
# the wrong commit.
upstream=$(git -C "$repository" rev-parse --short "origin/$commit" 2>/dev/null)
if [ -n "$upstream" ] && [ "$upstream" != "$resolved" ]; then
echo "=== $commit: local is $resolved, origin/$commit is $upstream -- measuring the local one" >&2
echo " put the SHA you mean in key-commits.txt if that is not what you want" >&2
fi
if [ -z "$resolved" ]; then
echo "=== $commit: not a commit in this repository"
echo "unresolved" > "$results/$commit.status"
Expand Down
Loading