From: Hongyu Li <“543306408@qq.com”>
openEuler inclusion category: bugfix bugzilla: https://gitee.com/openeuler-competition/summer-2021/issues/I3EBT6 CVE: NA
----------------------------------------------------------------------
The /proc/idle can give higher precision in accounting the CPU idle time compared with the traditional /proc/stat ways.
Signed-off-by: Hongyu Li <“543306408@qq.com”> --- fs/proc/Kconfig | 7 ++++ fs/proc/Makefile | 1 + fs/proc/proc_idle.c | 82 ++++++++++++++++++++++++++++++++++++++++++ kernel/sched/cputime.c | 16 +++++++++ kernel/sched/idle.c | 21 +++++++++++ 5 files changed, 127 insertions(+) create mode 100644 fs/proc/proc_idle.c
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index c930001056f9..46620afe9cac 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -107,3 +107,10 @@ config PROC_PID_ARCH_STATUS config PROC_CPU_RESCTRL def_bool n depends on PROC_FS + +config PROC_IDLE + bool "include /proc/idle file" + depends on PROC_FS + default y + help + Provide the CPU idle time in the /proc/idle file. diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 8704d41dd67c..69dd2da3a080 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -34,5 +34,6 @@ proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PRINTK) += kmsg.o proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o proc-$(CONFIG_BOOT_CONFIG) += bootconfig.o +proc-$(CONFIG_PROC_IDLE) += proc_idle.o obj-$(CONFIG_ETMEM_SCAN) += etmem_scan.o obj-$(CONFIG_ETMEM_SWAP) += etmem_swap.o diff --git a/fs/proc/proc_idle.c b/fs/proc/proc_idle.c new file mode 100644 index 000000000000..bbb52e247448 --- /dev/null +++ b/fs/proc/proc_idle.c @@ -0,0 +1,82 @@ +#include <linux/cpumask.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <linux/sched/stat.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/irqnr.h> +#include <linux/sched/cputime.h> +#include <linux/tick.h> + +#ifdef CONFIG_PROC_IDLE + +#define PROC_NAME "idle" + +extern u64 cpu_rq_get(int cpu); + +static u64 get_idle_sum_exec_runtime(int cpu) +{ + u64 idle = cpu_rq_get(cpu); + + return idle; +} + +static int show_idle(struct seq_file *p, void *v) +{ + int i; + u64 idle; + + idle = 0; + + for_each_possible_cpu(i) { + + idle += get_idle_sum_exec_runtime(i); + + } + + seq_put_decimal_ull(p, "cpu ", nsec_to_clock_t(idle)); + seq_putc(p, '\n'); + + for_each_online_cpu(i) { + + idle = get_idle_sum_exec_runtime(i); + + seq_printf(p, "cpu%d", i); + seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle)); + seq_putc(p, '\n'); + } + + return 0; +} + +static int idle_open(struct inode *inode, struct file *file) +{ + unsigned int size = 1024 + 128 * num_online_cpus(); + + return single_open_size(file, show_idle, NULL, size); +} + +static struct proc_ops idle_procs_ops = { + .proc_open = idle_open, + .proc_read_iter = seq_read_iter, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int __init kernel_module_init(void) +{ + proc_create(PROC_NAME, 0, NULL, &idle_procs_ops); + return 0; +} + +fs_initcall(kernel_module_init); + +#endif /*CONFIG_PROC_IDLE*/ diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 5a55d2300452..bb280852bb06 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -1078,3 +1078,19 @@ void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu) EXPORT_SYMBOL_GPL(kcpustat_cpu_fetch);
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */ + + +#ifdef CONFIG_PROC_IDLE + + +u64 cpu_rq_get(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + struct sched_entity *idle_se = &rq->idle->se; + u64 idle = idle_se->sum_exec_runtime; + + return idle; +} +EXPORT_SYMBOL_GPL(cpu_rq_get); + +#endif /* CONFIG_PROC_IDLE */ diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 36b545f17206..e3fb940a61e8 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -424,6 +424,20 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl
static void put_prev_task_idle(struct rq *rq, struct task_struct *prev) { +#ifdef CONFIG_PROC_IDLE + struct sched_entity *idle_se = &rq->idle->se; + u64 now = sched_clock(); + u64 delta_exec; + + delta_exec = now - idle_se->exec_start; + if (unlikely((s64)delta_exec <= 0)) + return; + + schedstat_set(idle_se->statistics.exec_max, + max(delta_exec, idle_se->statistics.exec_max)); + + idle_se->sum_exec_runtime += delta_exec; +#endif }
static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first) @@ -436,6 +450,13 @@ struct task_struct *pick_next_task_idle(struct rq *rq) { struct task_struct *next = rq->idle;
+#ifdef CONFIG_PROC_IDLE + struct sched_entity *idle_se = &rq->idle->se; + u64 now = sched_clock(); + + idle_se->exec_start = now; +#endif + set_next_task_idle(rq, next, true);
return next;