
From: Xu Kuohai <xukuohai@huawei.com> hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAOAT -------------------------------- Add cgroup-based interference statistics framework. Signed-off-by: Xu Kuohai <xukuohai@huawei.com> Signed-off-by: Pu Lehui <pulehui@huawei.com> --- include/linux/cgroup-defs.h | 4 + include/linux/cgroup.h | 55 +++++++++++ kernel/cgroup/Makefile | 1 + kernel/cgroup/cgroup-internal.h | 16 ++++ kernel/cgroup/cgroup.c | 16 +++- kernel/cgroup/ifs.c | 163 ++++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 kernel/cgroup/ifs.c diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index f3fd0407d346..47372df6abbe 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -552,7 +552,11 @@ struct cgroup { struct bpf_local_storage __rcu *bpf_cgrp_storage; #endif +#ifdef CONFIG_CGROUP_IFS + KABI_USE(1, struct cgroup_ifs *ifs) +#else KABI_RESERVE(1) +#endif KABI_RESERVE(2) KABI_RESERVE(3) KABI_RESERVE(4) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 62cea15eb6df..fd5617e7f0de 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -860,4 +860,59 @@ static inline void cgroup_bpf_put(struct cgroup *cgrp) {} void cgroup_move_task_to_root(struct task_struct *tsk); #endif +#ifdef CONFIG_CGROUP_IFS + +enum ifs_types { + IFS_STUB, + NR_IFS_TYPES, +}; + +struct cgroup_ifs_cpu { + /* total time for each interference, in ns */ + u64 time[NR_IFS_TYPES]; +}; + +/* + * cgroup interference statistics + */ +struct cgroup_ifs { + /* per-cpu interference statistics tracking */ + struct cgroup_ifs_cpu __percpu *pcpu; +}; + +extern struct cgroup_ifs cgroup_root_ifs; + +DECLARE_STATIC_KEY_FALSE(cgrp_ifs_enabled); +static inline bool cgroup_ifs_enabled(void) +{ + return static_branch_unlikely(&cgrp_ifs_enabled); +} + +static inline struct cgroup_ifs *cgroup_ifs(struct cgroup *cgrp) +{ + return cgroup_ino(cgrp) == 1 ? &cgroup_root_ifs : cgrp->ifs; +} + +static inline struct cgroup_ifs *task_ifs(struct task_struct *task) +{ + return cgroup_ifs(task_dfl_cgroup(task)); +} + +static inline struct cgroup_ifs *current_ifs(void) +{ + return task_ifs(current); +} + +static inline void cgroup_ifs_account_delta(struct cgroup_ifs_cpu *ifsc, + int type, u64 delta) +{ + if (!cgroup_ifs_enabled()) + return; + + if (delta > 0) + ifsc->time[type] += delta; +} + +#endif /* CONFIG_CGROUP_IFS */ + #endif /* _LINUX_CGROUP_H */ diff --git a/kernel/cgroup/Makefile b/kernel/cgroup/Makefile index 12f8457ad1f9..8d0cc493fb23 100644 --- a/kernel/cgroup/Makefile +++ b/kernel/cgroup/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_CGROUP_RDMA) += rdma.o obj-$(CONFIG_CPUSETS) += cpuset.o obj-$(CONFIG_CGROUP_MISC) += misc.o obj-$(CONFIG_CGROUP_DEBUG) += debug.o +obj-$(CONFIG_CGROUP_IFS) += ifs.o diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index a379e523ae05..0e24ff3c661a 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -302,4 +302,20 @@ int cgroup_addrm_files(struct cgroup_subsys_state *css, struct cgroup *cgrp, struct cftype cfts[], bool is_add); +#ifdef CONFIG_CGROUP_IFS +int cgroup_ifs_alloc(struct cgroup *cgrp); +void cgroup_ifs_free(struct cgroup *cgrp); +void cgroup_ifs_init(void); +int cgroup_ifs_add_files(struct cgroup_subsys_state *css, struct cgroup *cgrp); +void cgroup_ifs_rm_files(struct cgroup_subsys_state *css, struct cgroup *cgrp); +#else /* !CONFIG_CGROUP_IFS */ +static inline int cgroup_ifs_alloc(struct cgroup *cgrp) { return 0; } +static inline void cgroup_ifs_free(struct cgroup *cgrp) {} +static inline void cgroup_ifs_init(void) {} +static inline int cgroup_ifs_add_files(struct cgroup_subsys_state *css, + struct cgroup *cgrp) { return 0; } +static inline void cgroup_ifs_rm_files(struct cgroup_subsys_state *css, + struct cgroup *cgrp) {} +#endif /* CONFIG_CGROUP_IFS */ + #endif /* __CGROUP_INTERNAL_H */ diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 866931b39735..31f3d281e67c 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1700,6 +1700,7 @@ static void css_clear_dir(struct cgroup_subsys_state *css) if (cgroup_psi_enabled()) cgroup_addrm_files(css, cgrp, cgroup_psi_files, false); + cgroup_ifs_rm_files(css, cgrp); } else { cgroup_addrm_files(css, cgrp, cgroup1_base_files, false); @@ -1738,6 +1739,10 @@ static int css_populate_dir(struct cgroup_subsys_state *css) if (ret < 0) return ret; } + + ret = cgroup_ifs_add_files(css, cgrp); + if (ret < 0) + return ret; } else { ret = cgroup_addrm_files(css, cgrp, cgroup1_base_files, true); @@ -5477,6 +5482,7 @@ static void css_free_rwork_fn(struct work_struct *work) cgroup_put(cgroup_parent(cgrp)); kernfs_put(cgrp->kn); psi_cgroup_free(cgrp); + cgroup_ifs_free(cgrp); cgroup_rstat_exit(cgrp); kfree(cgrp); } else { @@ -5724,10 +5730,14 @@ static struct cgroup *cgroup_create(struct cgroup *parent, const char *name, if (ret) goto out_kernfs_remove; + ret = cgroup_ifs_alloc(cgrp); + if (ret) + goto out_psi_free; + if (cgrp->root == &cgrp_dfl_root) { ret = cgroup_bpf_inherit(cgrp); if (ret) - goto out_psi_free; + goto out_ifs_free; } /* @@ -5788,6 +5798,8 @@ static struct cgroup *cgroup_create(struct cgroup *parent, const char *name, return cgrp; +out_ifs_free: + cgroup_ifs_free(cgrp); out_psi_free: psi_cgroup_free(cgrp); out_kernfs_remove: @@ -6195,6 +6207,8 @@ int __init cgroup_init(void) BUG_ON(cgroup_init_cftypes(NULL, cgroup_psi_files)); BUG_ON(cgroup_init_cftypes(NULL, cgroup1_base_files)); + cgroup_ifs_init(); + cgroup_rstat_boot(); get_user_ns(init_cgroup_ns.user_ns); diff --git a/kernel/cgroup/ifs.c b/kernel/cgroup/ifs.c new file mode 100644 index 000000000000..fc761cb02a6d --- /dev/null +++ b/kernel/cgroup/ifs.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Interference statistics for cgroup + * + * Copyright (C) 2025-2025 Huawei Technologies Co., Ltd + */ + +#include "cgroup-internal.h" + +static DEFINE_PER_CPU(struct cgroup_ifs_cpu, cgrp_root_ifs_cpu); +struct cgroup_ifs cgroup_root_ifs = { + .pcpu = &cgrp_root_ifs_cpu, +}; + +DEFINE_STATIC_KEY_FALSE(cgrp_ifs_enabled); + +#ifdef CONFIG_CGROUP_IFS_DEFAULT_ENABLED +static bool ifs_enable = true; +#else +static bool ifs_enable; +#endif + +static int __init setup_ifs(char *str) +{ + return kstrtobool(str, &ifs_enable) == 0; +} +__setup("cgroup_ifs=", setup_ifs); + +int cgroup_ifs_alloc(struct cgroup *cgrp) +{ + cgrp->ifs = kzalloc(sizeof(struct cgroup_ifs), GFP_KERNEL); + if (!cgrp->ifs) + return -ENOMEM; + + cgrp->ifs->pcpu = alloc_percpu(struct cgroup_ifs_cpu); + if (!cgrp->ifs->pcpu) { + kfree(cgrp->ifs); + return -ENOMEM; + } + + return 0; +} + +void cgroup_ifs_free(struct cgroup *cgrp) +{ + free_percpu(cgrp->ifs->pcpu); + kfree(cgrp->ifs); +} + +static const char *ifs_type_name(int type) +{ + char *name = NULL; + + switch (type) { + default: + break; + } + + return name; +} + +static int print_sum_time(struct cgroup_ifs *ifs, struct seq_file *seq) +{ + u64 time[NR_IFS_TYPES] = { 0 }; + int cpu; + int i; + + for_each_possible_cpu(cpu) { + for (i = 0; i < NR_IFS_TYPES; i++) + time[i] += per_cpu_ptr(ifs->pcpu, cpu)->time[i]; + } + + seq_printf(seq, "%-18s%s\n", "Interference", "Total Time (ns)"); + + for (i = 0; i < NR_IFS_TYPES; i++) + seq_printf(seq, "%-18s%llu\n", ifs_type_name(i), time[i]); + + return 0; +} + +static int cgroup_ifs_show(struct seq_file *seq, void *v) +{ + struct cgroup __maybe_unused *cgrp = seq_css(seq)->cgroup; + struct cgroup_ifs __maybe_unused *ifs = cgroup_ifs(cgrp); + int ret; + + if (!ifs) { + pr_info("cgroup_ino(cgrp) = %ld\n", cgroup_ino(cgrp)); + return -EINVAL; + } + + ret = print_sum_time(ifs, seq); + if (ret) + return ret; + + return 0; +} + +static ssize_t cgroup_ifs_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + struct cgroup *cgrp = seq_css(of->seq_file)->cgroup; + struct cgroup_ifs *ifs = cgroup_ifs(cgrp); + struct cgroup_ifs_cpu *ifsc; + bool clear; + int cpu; + + if (!ifs) + return -EOPNOTSUPP; + + if (kstrtobool(strstrip(buf), &clear) < 0) + return -EINVAL; + + if (!clear) { + for_each_possible_cpu(cpu) { + ifsc = per_cpu_ptr(ifs->pcpu, cpu); + memset(ifsc->time, 0, sizeof(ifsc->time)); + } + } + + return nbytes; +} + +static struct cftype cgroup_ifs_files[] = { + { + .name = "interference.stat", + .seq_show = cgroup_ifs_show, + .write = cgroup_ifs_write, + }, + { } /* terminate */ +}; + +void cgroup_ifs_init(void) +{ + if (!ifs_enable) + return; + + BUG_ON(cgroup_init_cftypes(NULL, cgroup_ifs_files)); + + static_branch_enable(&cgrp_ifs_enabled); +} + +int cgroup_ifs_add_files(struct cgroup_subsys_state *css, struct cgroup *cgrp) +{ + int ret = 0; + + if (!cgroup_ifs_enabled()) + return 0; + + ret = cgroup_addrm_files(css, cgrp, cgroup_ifs_files, true); + if (ret < 0) { + cgroup_addrm_files(css, cgrp, cgroup_ifs_files, false); + return ret; + } + + return 0; +} + +void cgroup_ifs_rm_files(struct cgroup_subsys_state *css, struct cgroup *cgrp) +{ + if (cgroup_ifs_enabled()) + cgroup_addrm_files(css, cgrp, cgroup_ifs_files, false); +} -- 2.34.1