首页 > 技术文章 > 调度器1—相关接口和命令行工具

hellokitty2 2021-10-01 11:39 原文

一、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;
}

 

推荐阅读