Loading arch/arm64/configs/sdm845-perf_defconfig +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_CORE_ROTATE=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set Loading arch/arm64/configs/sdm845_defconfig +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_CORE_ROTATE=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set Loading init/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -1293,6 +1293,16 @@ config SCHED_CORE_CTL If unsure, say N here. config SCHED_CORE_ROTATE bool "Scheduler core rotation" depends on SMP help This options enables the core rotation functionality in the scheduler. Scheduler with core rotation aims to utilize CPUs evenly. If unsure, say N here. config CHECKPOINT_RESTORE bool "Checkpoint/restore support" if EXPERT select PROC_CHILDREN Loading kernel/sched/core.c +47 −0 Original line number Diff line number Diff line Loading @@ -9624,3 +9624,50 @@ void sched_exit(struct task_struct *p) #endif /* CONFIG_SCHED_WALT */ __read_mostly bool sched_predl = 1; #ifdef CONFIG_SCHED_CORE_ROTATE int find_first_cpu_bit(struct task_struct *p, const cpumask_t *search_cpus, struct sched_group *sg_target, bool *avoid_prev_cpu, bool *do_rotate, struct find_first_cpu_bit_env *env) { int i = -1; unsigned long mcc; int cpu = smp_processor_id(); mcc = cpu_rq(cpu)->rd->max_cpu_capacity.val; /* do rotation only for big CPUs. */ *do_rotate = (cpumask_first(search_cpus) < nr_cpu_ids && capacity_orig_of(cpumask_first(search_cpus)) == mcc); if (*do_rotate) { if (time_before_eq(jiffies, *env->avoid_prev_cpu_last + env->interval)) return *env->rotate_cpu_start; spin_lock(env->rotate_lock); if (time_after(jiffies, *env->avoid_prev_cpu_last + env->interval)) { cpumask_t tmpmask; *env->avoid_prev_cpu_last = jiffies; *avoid_prev_cpu = true; cpumask_copy(&tmpmask, sched_group_cpus(sg_target)); cpumask_andnot(&tmpmask, &tmpmask, cpu_isolated_mask); i = cpumask_next(*env->rotate_cpu_start, &tmpmask); if (i >= nr_cpu_ids) i = cpumask_first(&tmpmask) - 1; /* Change start CPU every interval. */ *env->rotate_cpu_start = i; } else { i = *env->rotate_cpu_start; } spin_unlock(env->rotate_lock); } return i; } #endif kernel/sched/core_ctl.c +81 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/kthread.h> #include <linux/sched.h> #include <linux/sched/rt.h> #include <linux/syscore_ops.h> #include <trace/events/sched.h> Loading @@ -35,6 +36,10 @@ struct cluster_data { unsigned int active_cpus; unsigned int num_cpus; unsigned int nr_isolated_cpus; #ifdef CONFIG_SCHED_CORE_ROTATE unsigned long set_max; unsigned long set_cur; #endif cpumask_t cpu_mask; unsigned int need_cpus; unsigned int task_thres; Loading Loading @@ -76,6 +81,7 @@ static void wake_up_core_ctl_thread(struct cluster_data *state); static bool initialized; static unsigned int get_active_cpu_count(const struct cluster_data *cluster); static void cpuset_next(struct cluster_data *cluster); /* ========================= sysfs interface =========================== */ Loading @@ -88,6 +94,7 @@ static ssize_t store_min_cpus(struct cluster_data *state, return -EINVAL; state->min_cpus = min(val, state->max_cpus); cpuset_next(state); wake_up_core_ctl_thread(state); return count; Loading @@ -109,6 +116,7 @@ static ssize_t store_max_cpus(struct cluster_data *state, val = min(val, state->num_cpus); state->max_cpus = val; state->min_cpus = min(state->min_cpus, state->max_cpus); cpuset_next(state); wake_up_core_ctl_thread(state); return count; Loading Loading @@ -702,6 +710,67 @@ static void move_cpu_lru(struct cpu_data *cpu_data) spin_unlock_irqrestore(&state_lock, flags); } #ifdef CONFIG_SCHED_CORE_ROTATE static void cpuset_next(struct cluster_data *cluster) { int cpus_needed = cluster->num_cpus - cluster->min_cpus; cluster->set_cur++; cluster->set_cur = min(cluster->set_cur, cluster->set_max); /* * This loop generates bit sets from 0 to pow(num_cpus, 2) - 1. * We start loop from set_cur to set_cur - 1 and break when weight of * set_cur equals to cpus_needed. */ while (1) { if (bitmap_weight(&cluster->set_cur, BITS_PER_LONG) == cpus_needed) { break; } cluster->set_cur++; cluster->set_cur = min(cluster->set_cur, cluster->set_max); if (cluster->set_cur == cluster->set_max) /* roll over */ cluster->set_cur = 0; }; pr_debug("first_cpu=%d cpus_needed=%d set_cur=0x%lx\n", cluster->first_cpu, cpus_needed, cluster->set_cur); } static bool should_we_isolate(int cpu, struct cluster_data *cluster) { /* cpu should be part of cluster */ return !!(cluster->set_cur & (1 << (cpu - cluster->first_cpu))); } static void core_ctl_resume(void) { unsigned int i = 0; struct cluster_data *cluster; /* move to next isolation cpu set */ for_each_cluster(cluster, i) cpuset_next(cluster); } static struct syscore_ops core_ctl_syscore_ops = { .resume = core_ctl_resume, }; #else static void cpuset_next(struct cluster_data *cluster) { } static bool should_we_isolate(int cpu, struct cluster_data *cluster) { return true; } #endif static void try_to_isolate(struct cluster_data *cluster, unsigned int need) { struct cpu_data *c, *tmp; Loading @@ -726,6 +795,9 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need) if (c->is_busy) continue; if (!should_we_isolate(c->cpu, cluster)) continue; spin_unlock_irqrestore(&state_lock, flags); pr_debug("Trying to isolate CPU%u\n", c->cpu); Loading Loading @@ -1029,6 +1101,11 @@ static int cluster_init(const struct cpumask *mask) cluster->offline_delay_ms = 100; cluster->task_thres = UINT_MAX; cluster->nrrun = cluster->num_cpus; #ifdef CONFIG_SCHED_CORE_ROTATE cluster->set_max = cluster->num_cpus * cluster->num_cpus; /* by default mark all cpus as eligible */ cluster->set_cur = cluster->set_max - 1; #endif cluster->enable = true; INIT_LIST_HEAD(&cluster->lru); spin_lock_init(&cluster->pending_lock); Loading Loading @@ -1065,6 +1142,10 @@ static int __init core_ctl_init(void) if (should_skip(cpu_possible_mask)) return 0; #ifdef CONFIG_SCHED_CORE_ROTATE register_syscore_ops(&core_ctl_syscore_ops); #endif cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "core_ctl/isolation:online", core_ctl_isolation_online_cpu, NULL); Loading Loading
arch/arm64/configs/sdm845-perf_defconfig +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_CORE_ROTATE=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set Loading
arch/arm64/configs/sdm845_defconfig +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_CORE_ROTATE=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set Loading
init/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -1293,6 +1293,16 @@ config SCHED_CORE_CTL If unsure, say N here. config SCHED_CORE_ROTATE bool "Scheduler core rotation" depends on SMP help This options enables the core rotation functionality in the scheduler. Scheduler with core rotation aims to utilize CPUs evenly. If unsure, say N here. config CHECKPOINT_RESTORE bool "Checkpoint/restore support" if EXPERT select PROC_CHILDREN Loading
kernel/sched/core.c +47 −0 Original line number Diff line number Diff line Loading @@ -9624,3 +9624,50 @@ void sched_exit(struct task_struct *p) #endif /* CONFIG_SCHED_WALT */ __read_mostly bool sched_predl = 1; #ifdef CONFIG_SCHED_CORE_ROTATE int find_first_cpu_bit(struct task_struct *p, const cpumask_t *search_cpus, struct sched_group *sg_target, bool *avoid_prev_cpu, bool *do_rotate, struct find_first_cpu_bit_env *env) { int i = -1; unsigned long mcc; int cpu = smp_processor_id(); mcc = cpu_rq(cpu)->rd->max_cpu_capacity.val; /* do rotation only for big CPUs. */ *do_rotate = (cpumask_first(search_cpus) < nr_cpu_ids && capacity_orig_of(cpumask_first(search_cpus)) == mcc); if (*do_rotate) { if (time_before_eq(jiffies, *env->avoid_prev_cpu_last + env->interval)) return *env->rotate_cpu_start; spin_lock(env->rotate_lock); if (time_after(jiffies, *env->avoid_prev_cpu_last + env->interval)) { cpumask_t tmpmask; *env->avoid_prev_cpu_last = jiffies; *avoid_prev_cpu = true; cpumask_copy(&tmpmask, sched_group_cpus(sg_target)); cpumask_andnot(&tmpmask, &tmpmask, cpu_isolated_mask); i = cpumask_next(*env->rotate_cpu_start, &tmpmask); if (i >= nr_cpu_ids) i = cpumask_first(&tmpmask) - 1; /* Change start CPU every interval. */ *env->rotate_cpu_start = i; } else { i = *env->rotate_cpu_start; } spin_unlock(env->rotate_lock); } return i; } #endif
kernel/sched/core_ctl.c +81 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/kthread.h> #include <linux/sched.h> #include <linux/sched/rt.h> #include <linux/syscore_ops.h> #include <trace/events/sched.h> Loading @@ -35,6 +36,10 @@ struct cluster_data { unsigned int active_cpus; unsigned int num_cpus; unsigned int nr_isolated_cpus; #ifdef CONFIG_SCHED_CORE_ROTATE unsigned long set_max; unsigned long set_cur; #endif cpumask_t cpu_mask; unsigned int need_cpus; unsigned int task_thres; Loading Loading @@ -76,6 +81,7 @@ static void wake_up_core_ctl_thread(struct cluster_data *state); static bool initialized; static unsigned int get_active_cpu_count(const struct cluster_data *cluster); static void cpuset_next(struct cluster_data *cluster); /* ========================= sysfs interface =========================== */ Loading @@ -88,6 +94,7 @@ static ssize_t store_min_cpus(struct cluster_data *state, return -EINVAL; state->min_cpus = min(val, state->max_cpus); cpuset_next(state); wake_up_core_ctl_thread(state); return count; Loading @@ -109,6 +116,7 @@ static ssize_t store_max_cpus(struct cluster_data *state, val = min(val, state->num_cpus); state->max_cpus = val; state->min_cpus = min(state->min_cpus, state->max_cpus); cpuset_next(state); wake_up_core_ctl_thread(state); return count; Loading Loading @@ -702,6 +710,67 @@ static void move_cpu_lru(struct cpu_data *cpu_data) spin_unlock_irqrestore(&state_lock, flags); } #ifdef CONFIG_SCHED_CORE_ROTATE static void cpuset_next(struct cluster_data *cluster) { int cpus_needed = cluster->num_cpus - cluster->min_cpus; cluster->set_cur++; cluster->set_cur = min(cluster->set_cur, cluster->set_max); /* * This loop generates bit sets from 0 to pow(num_cpus, 2) - 1. * We start loop from set_cur to set_cur - 1 and break when weight of * set_cur equals to cpus_needed. */ while (1) { if (bitmap_weight(&cluster->set_cur, BITS_PER_LONG) == cpus_needed) { break; } cluster->set_cur++; cluster->set_cur = min(cluster->set_cur, cluster->set_max); if (cluster->set_cur == cluster->set_max) /* roll over */ cluster->set_cur = 0; }; pr_debug("first_cpu=%d cpus_needed=%d set_cur=0x%lx\n", cluster->first_cpu, cpus_needed, cluster->set_cur); } static bool should_we_isolate(int cpu, struct cluster_data *cluster) { /* cpu should be part of cluster */ return !!(cluster->set_cur & (1 << (cpu - cluster->first_cpu))); } static void core_ctl_resume(void) { unsigned int i = 0; struct cluster_data *cluster; /* move to next isolation cpu set */ for_each_cluster(cluster, i) cpuset_next(cluster); } static struct syscore_ops core_ctl_syscore_ops = { .resume = core_ctl_resume, }; #else static void cpuset_next(struct cluster_data *cluster) { } static bool should_we_isolate(int cpu, struct cluster_data *cluster) { return true; } #endif static void try_to_isolate(struct cluster_data *cluster, unsigned int need) { struct cpu_data *c, *tmp; Loading @@ -726,6 +795,9 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need) if (c->is_busy) continue; if (!should_we_isolate(c->cpu, cluster)) continue; spin_unlock_irqrestore(&state_lock, flags); pr_debug("Trying to isolate CPU%u\n", c->cpu); Loading Loading @@ -1029,6 +1101,11 @@ static int cluster_init(const struct cpumask *mask) cluster->offline_delay_ms = 100; cluster->task_thres = UINT_MAX; cluster->nrrun = cluster->num_cpus; #ifdef CONFIG_SCHED_CORE_ROTATE cluster->set_max = cluster->num_cpus * cluster->num_cpus; /* by default mark all cpus as eligible */ cluster->set_cur = cluster->set_max - 1; #endif cluster->enable = true; INIT_LIST_HEAD(&cluster->lru); spin_lock_init(&cluster->pending_lock); Loading Loading @@ -1065,6 +1142,10 @@ static int __init core_ctl_init(void) if (should_skip(cpu_possible_mask)) return 0; #ifdef CONFIG_SCHED_CORE_ROTATE register_syscore_ops(&core_ctl_syscore_ops); #endif cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "core_ctl/isolation:online", core_ctl_isolation_online_cpu, NULL); Loading