1#include <enforce.h>
2#include <global.h>
3#include <math/fixed.h>
4#include <math/min_max.h>
5#include <math/range.h>
6#include <scaled_param.h>
7#include <smp/core.h>
8#include <string.h>
9
10static size_t geom_interp(size_t a, size_t b, fx32_32_t t) {
11 if (t <= 0)
12 return a;
13 if (t >= FX_ONE)
14 return b;
15 if (a == b)
16 return a;
17
18 enforce_precond(a <= INT64_MAX && b <= INT64_MAX);
19 int64_t lower = (int64_t) a;
20 int64_t upper = (int64_t) b;
21 fx32_32_t ln_a = fx_ln(x: fx_from_int(x: lower));
22 fx32_32_t ln_b = fx_ln(x: fx_from_int(x: upper));
23 fx32_32_t result = fx_exp(x: fx_add(a: ln_a, b: fx_mul(a: t, b: fx_sub(a: ln_b, b: ln_a))));
24
25 int64_t val = fx_to_int(x: result);
26 val = CLAMP(val, lower, upper);
27 return (size_t) val;
28}
29
30static size_t linear_interp(size_t a, size_t b, fx32_32_t t) {
31 if (t <= 0)
32 return a;
33 if (t >= FX_ONE)
34 return b;
35 if (a == b)
36 return a;
37
38 enforce_precond(a <= INT64_MAX && b <= INT64_MAX);
39 int64_t lower = (int64_t) a;
40 int64_t upper = (int64_t) b;
41 fx32_32_t span = fx_from_int(x: upper - lower);
42 int64_t val = fx_to_int(x: fx_add(a: fx_from_int(x: lower), b: fx_mul(a: t, b: span)));
43 val = CLAMP(val, lower, upper);
44 return (size_t) val;
45}
46
47static size_t scale_log(fx32_32_t value, size_t min_val, size_t def_val,
48 size_t max_val) {
49 value = fx_clamp(x: value, lo: 0, FX_ONE);
50 if (value == FX_HALF)
51 return def_val;
52 if (value < FX_HALF)
53 return geom_interp(a: min_val, b: def_val, t: value << 1);
54 return geom_interp(a: def_val, b: max_val, t: (value - FX_HALF) << 1);
55}
56
57static size_t scale_linear(fx32_32_t value, size_t min_val, size_t def_val,
58 size_t max_val) {
59 value = fx_clamp(x: value, lo: 0, FX_ONE);
60 if (value == FX_HALF)
61 return def_val;
62 if (value < FX_HALF)
63 return linear_interp(a: min_val, b: def_val, t: value << 1);
64 return linear_interp(a: def_val, b: max_val, t: (value - FX_HALF) << 1);
65}
66
67static size_t scale_core_multiplier(fx32_32_t value, size_t min_val,
68 size_t def_val, size_t max_val) {
69 size_t per_core = scale_linear(value, min_val, def_val, max_val);
70 return per_core * (global.core_count > 0 ? global.core_count : 1);
71}
72
73static const scaling_fn_t scale_lut[SCALE_CURVE_MAX] = {
74 [SCALE_NONE] = NULL,
75 [SCALE_PIECEWISE_LOG] = scale_log,
76 [SCALE_PIECEWISE_LINEAR] = scale_linear,
77 [SCALE_CORE_MULTIPLIER] = scale_core_multiplier,
78 [SCALE_CUSTOM] = NULL,
79};
80
81size_t scaled_param_eval(const struct scaled_param *desc, fx32_32_t value) {
82 if (!desc || desc->curve == SCALE_NONE)
83 return 0;
84
85 if (desc->curve == SCALE_CUSTOM)
86 return desc->custom_scale
87 ? desc->custom_scale(value, desc->min_val, desc->def_val,
88 desc->max_val)
89 : desc->def_val;
90
91 enforce(IN_RANGE(desc->curve, SCALE_NONE, SCALE_CUSTOM));
92 scaling_fn_t fn = scale_lut[desc->curve];
93 return fn ? fn(value, desc->min_val, desc->def_val, desc->max_val)
94 : desc->def_val;
95}
96
97size_t scaled_param_format(const struct scaled_param *desc, fx32_32_t value,
98 size_t scaled_val, char *buf, size_t cap) {
99 if (!desc || desc->curve == SCALE_NONE)
100 return 0;
101 if (desc->custom_print)
102 return desc->custom_print(value, scaled_val, buf, cap);
103 return snprintf(buf, cap, "%zu %s", scaled_val,
104 desc->unit ? desc->unit : "units");
105}
106