Linux sched_setaffinity()用于sched_截止日期

Linux sched_setaffinity()用于sched_截止日期,linux,linux-kernel,operating-system,scheduled-tasks,scheduling,Linux,Linux Kernel,Operating System,Scheduled Tasks,Scheduling,在linux中,有没有一种方法可以使用截止日期调度,同时设置cpu与进程的关联性?我正在运行4.16内核。下面是我的测试代码: #define _GNU_SOURCE #include "include/my_sched.h" #include <stdio.h> #include <time.h> #include <sys/time.h> int main() { struct sched_attr attr; int x = 0;

在linux中,有没有一种方法可以使用截止日期调度,同时设置cpu与进程的关联性?我正在运行4.16内核。下面是我的测试代码:

#define _GNU_SOURCE
#include "include/my_sched.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>

int main() {
    struct sched_attr attr;
    int x = 0;
    int ret;
    unsigned int flags = 0;
    long int tid = gettid();

    printf("deadline thread started [%ld]\n", tid);

    /* Set scheduling properties */
    attr.size = sizeof(attr);
    attr.sched_flags = 0;
    attr.sched_nice = 0;
    attr.sched_priority = 0;

    /* This creates a 100ms/300ms reservation */
    attr.sched_policy = SCHED_DEADLINE;
    attr.sched_runtime = 100 * 1000 * 1000;
    attr.sched_period = attr.sched_deadline = 300 * 1000 * 1000;

    ret = sched_setattr(0, &attr, flags);
    if (ret != 0) {
        done = 0;
        perror("sched_setattr");
        printf("exit!\n");
        exit(-1);
    }

    /* Set CPU affinity */
    cpu_set_t  mask;
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    ret = sched_setaffinity(0, sizeof(mask), &mask);

    if (ret != 0) {
        done = 0;
        perror("sched_setaffinity");
        printf("exit!\n");
        exit(-1);
    }


    return 0;
}
如果交换sched_setattr()和sched_setaffinity()的顺序,则会出现不同的错误:

sched_setattr: Operation not permitted
即使我在sudo,这种情况也会发生

我的代码有问题吗?为什么我不能在同一个程序中使用sched_setaffinity()和sched_setattr()来安排截止日期

对于任何有兴趣编译和尝试该程序的人,下面是my_include.h的代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <linux/unistd.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <sys/syscall.h>
#include <pthread.h>

#define gettid() syscall(__NR_gettid)

#define SCHED_DEADLINE  6

/* XXX use the proper syscall numbers */
#ifdef __x86_64__
#define __NR_sched_setattr      314
#define __NR_sched_getattr      315
#endif

#ifdef __i386__
#define __NR_sched_setattr      351
#define __NR_sched_getattr      352
#endif

#ifdef __arm__
#define __NR_sched_setattr      380
#define __NR_sched_getattr      381
#endif

static volatile int done;

struct sched_attr {
    __u32 size;

    __u32 sched_policy;
    __u64 sched_flags;

    /* SCHED_NORMAL, SCHED_BATCH */
    __s32 sched_nice;

    /* SCHED_FIFO, SCHED_RR */
    __u32 sched_priority;

    /* SCHED_DEADLINE (nsec) */
    __u64 sched_runtime;
    __u64 sched_deadline;
    __u64 sched_period;
};

int sched_setattr(pid_t pid,
        const struct sched_attr *attr,
        unsigned int flags)
{
    return syscall(__NR_sched_setattr, pid, attr, flags);
}

int sched_getattr(pid_t pid,
        struct sched_attr *attr,
        unsigned int size,
        unsigned int flags)
{
    return syscall(__NR_sched_getattr, pid, attr, size, flags);
}

以上两部分对应我前面提到的两个错误。有人能向我解释一下这个评论是什么意思吗?我知道调度域和根域是什么,但我不知道SCHED_DEADLINE task与其他调度策略在调度域方面有什么不同?为什么将SCHED_DEADLINE任务绑定到特定的核心没有意义?

经过一些挖掘,我终于很好地理解了为什么设置关联会导致SCHED_DEADLINE调度器出现问题

对于任何只想将EDF任务绑定到核心子集的人,可以参考第5节。您可以使用cpuset和cgroup实用程序将核心分配给EDF任务

不允许sched_setaffinity()用于sched_截止日期任务是一种保守的方法,可以确保在linux内核中进行有效的可调度性测试。考虑下面的场景,其中机器有9个核心,任务1想要与核心1,2,4,5有亲和力,任务2想要与核心3,4,5,6,7,8有亲和力。

