#include <scx/common.bpf.h>
#include <bpf_arena_common.bpf.h>
#include <bpf_arena_spin_lock.h>
#include <lib/ravg.h>
static const u64 ravg_full_sum[] = {
524288, 786432, 917504, 983040,
1015808, 1032192, 1040384, 1044480,
1046528, 1047552, 1048064, 1048320,
1048448, 1048512, 1048544, 1048560,
1048568, 1048572, 1048574, 1048575,
};
static const int ravg_full_sum_len = sizeof(ravg_full_sum) / sizeof(ravg_full_sum[0]);
__weak
int ravg_accumulate(struct ravg_data *rd, u64 new_val, u64 now,
u32 half_life)
{
u32 cur_seq, val_seq, seq_delta;
if (now < rd->val_at)
now = rd->val_at;
cur_seq = now / half_life;
val_seq = rd->val_at / half_life;
seq_delta = cur_seq - val_seq;
if (seq_delta > 0) {
rd->old = ravg_decay(rd->old, seq_delta);
ravg_add(&rd->old, ravg_decay(rd->cur, seq_delta));
rd->cur = 0;
}
if (!rd->val)
goto out;
if (seq_delta > 0) {
u32 dur;
dur = ravg_normalize_dur(half_life - rd->val_at % half_life, half_life);
ravg_add(&rd->old, rd->val * ravg_decay(dur, seq_delta));
if (seq_delta > 1) {
u32 idx = seq_delta - 2;
if (idx >= ravg_full_sum_len)
idx = ravg_full_sum_len - 1;
ravg_add(&rd->old, rd->val * ravg_full_sum[idx]);
}
rd->cur += rd->val * ravg_normalize_dur(now % half_life,
half_life);
} else {
rd->cur += rd->val * ravg_normalize_dur(now - rd->val_at,
half_life);
}
out:
if (new_val >= 1LLU << RAVG_VAL_BITS)
rd->val = (1LLU << RAVG_VAL_BITS) - 1;
else
rd->val = new_val;
rd->val_at = now;
return 0;
}
static inline
u64 u64_x_u32_rshift(u64 a, u32 b, u32 rshift)
{
const u64 mask32 = (u32)-1;
u64 al = a & mask32;
u64 ah = (a & (mask32 << 32)) >> 32;
al *= b;
ah *= b;
al >>= rshift;
if (rshift <= 32)
ah <<= 32 - rshift;
else
ah >>= rshift - 32;
return al + ah;
}
__weak
int ravg_scale(struct ravg_data *rd, u32 mult, u32 rshift)
{
rd->val = u64_x_u32_rshift(rd->val, mult, rshift);
rd->old = u64_x_u32_rshift(rd->old, mult, rshift);
rd->cur = u64_x_u32_rshift(rd->cur, mult, rshift);
return 0;
}
__weak
u64 ravg_read(struct ravg_data *rd, u64 now, u64 half_life)
{
struct ravg_data trd;
u32 elapsed;
if (now < rd->val_at)
now = rd->val_at;
elapsed = now % half_life;
trd = *rd;
rd = &trd;
ravg_accumulate(rd, 0, now, half_life);
if (elapsed) {
u32 progress = ravg_normalize_dur(elapsed, half_life);
u64 old = u64_x_u32_rshift(rd->old,
(1 << RAVG_FRAC_BITS) - progress / 2,
RAVG_FRAC_BITS);
u64 cur = rd->cur / 2;
return old + cur;
} else {
return rd->old;
}
}