stedc_levels_plan.hh
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <cstdint>
6#include <limits>
7
8namespace batchlas {
9
10// Level-synchronous STEDC merge tree; own header so tests can assert on it (a bad leaf is only slow).
12 int64_t leaf = 0; // leaf sub-problem size
13 int32_t levels = 0; // merge levels; the tree has 2^levels leaves
14 int64_t padded_n = 0; // leaf << levels
15};
16
17// Merge tree for an n x n tridiagonal and the tuned leaf threshold; `levels == 0` means
18// no level plan applies (the caller falls back to the recursive driver).
19inline StedcLevelPlan plan_stedc_levels(int64_t n, int64_t threshold) {
20 StedcLevelPlan plan{n, 0, n};
21 if (n <= threshold || threshold <= 0) {
22 return plan;
23 }
24 // HARD CAP, not a preference: the leaf never exceeds the threshold (the sub-group
25 // width; steqr_cta throws above it and one step over costs ~14x). Below the cap,
26 // prefer the tree that pads least; weighting width against padding regressed syev.
27 // evidence: docs/perf/stedc.md#stedc-the-leaf-cap-at-the-sub-group-width
28 const int64_t lo = std::max<int64_t>(2, threshold / 2);
29 const int64_t hi = threshold;
30 double best_score = std::numeric_limits<double>::max();
31 for (int32_t L = 1; L <= 24; ++L) {
32 const int64_t k = int64_t(1) << L;
33 if (k > n) break;
34 const int64_t leaf = (n + k - 1) / k;
35 if (leaf > hi) continue;
36 if (leaf < lo) break;
37 const int64_t N = leaf * k;
38 const double score = static_cast<double>(N - n) / static_cast<double>(n)
39 + 1e-3 * std::abs(static_cast<double>(leaf - threshold)) / static_cast<double>(threshold);
40 if (score < best_score) {
41 best_score = score;
42 plan = StedcLevelPlan{leaf, L, N};
43 }
44 }
45 return plan;
46}
47
48} // namespace batchlas
StedcLevelPlan plan_stedc_levels(int64_t n, int64_t threshold)