Skip to main content
 首页 » 操作系统

Linux 调度器之相关接口和命令行工具

2022年07月19日209del

一、CPU调度策略设置

1. 内核函数

int sched_setscheduler(struct task_struct *p, int policy, const struct sched_param *param) 
衍生函数: 
sched_setscheduler_nocheck

内核中设置为RT线程举例:

struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; //100-1 
sched_setscheduler_nocheck(cluster->core_ctl_thread, SCHED_FIFO, &param); 
 
# cat /proc/459/sched 
policy                                       :                    1 //SCHED_FIFO 
prio                                         :                    0 //最高RT优先级

内核中调用这个接口设置优先级使用的还是用户空间的优先级,最大为99,在内核中cat /proc/pid/sched 看就是0,对应内核中最高优先级。

设置内核线程调度策略和优先级,优先级设置只对RT线程有效。

2. 系统调用

int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); 
int sched_getscheduler(pid_t pid);

若要设置为RT,需要root权限,此时cat /proc/pid/sched看到的normal的优先级数值为99-param->sched_priority;若设置为CFS,param->sched_priority必须为0。实现文件为kernel/sched/core.c。

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)线程,优先级设置为用户空间的15,在内核中对应的是99-15=84,cat /proc/pid/sched看到的就是84.

二、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 线程无效,实现文件kernel/sys.c。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, &param); 
        if (ret) { 
            printf("sched_setscheduler error, ret=%d: %s\n", ret, strerror(errno)); //need 权限 
            return -1; 
        } 
 
        printf("my pid=%d\n", getpid()); 
 
        ret = setpriority(PRIO_PROCESS, getpid(), 20); 
        if (ret) { 
            printf("setpriority error, ret=%d: %s\n", 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, &param); 
    if (ret) { 
            printf("sched_setscheduler error, ret=%d: %s\n", ret, strerror(errno)); //need root权限 
            return -1; 
    } 
    #endif 
 
    printf("my pid=%d\n", 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\n", 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\n", ret, strerror(errno)); //need root权限 
        return -1; 
    } 
    #endif 
 
    while(1); 
 
    return 0; 
}

本文参考链接:https://www.cnblogs.com/hellokitty2/p/15359075.html