一、CPU调度策略设置
1. 内核函数
int sched_setscheduler(struct task_struct *p, int policy, const struct sched_param *param) 衍生函数: sched_setscheduler_nocheck
设置内核线程调度策略和优先级,优先级设置只对RT线程有效。
2. 系统调用
int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); int sched_getscheduler(pid_t pid);
若要设置为RT,需要root权限,此时RT优先级数值为99-param->sched_priority;若设置为CFS,param->sched_priority必须为0
3. Native函数
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
初始化attr,设置调度策略。设置为RT调度策略需要root权限,设置为CFS不需要。
4. 上层函数
native void setThreadScheduler(int tid, int policy, int priority) //Process.java
通过 android_util_Process.cpp 这个JNI文件中调用 sched_setscheduler 函数实现。
5. 命令行工具
chrt -f -p <pid> 15
将pid线程设置为RT(-f)线程,优先级比RT最低优先级提升15,为99-15=89
二、CPU调度优先级设置
1. 内核函数
void set_user_nice(struct task_struct *p, long nice)
和系统调用 nice 和 setpriority 对应。
2. 系统调用
int nice(int inc);
当前cfs线程优先级数值加inc,inc可正可负,对rt线程无效。
int getpriority(int which, id_t who); int setpriority(int which, id_t who, int prio);
CFS线程在 nice=0(prio=120) 的基础上优先级数值加上 prio,对 RT 线程无效,RT线程使用 sched_setscheduler 设置优先级。优先级往低处设置不需要权限,优先级往高处设置需要相应的权限。参考《linux能力机制》
3. Native函数
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
初始化attr,设置调度优先级,若是RT策略,param->sched_priority取值1-99,设置后对应优先级数值为99-param->sched_priority,若是CFS策略,param->sched_priority必须为0.
int androidSetThreadPriority(pid_t tid, int pri) //android/system/core/libutils/Threads.cpp
4. 上层函数
native void setThreadPriority(int tid, int priority) //Process.java
通过 android_util_Process.cpp 这个JNI文件中调用setpriority函数实现。
5. 命令行工具
renice -n 2 -p <pid>
优先级数值加 2,也可以为负值。
三、绑核设置
1. 内核函数
void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) 衍生函数: set_cpus_allowed_common set_cpus_allowed_ptr
2. 系统调用
int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
cpusetsize 为 sizeof(cpu_set_t),可以 "man sched_setaffinity" 和 "$ man CPU_ZERO" 查看使用方法。看 /proc/pid/status 的 Cpus_allowed 查看设置成功情况。设置后此任务只能跑在设定的CPU上,即使被设置的CPU上和忙其它CPU很空闲,也不能被 balance 到其它CPU核上。
3. Native函数
待补充,目前还没发现有,但是Native函数可以直接使用系统调用。
4. 上层函数
待补充,目前还没发现有,但是自己可以在 Process.java 中进行封装后使用。
5. 命令行工具
taskset -p 0f <pid>
将线程pid绑定到 CPU0-CPU3,注意是 0f 而不是 0x0f.
6. cgroup 设置
cpuset分组,每个分组tasks文件里面的任务绑定到cpus文件指定的cpu上,可以通过下面方法查看
# find ./ -name cpus
# find ./ -name cpus | xargs cat
四、Demo
#include <sched.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/time.h> #include <sys/resource.h> #include <linux/capability.h> #if 0 int main() { int ret; struct sched_param param = {.sched_priority = 10}; ret = sched_setscheduler(0, SCHED_FIFO, ¶m); if (ret) { printf("sched_setscheduler error, ret=%d: %s ", ret, strerror(errno)); //need 权限 return -1; } printf("my pid=%d ", getpid()); ret = setpriority(PRIO_PROCESS, getpid(), 20); if (ret) { printf("setpriority error, ret=%d: %s ", ret, strerror(errno)); //need 权限 return -1; } while(1); return 0; } /* policy : 1 prio : 89 */ #endif int main() { int ret; __user_cap_header_struct hdr; __user_cap_data_struct data; #if 0 struct sched_param param = {.sched_priority = 0}; ret = sched_setscheduler(0, SCHED_OTHER, ¶m); if (ret) { printf("sched_setscheduler error, ret=%d: %s ", ret, strerror(errno)); //need root权限 return -1; } #endif printf("my pid=%d ", getpid()); nice(5); #if 1 hdr.version = _LINUX_CAPABILITY_VERSION; //setcaps hdr.pid = getpid(); data.effective = (1 << CAP_SYS_NICE); data.permitted = (1 << CAP_SYS_NICE); data.inheritable = 0xffffffff; if (-1 == capset(&hdr, &data)) { printf("capset %s",strerror(errno)); return -1; } ret = setpriority(PRIO_PROCESS, getpid(), -10); //在nice=0(prio=120)的基础上加10,无论之前优先级是多少 if (ret) { printf("setpriority error, ret=%d: %s ", ret, strerror(errno)); //need root权限 return -1; } #endif #if 0 ret = setpriority(PRIO_PROCESS, getpid(), 5); //重复设置报错没权限 if (ret) { printf("setpriority 2 error, ret=%d: %s ", ret, strerror(errno)); //need root权限 return -1; } #endif while(1); return 0; }