【问题标题】:what does struct sched_domain stands for in include/linux/sched.h (scheduling domains in kernel)struct sched_domain 在 include/linux/sched.h 中代表什么(在内核中调度域)
【发布时间】:2012-12-23 04:19:12
【问题描述】:

我正在尝试了解负载平衡器如何在 Linux 内核中的多处理器系统上工作,

Linux 调度器基本上使用 runques 来存储它接下来必须运行的任务, 现在考虑多处理器系统的情况 load_balancer() 的实现方式在 Robert Loves 的书 Linux Kernel Development 2nd edition 中给出的解释如下

首先,load_balance() 调用 find_busiest_queue() 来确定 最繁忙的运行队列。换句话说,这是带有 其中进程数最多。如果没有运行队列 比当前进程多 25% 或更多,find_busiest_queue() 返回 NULL 和 load_balance() 返回。否则,最繁忙的运行队列是 返回。

其次,load_balance() 决定哪个优先级数组最忙 它想从中拉出的运行队列。首选过期数组,因为 这些任务在相对较长的时间内没有运行,因此大多数 可能不在处理器的缓存中(也就是说,它们不是缓存热的)。 如果过期的优先级数组为空,则只有活动的优先级数组 选择。

接下来,load_balance() 查找最高优先级(最小值)列表 有任务,因为公平分配高 优先级任务高于优先级较低的任务。

分析给定优先级的每个任务,找到一个任务 未运行,未阻止通过处理器关联进行迁移,并且未阻止 缓存热。如果任务满足此条件,则调用 pull_task() 以 将任务从最繁忙的运行队列拉到当前运行队列。

只要runqueues保持不平衡,前两步就是 重复和更多的任务从最繁忙的运行队列拉到 当前的。最后,当不平衡解决时,当前的runqueue 已解锁并且 load_balance() 返回。

代码如下

static int load_balance(int this_cpu, runqueue_t *this_rq,
                        struct sched_domain *sd, enum idle_type idle)
{
        struct sched_group *group;
        runqueue_t *busiest;
        unsigned long imbalance;
        int nr_moved;

        spin_lock(&this_rq->lock);

        group = find_busiest_group(sd, this_cpu, &imbalance, idle);
        if (!group)
                goto out_balanced;

        busiest = find_busiest_queue(group);
        if (!busiest)
                goto out_balanced;

        nr_moved = 0;
        if (busiest->nr_running > 1) {
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
                                      imbalance, sd, idle);
                spin_unlock(&busiest->lock);
        }
        spin_unlock(&this_rq->lock);

        if (!nr_moved) {
                sd->nr_balance_failed++;

                if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
                        int wake = 0;

                        spin_lock(&busiest->lock);
                        if (!busiest->active_balance) {
                                busiest->active_balance = 1;
                                busiest->push_cpu = this_cpu;
                                wake = 1;
                        }
                        spin_unlock(&busiest->lock);
                        if (wake)
                                wake_up_process(busiest->migration_thread);
                        sd->nr_balance_failed = sd->cache_nice_tries;
                }
        } else
                sd->nr_balance_failed = 0;

        sd->balance_interval = sd->min_interval;

        return nr_moved;

out_balanced:
        spin_unlock(&this_rq->lock);

        if (sd->balance_interval < sd->max_interval)
                sd->balance_interval *= 2;

        return 0; 
}

我不清楚的是上面代码中的结构 struct sched_domain *sd 我检查的这个结构定义在 包括/linux/sched.h如下 http://lxr.linux.no/linux+v3.7.1/include/linux/sched.h#L895 这是一个很大的结构,所以为了简单起见,我只给出了一个链接。 我想知道的是上面代码中struct sched_domain有什么用?

为什么在调用 load_balancer() 时使用这个结构体代表什么?

这里可能给出了一些东西 http://www.kernel.org/doc/Documentation/scheduler/sched-domains.txt 为什么 CPU 需要调度域?这些域名代表什么?

【问题讨论】:

    标签: c kernel intel scheduler processor


    【解决方案1】:

    调度域和调度程序组/cpu 组有助于缓解 调度任务的过程,例如:

    1. 跨 CPU 的负载平衡任务。
    2. 为要运行的新任务选择 CPU。
    3. 为睡眠任务选择一个 CPU,以便在它醒来时运行。

    它有两个优点:

    1. 它将系统中的 CPU 很好地组织成组和层次结构。

    2. 它以一种有用的方式组织 cpus。所有 cpus
      共享一个 l2 缓存属于一个域。共享一个 l3 缓存的所有 cpu
      属于更高层次的域,它包含了所有的域
      共享 l2 缓存。

    你看到的树状数据结构的优点是相似的 这里是调度程序域和组的优势。

    参考下图

         _________sd1________
        /                    \
        ----------------------
             l3 cache
        ----------------------
        ---------   ----------
        l2 cache    l2 cache
        ---------   ----------
        cpu0 cpu1   cpu2 cpu3
        \_______/   \________/
          sd0          sd0
    
     ________sd1_________
    /                    \
    ----------------------
          l3 cache
    ----------------------
    ---------   ----------
    l2 cache    l2 cache
    ---------   ----------
    cpu4 cpu5   cpu6 cpu7
    \_______/   \________/
      sd0          sd0
    

    您在上面看到的是调度程序域层次结构。sd1 包含 sd0s 恰好是 sd1 的调度程序组。每个 cpu 都有一个调度程序 与之关联的域层次结构。例如。
    cpu0->sd=sd0; sd0->parent=sd1.这样通过链表我们可以 遍历一个 cpu 所属的所有调度器域。

    这有什么帮助?

    1.负载均衡:说cpu0是空闲的,准备拉任务 本身来减轻任何其他负担的cpu。在上述方法中,它首先 检查是否属于第一级 sched 域的其他 cpu ,需要减轻负载。这里,cpu1。如果是这样,它会从 cpu1,否则转到更高级别的域sd1。如果它选择 从 cpu1 迁移任务是最好的,因为缓存内容 可以使用;共享缓存。无需再次从内存中获取。这是 第一个优势:sched域是基于优势形成的 硬件必须提供。

    如果它去 sd1,那么它会探测 sd1 的“组”,都是 sd0s。这里是 下一个优势。它只需要有关 sched 组的信息,并且 不会打扰其中的单个cpu。它会检查是否 负载(sd0[cpu2,cpu3]) > 负载(sd0[cpu0,cpu1]) 只有当这是真的时,它才会继续查看 cpu2/3 是否加载更多。如果 没有调度程序域或组,我们必须查看状态 cpu2 和 cpu3 在两次迭代中,而不是像我们这样的 1 次迭代 现在做。

    现在将此问题和解决方案扩展到 128 cpu!想象一下有多乱 如果没有什么可以告诉你哪个 cpu 将是 最好减轻负载,在最坏的情况下,您将不得不迭代 通过所有 128 cpu。

    但是对于调度程序域或组,假设您将 128 个 cpu 划分为 16 个 cpu 的组,你会有 8 个组。看看哪个是最忙的,所以 那将是 8 次迭代,然后你会知道最繁忙的组,然后 下降。另外 16 次迭代。所以最坏的情况

    8+16 = 24 次迭代。而这种减少仅适用于一级 sched 领域。想象一下,如果你有更多的关卡,你会做出 迭代次数甚至更低。

    因此,简而言之,调度程序域和组是“分而治之”的 ;但尽可能地征服更有用的解决方案 安排相关的事情。

    我发帖以防将来有人想阅读它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-16
      • 2013-08-31
      • 2020-07-17
      相关资源
      最近更新 更多