scx_lavd: refactoring do_update_sys_stat()

Originally, do_update_sys_stat() simply calculated the system-wide CPU
utilization. Over time, it has evolved to collect all kinds of
system-wide, periodic statistics for decision-making, so it has become
bulky. Now, it is time to refactor it for readability. This commit does
not contain functional changes other than refactoring.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
This commit is contained in:
Changwoo Min 2024-06-12 21:15:25 +09:00
parent 9d129f0afa
commit 753f333c09

View File

@ -692,36 +692,57 @@ static u64 calc_avg_freq(u64 old_freq, u64 interval)
return ewma_freq; return ewma_freq;
} }
static void do_update_sys_stat(void) struct sys_stat_ctx {
{ struct sys_stat *stat_cur;
struct sys_stat *stat_cur = get_sys_stat_cur(); struct sys_stat *stat_next;
struct sys_stat *stat_next = get_sys_stat_next(); u64 now;
u64 now, duration, duration_total, compute; u64 duration;
u64 idle_total = 0, compute_total = 0; u64 duration_total;
u64 load_actual = 0, load_ideal = 0, load_run_time_ns = 0; u64 idle_total;
s64 max_lat_cri = 0, min_lat_cri = UINT_MAX, avg_lat_cri = 0; u64 compute_total;
u64 sum_lat_cri = 0, sched_nr = 0; u64 load_actual;
u64 sum_perf_cri = 0, avg_perf_cri = 0; u64 load_ideal;
u64 new_util, new_load_factor; u64 load_run_time_ns;
u64 nr_violation = 0; s64 max_lat_cri;
int cpu; s64 min_lat_cri;
s64 avg_lat_cri;
u64 sum_lat_cri;
u64 sched_nr;
u64 sum_perf_cri;
u64 avg_perf_cri;
u64 new_util;
u64 new_load_factor;
u64 nr_violation;
};
now = bpf_ktime_get_ns(); static void init_sys_stat_ctx(struct sys_stat_ctx *c)
duration = now - stat_cur->last_update_clk; {
memset(c, 0, sizeof(*c));
c->stat_cur = get_sys_stat_cur();
c->stat_next = get_sys_stat_next();
c->now = bpf_ktime_get_ns();
c->duration = c->now - c->stat_cur->last_update_clk;
c->min_lat_cri = UINT_MAX;
}
static void collect_sys_stat(struct sys_stat_ctx *c)
{
int cpu;
bpf_for(cpu, 0, nr_cpus_onln) { bpf_for(cpu, 0, nr_cpus_onln) {
struct cpu_ctx *cpuc = get_cpu_ctx_id(cpu); struct cpu_ctx *cpuc = get_cpu_ctx_id(cpu);
if (!cpuc) { if (!cpuc) {
compute_total = 0; c->compute_total = 0;
break; break;
} }
/* /*
* Accumulate cpus' loads. * Accumulate cpus' loads.
*/ */
load_ideal += cpuc->load_ideal; c->load_ideal += cpuc->load_ideal;
load_actual += cpuc->load_actual; c->load_actual += cpuc->load_actual;
load_run_time_ns += cpuc->load_run_time_ns; c->load_run_time_ns += cpuc->load_run_time_ns;
/* /*
* Accumulate task's latency criticlity information. * Accumulate task's latency criticlity information.
@ -730,24 +751,24 @@ static void do_update_sys_stat(void)
* accuracy should be small and very rare and thus should be * accuracy should be small and very rare and thus should be
* fine. * fine.
*/ */
sum_lat_cri += cpuc->sum_lat_cri; c->sum_lat_cri += cpuc->sum_lat_cri;
cpuc->sum_lat_cri = 0; cpuc->sum_lat_cri = 0;
sched_nr += cpuc->sched_nr; c->sched_nr += cpuc->sched_nr;
cpuc->sched_nr = 0; cpuc->sched_nr = 0;
if (cpuc->max_lat_cri > max_lat_cri) if (cpuc->max_lat_cri > c->max_lat_cri)
max_lat_cri = cpuc->max_lat_cri; c->max_lat_cri = cpuc->max_lat_cri;
cpuc->max_lat_cri = 0; cpuc->max_lat_cri = 0;
if (cpuc->min_lat_cri < min_lat_cri) if (cpuc->min_lat_cri < c->min_lat_cri)
min_lat_cri = cpuc->min_lat_cri; c->min_lat_cri = cpuc->min_lat_cri;
cpuc->min_lat_cri = UINT_MAX; cpuc->min_lat_cri = UINT_MAX;
/* /*
* Accumulate task's performance criticlity information. * Accumulate task's performance criticlity information.
*/ */
sum_perf_cri += cpuc->sum_perf_cri; c->sum_perf_cri += cpuc->sum_perf_cri;
cpuc->sum_perf_cri = 0; cpuc->sum_perf_cri = 0;
/* /*
@ -760,9 +781,9 @@ static void do_update_sys_stat(void)
break; break;
bool ret = __sync_bool_compare_and_swap( bool ret = __sync_bool_compare_and_swap(
&cpuc->idle_start_clk, old_clk, now); &cpuc->idle_start_clk, old_clk, c->now);
if (ret) { if (ret) {
idle_total += now - old_clk; c->idle_total += c->now - old_clk;
break; break;
} }
} }
@ -770,71 +791,96 @@ static void do_update_sys_stat(void)
/* /*
* Calculcate per-CPU utilization * Calculcate per-CPU utilization
*/ */
compute = 0; u64 compute = 0;
if (duration > cpuc->idle_total) if (c->duration > cpuc->idle_total)
compute = duration - cpuc->idle_total; compute = c->duration - cpuc->idle_total;
new_util = (compute * LAVD_CPU_UTIL_MAX) / duration; c->new_util = (compute * LAVD_CPU_UTIL_MAX) / c->duration;
cpuc->util = calc_avg(cpuc->util, new_util); cpuc->util = calc_avg(cpuc->util, c->new_util);
if (cpuc->util > LAVD_TC_PER_CORE_MAX_CTUIL) if (cpuc->util > LAVD_TC_PER_CORE_MAX_CTUIL)
nr_violation += 1000; c->nr_violation += 1000;
/* /*
* Accmulate system-wide idle time * Accmulate system-wide idle time
*/ */
idle_total += cpuc->idle_total; c->idle_total += cpuc->idle_total;
cpuc->idle_total = 0; cpuc->idle_total = 0;
} }
}
duration_total = duration * nr_cpus_onln; static void calc_sys_stat(struct sys_stat_ctx *c)
if (duration_total > idle_total) {
compute_total = duration_total - idle_total; c->duration_total = c->duration * nr_cpus_onln;
if (c->duration_total > c->idle_total)
c->compute_total = c->duration_total - c->idle_total;
new_util = (compute_total * LAVD_CPU_UTIL_MAX) / duration_total; c->new_util = (c->compute_total * LAVD_CPU_UTIL_MAX) /
c->duration_total;
new_load_factor = (1000 * LAVD_LOAD_FACTOR_ADJ * load_run_time_ns) / c->new_load_factor = (1000 * LAVD_LOAD_FACTOR_ADJ *
(LAVD_TARGETED_LATENCY_NS * nr_cpus_onln); c->load_run_time_ns) /
if (new_load_factor > LAVD_LOAD_FACTOR_MAX) (LAVD_TARGETED_LATENCY_NS * nr_cpus_onln);
new_load_factor = LAVD_LOAD_FACTOR_MAX; if (c->new_load_factor > LAVD_LOAD_FACTOR_MAX)
c->new_load_factor = LAVD_LOAD_FACTOR_MAX;
if (sched_nr == 0) { if (c->sched_nr == 0) {
/* /*
* When a system is completely idle, it is indeed possible * When a system is completely idle, it is indeed possible
* nothing scheduled for an interval. * nothing scheduled for an interval.
*/ */
min_lat_cri = stat_cur->min_lat_cri; c->min_lat_cri = c->stat_cur->min_lat_cri;
max_lat_cri = stat_cur->max_lat_cri; c->max_lat_cri = c->stat_cur->max_lat_cri;
avg_lat_cri = stat_cur->avg_lat_cri; c->avg_lat_cri = c->stat_cur->avg_lat_cri;
avg_perf_cri = stat_cur->avg_perf_cri; c->avg_perf_cri = c->stat_cur->avg_perf_cri;
} }
else { else {
avg_lat_cri = sum_lat_cri / sched_nr; c->avg_lat_cri = c->sum_lat_cri / c->sched_nr;
avg_perf_cri = sum_perf_cri / sched_nr; c->avg_perf_cri = c->sum_perf_cri / c->sched_nr;
} }
}
static void update_sys_stat_next(struct sys_stat_ctx *c)
{
/* /*
* Update the CPU utilization to the next version. * Update the CPU utilization to the next version.
*/ */
stat_next->load_actual = calc_avg(stat_cur->load_actual, load_actual); struct sys_stat *stat_cur = c->stat_cur;
stat_next->load_ideal = calc_avg(stat_cur->load_ideal, load_ideal); struct sys_stat *stat_next = c->stat_next;
stat_next->util = calc_avg(stat_cur->util, new_util);
stat_next->load_factor = calc_avg(stat_cur->load_factor, new_load_factor);
stat_next->min_lat_cri = calc_avg(stat_cur->min_lat_cri, min_lat_cri); stat_next->load_actual =
stat_next->max_lat_cri = calc_avg(stat_cur->max_lat_cri, max_lat_cri); calc_avg(stat_cur->load_actual, c->load_actual);
stat_next->avg_lat_cri = calc_avg(stat_cur->avg_lat_cri, avg_lat_cri); stat_next->load_ideal =
calc_avg(stat_cur->load_ideal, c->load_ideal);
stat_next->util =
calc_avg(stat_cur->util, c->new_util);
stat_next->load_factor =
calc_avg(stat_cur->load_factor, c->new_load_factor);
stat_next->min_lat_cri =
calc_avg(stat_cur->min_lat_cri, c->min_lat_cri);
stat_next->max_lat_cri =
calc_avg(stat_cur->max_lat_cri, c->max_lat_cri);
stat_next->avg_lat_cri =
calc_avg(stat_cur->avg_lat_cri, c->avg_lat_cri);
stat_next->thr_lat_cri = stat_next->max_lat_cri - stat_next->thr_lat_cri = stat_next->max_lat_cri -
((stat_next->max_lat_cri - stat_next->avg_lat_cri) >> 1); ((stat_next->max_lat_cri - stat_next->avg_lat_cri) >> 1);
stat_next->avg_perf_cri = calc_avg(stat_cur->avg_perf_cri, avg_perf_cri); stat_next->avg_perf_cri =
calc_avg(stat_cur->avg_perf_cri, c->avg_perf_cri);
stat_next->nr_violation = calc_avg(stat_cur->nr_violation, nr_violation); stat_next->nr_violation =
calc_avg(stat_cur->nr_violation, c->nr_violation);
}
static void calc_inc1k(struct sys_stat_ctx *c)
{
/* /*
* Calculate the increment for latency criticality to priority mapping * Calculate the increment for mapping from latency criticality to
* priority.
* - Case 1. inc1k_low: [min_lc, avg_lc) -> [half_range, 0) * - Case 1. inc1k_low: [min_lc, avg_lc) -> [half_range, 0)
* - Case 2. inc1k_high: [avg_lc, max_lc] -> [0, -half_range) * - Case 2. inc1k_high: [avg_lc, max_lc] -> [0, -half_range)
*/ */
struct sys_stat *stat_next = c->stat_next;
if (stat_next->avg_lat_cri == stat_next->min_lat_cri) if (stat_next->avg_lat_cri == stat_next->min_lat_cri)
stat_next->inc1k_low = 0; stat_next->inc1k_low = 0;
else { else {
@ -850,11 +896,25 @@ static void do_update_sys_stat(void)
(stat_next->max_lat_cri + 1 - (stat_next->max_lat_cri + 1 -
stat_next->avg_lat_cri); stat_next->avg_lat_cri);
} }
}
static void do_update_sys_stat(void)
{
struct sys_stat_ctx c;
/*
* Collect and prepare the next version of stat.
*/
init_sys_stat_ctx(&c);
collect_sys_stat(&c);
calc_sys_stat(&c);
update_sys_stat_next(&c);
calc_inc1k(&c);
/* /*
* Make the next version atomically visible. * Make the next version atomically visible.
*/ */
stat_next->last_update_clk = now; c.stat_next->last_update_clk = c.now;
flip_sys_stat(); flip_sys_stat();
} }