结果表明,如果不同SCHED_截止日期任务的相似性掩码重叠一部分,可调度性测试将成为NP难问题。因此,没有有效的方法来确定任务集是否可调度。针对任意核亲和力的最新可调度性测试需要指数级的计算复杂度。向这种可调度性测试中添加功能将大大降低内核的性能

然而,我认为从内核的角度来看,这是一种实现可调度性的保守方法。这是因为如果linux管理员知道他在做什么,他可以有意识地将所有SCHED_截止日期任务映射到特定的内核子集。在下面的示例中,我们可以将核心1、2、4、5专用于EDF任务。效果与使用cpuset方法没有什么不同。无论如何,sched_setaffinity()能够模拟全局、集群和分区作业级别的固定优先级调度

参考资料:


古吉拉特,A.,塞奎拉,F.,和勃兰登堡,B.B.(2014)。具有任意处理器亲缘关系的多处理机实时调度:从实践到理论。实时系统,51440-483。

经过一些挖掘,我终于很好地理解了为什么设置关联会导致调度程序中出现问题

对于任何只想将EDF任务绑定到核心子集的人,可以参考第5节。您可以使用cpuset和cgroup实用程序将核心分配给EDF任务

不允许sched_setaffinity()用于sched_截止日期任务是一种保守的方法,可以确保在linux内核中进行有效的可调度性测试。考虑下面的场景,其中机器有9个核心,任务1想要与核心1,2,4,5有亲和力,任务2想要与核心3,4,5,6,7,8有亲和力。

结果表明,如果不同SCHED_截止日期任务的相似性掩码重叠一部分,可调度性测试将成为NP难问题。因此,没有有效的方法来确定任务集是否可调度。针对任意核亲和力的最新可调度性测试需要指数级的计算复杂度。向这种可调度性测试中添加功能将大大降低内核的性能

然而,我认为从内核的角度来看,这是一种实现可调度性的保守方法。这是因为如果linux管理员知道他在做什么,他可以有意识地将所有SCHED_截止日期任务映射到特定的内核子集。在下面的示例中,我们可以将核心1、2、4、5专用于EDF任务。效果与使用cpuset方法没有什么不同。无论如何,sched_setaffinity()能够模拟全局、集群和分区作业级别的固定优先级调度

参考资料:

古吉拉特,A.,塞奎拉,F.,和勃兰登堡,B.B.(2014)。具有任意处理器亲缘关系的多处理机实时调度:从实践到理论。实时系统,51440-483

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <linux/unistd.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <sys/syscall.h>
#include <pthread.h>

#define gettid() syscall(__NR_gettid)

#define SCHED_DEADLINE  6

/* XXX use the proper syscall numbers */
#ifdef __x86_64__
#define __NR_sched_setattr      314
#define __NR_sched_getattr      315
#endif

#ifdef __i386__
#define __NR_sched_setattr      351
#define __NR_sched_getattr      352
#endif

#ifdef __arm__
#define __NR_sched_setattr      380
#define __NR_sched_getattr      381
#endif

static volatile int done;

struct sched_attr {
    __u32 size;

    __u32 sched_policy;
    __u64 sched_flags;

    /* SCHED_NORMAL, SCHED_BATCH */
    __s32 sched_nice;

    /* SCHED_FIFO, SCHED_RR */
    __u32 sched_priority;

    /* SCHED_DEADLINE (nsec) */
    __u64 sched_runtime;
    __u64 sched_deadline;
    __u64 sched_period;
};

int sched_setattr(pid_t pid,
        const struct sched_attr *attr,
        unsigned int flags)
{
    return syscall(__NR_sched_setattr, pid, attr, flags);
}

int sched_getattr(pid_t pid,
        struct sched_attr *attr,
        unsigned int size,
        unsigned int flags)
{
    return syscall(__NR_sched_getattr, pid, attr, size, flags);
}
/*
 * Don't allow tasks with an affinity mask smaller than
 * the entire root_domain to become SCHED_DEADLINE. We
 * will also fail if there's no bandwidth available.
 */
if (!cpumask_subset(span, &p->cpus_allowed) ||
    rq->rd->dl_bw.bw == 0) {
    task_rq_unlock(rq, p, &rf);
    return -EPERM;
}

... 

/*
 * Since bandwidth control happens on root_domain basis,
 * if admission test is enabled, we only admit -deadline
 * tasks allowed to run on all the CPUs in the task's
 * root_domain.
 */
#ifdef CONFIG_SMP
if (task_has_dl_policy(p) && dl_bandwidth_enabled()) {
    rcu_read_lock();
    if (!cpumask_subset(task_rq(p)->rd->span, new_mask)) {
        retval = -EBUSY;
        rcu_read_unlock();
        goto out_free_new_mask;
    }
    rcu_read_unlock();
}