use core::hint::unlikely;
use crate::time::sched_clock::sched_clock;
const SCHED_CAPACITY_SHIFT: usize = 10;
const SCHED_CAPACITY_SCALE: usize = 1 << SCHED_CAPACITY_SHIFT;
#[allow(non_upper_case_globals)]
const runnable_avg_yN_inv: [u32; 32] = [
0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6, 0xe0ccdeeb, 0xdbfbb796,
0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85, 0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46,
0xb504f333, 0xb123f581, 0xad583ee9, 0xa9a15ab4, 0xa5fed6a9, 0xa2704302, 0x9ef5325f, 0x9b8d39b9,
0x9837f050, 0x94f4efa8, 0x91c3d373, 0x8ea4398a, 0x8b95c1e3, 0x88980e80, 0x85aac367, 0x82cd8698,
];
const LOAD_AVG_PERIOD: u32 = 32;
const LOAD_AVG_MAX: u32 = 47742;
const PELT_MIN_DIVIDER: u32 = LOAD_AVG_MAX - 1024;
fn decay_load(mut val: u64, n: u64) -> u64 {
if unlikely(n > u64::from(LOAD_AVG_PERIOD) * 63) {
return 0;
}
let mut local_n = n as u32;
if unlikely(local_n >= LOAD_AVG_PERIOD) {
val >>= local_n / LOAD_AVG_PERIOD;
local_n %= LOAD_AVG_PERIOD;
}
((u128::from(val) * u128::from(runnable_avg_yN_inv[local_n as usize])) >> 32) as u64
}
fn __accumulate_pelt_segments(periods: u64, d1: u32, d3: u32) -> u32 {
let c3 = d3;
let c1 = decay_load(u64::from(d1), periods);
let c2 = u64::from(LOAD_AVG_MAX) - decay_load(u64::from(LOAD_AVG_MAX), periods) - 1024;
c1 as u32 + c2 as u32 + c3
}
#[repr(align(64))]
pub(crate) struct SchedAvg {
last_update_time: u64,
load_sum: u64,
runnable_sum: u64,
util_sum: u64,
period_contrib: u64,
load_avg: u64,
runnable_avg: u64,
util_avg: u64,
}
impl SchedAvg {
pub(crate) fn new() -> Self {
SchedAvg {
last_update_time: sched_clock(),
load_sum: 0,
runnable_sum: 0,
util_sum: 0,
period_contrib: 0,
load_avg: 0,
runnable_avg: 0,
util_avg: 0,
}
}
#[inline(always)]
fn accumulate_sum(&mut self, mut delta: u64, load: u64, runnable: u64, running: u64) -> bool {
let mut contrib = delta as u32;
delta += self.period_contrib;
let periods = delta / 1024;
if periods != 0 {
self.load_sum = decay_load(self.load_sum, periods);
self.runnable_sum = decay_load(self.runnable_sum, periods);
self.util_sum = decay_load(self.util_sum, periods);
delta %= 1024;
if load != 0 {
contrib = __accumulate_pelt_segments(
periods,
1024 - self.period_contrib as u32,
delta as u32,
);
}
}
self.period_contrib = delta;
if load != 0 {
self.load_sum += load * u64::from(contrib);
}
if runnable != 0 {
self.runnable_sum += (runnable * u64::from(contrib)) * SCHED_CAPACITY_SCALE as u64;
}
if running != 0 {
self.util_sum += u64::from(contrib) * SCHED_CAPACITY_SCALE as u64;
}
periods != 0
}
#[inline(always)]
fn ___update_load_sum(
&mut self,
now: u64,
load: u64,
mut runnable: u64,
mut running: u64,
) -> bool {
let mut delta = now - self.last_update_time;
delta >>= 10;
if delta == 0 {
return false;
}
self.last_update_time += delta << 10;
if load == 0 {
runnable = 0;
running = 0;
}
if self.accumulate_sum(delta, load, runnable, running) {
return true;
}
false
}
const fn get_pelt_divider(&self) -> u64 {
self.period_contrib + PELT_MIN_DIVIDER as u64
}
#[inline(always)]
fn ___update_load_avg(&mut self, load: u64) {
let divider = self.get_pelt_divider();
self.load_avg = (load * self.load_sum) / divider;
self.runnable_avg = self.runnable_sum / divider;
self.util_avg = self.util_sum / divider;
}
#[inline(always)]
pub(crate) fn update_load_avg(
&mut self,
now: u64,
load: u64,
runnable: u64,
running: u64,
) -> bool {
if self.___update_load_sum(now, load, runnable, running) {
self.___update_load_avg(load);
return true;
}
false
}
#[inline(always)]
pub(crate) fn load_avg(&self) -> u64 {
self.load_avg
}
#[inline(always)]
pub(crate) fn runnable_avg(&self) -> u64 {
self.runnable_avg
}
#[inline(always)]
pub(crate) fn util_avg(&self) -> u64 {
self.util_avg
}
}