blob: 39a8f164f77a017a7f7af01b3db91764877fc2ad [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 Oplus. All rights reserved.
*/
#include <linux/sched.h>
#include <linux/reciprocal_div.h>
#include <../kernel/sched/sched.h>
#include "special_opt.h"
#if IS_ENABLED(CONFIG_OPLUS_FEATURE_UIFRIST_HEAVYLOAD)
#include <trace/hooks/sched.h>
int sysctl_cpu_multi_thread = 0;
int ux_prefer_cpu[NR_CPUS] = { 0 };
module_param_named(enable, sysctl_cpu_multi_thread, uint, 0644);
#endif /* IS_ENABLED(CONFIG_OPLUS_FEATURE_UIFRIST_HEAVYLOAD) */
#ifdef CONFIG_OPLUS_SYSTEM_KERNEL_QCOM
bool is_heavy_load_task(struct task_struct *p)
{
int cpu;
unsigned long thresh_load;
struct reciprocal_value spc_rdiv = reciprocal_value(100);
if (!sysctl_cpu_multi_thread || !p)
return false;
cpu = task_cpu(p);
thresh_load = capacity_orig_of(cpu) * HEAVY_LOAD_SCALE;
if (task_util(p) > reciprocal_divide(thresh_load, spc_rdiv))
return true;
return false;
}
#else
bool is_heavy_load_task(struct task_struct *p)
{
long taskload;
bool ret = false;
if (!sysctl_cpu_multi_thread || !p)
return false;
taskload = READ_ONCE(p->se.avg.load_avg);
if (taskload >= 1000 && taskload <= 1024){
ret = true;
}
return ret;
}
#endif//CONFIG_OPLUS_SYSTEM_KERNEL_QCOM
#if IS_ENABLED(CONFIG_OPLUS_FEATURE_UIFRIST_HEAVYLOAD)
static int ux_init_cpu_data(void)
{
int i = 0;
int min_cpu = 0, ux_cpu = 0;
for (; i < nr_cpu_ids; ++i) {
ux_prefer_cpu[i] = -1;
}
ux_cpu = cpumask_weight(topology_core_cpumask(min_cpu));
if (ux_cpu == 0) {
pr_err("failed to init ux cpu data\n");
return -1;
}
for (i = 0; i < nr_cpu_ids && ux_cpu < nr_cpu_ids; ++i) {
ux_prefer_cpu[i] = ux_cpu++;
}
return 0;
}
static bool test_ux_task_cpu(int cpu)
{
return (cpu >= ux_prefer_cpu[0]);
}
static void check_preempt_wakeup_handler(void *data, struct task_struct *p,
int *ignore)
{
if (sysctl_cpu_multi_thread == 0)
return;
if (is_heavy_load_task(p))
*ignore = 1;
}
static void check_preempt_tick_handler(void *data, struct task_struct *p,
unsigned long *ideal_runtime)
{
if (sysctl_cpu_multi_thread == 0)
return;
if (is_heavy_load_task(p))
*ideal_runtime = HEAVY_LOAD_RUNTIME;
}
static void find_best_target_handler(void *data, struct task_struct *p, int cpu,
int *ignore)
{
if (sysctl_cpu_multi_thread == 0)
return;
if (is_heavy_load_task(p)) {
if (!test_ux_task_cpu(cpu))
*ignore = 1;
} else {
if (test_ux_task_cpu(cpu))
*ignore = 1;
}
}
static void cpupri_find_fitness_handler(void *data, struct task_struct *p, struct cpumask *lowest_mask)
{
unsigned int cpu;
if (sysctl_cpu_multi_thread == 0)
return;
cpu = cpumask_first(lowest_mask);
while (cpu < nr_cpu_ids) {
if (test_ux_task_cpu(cpu)) {
cpumask_clear_cpu(cpu, lowest_mask);
}
cpu = cpumask_next(cpu, lowest_mask);
}
}
static int register_vendor_hooks()
{
int rc = 0;
rc = register_trace_android_rvh_check_preempt_wakeup(
check_preempt_wakeup_handler, NULL);
if (rc != 0) {
pr_err("uifirst: register_trace_android_vh_scheduler_tick failed! rc=%d\n",
rc);
return rc;
}
rc = register_trace_android_rvh_check_preempt_tick(
check_preempt_tick_handler, NULL);
if (rc != 0) {
pr_err("uifirst: register_trace_android_vh_scheduler_tick failed! rc=%d\n",
rc);
return rc;
}
rc = register_trace_android_rvh_find_best_target(
find_best_target_handler, NULL);
if (rc != 0) {
pr_err("uifirst: register_trace_android_vh_scheduler_tick failed! rc=%d\n",
rc);
return rc;
}
rc = register_trace_android_rvh_cpupri_find_fitness(
cpupri_find_fitness_handler, NULL);
if (rc != 0) {
pr_err("uifirst: register_trace_android_rvh_cpupri_find_fitness failed! rc=%d\n",
rc);
return rc;
}
return 0;
}
static int __init init_uifirst_sepecial_opt(void)
{
int rc;
rc = ux_init_cpu_data();
if (rc != 0) {
return rc;
}
rc = register_vendor_hooks();
if (rc != 0) {
return rc;
}
return 0;
}
device_initcall(init_uifirst_sepecial_opt);
MODULE_LICENSE("GPL v2");
#endif /* IS_ENABLED(CONFIG_OPLUS_FEATURE_UIFRIST_HEAVYLOAD) */