为什么使用任务集在一组独立的内核上运行多线程 Linux 程序会导致所有线程在一个内核上运行?

2024-02-28

期望的行为:在一组已使用隔离的内核上运行多线程 Linux 程序isolcpus.

这是一个小程序,我们可以用作多线程程序的示例:

#include <stdio.h>
#include <pthread.h>
#include <err.h>
#include <unistd.h>
#include <stdlib.h>

#define NTHR    16
#define TIME    60 * 5

void *
do_stuff(void *arg)
{
    int i = 0;

    (void) arg;
    while (1) {
        i += i;
        usleep(10000); /* dont dominate CPU */
    }
}

int
main(void)
{
    pthread_t   threads[NTHR];
    int     rv, i;

    for (i = 0; i < NTHR; i++) {
        rv = pthread_create(&threads[i], NULL, do_stuff, NULL);
        if (rv) {
            perror("pthread_create");
            return (EXIT_FAILURE);
        }
    }
    sleep(TIME);
    exit(EXIT_SUCCESS);
}

如果我在没有独立 CPU 的内核上编译并运行它,那么线程将分布在我的 4 个 CPU 上。好的!

现在如果我添加isolcpus=2,3到内核​​命令行并重新启动:

  • 在没有任务集的情况下运行程序会将线程分配到核心 0 和 1。这是预期的,因为默认关联掩码现在排除了核心 2 和 3。
  • 跑步与taskset -c 0,1具有相同的效果。好的。
  • 跑步与taskset -c 2,3导致所有线程进入同一个核心(核心 2 或核心 3)。这是不希望的。线程应该分布在核心 2 和 3 上。对吗?

这个帖子 https://serverfault.com/questions/573025/taskset-not-working-over-a-range-of-cores-in-isolcpus描述了类似的问题(尽管给出的示例距离 pthreads API 更远)。 OP 很乐意通过使用不同的调度程序来解决这个问题。不过,我不确定这是否适合我的用例。

有没有办法使用默认调度程序将线程分布在独立的核心上?

这是我应该报告的内核错误吗?

EDIT:

如果您使用像 fifo 调度程序这样的实时调度程序,正确的事情确实会发生。看man sched and man chrt了解详情。


来自 Linux 内核参数文档:

该选项可用于指定一个或多个要隔离的 CPU 通用 SMP 平衡和调度算法。

因此,此选项将有效防止调度程序将线程从一个核心迁移到另一个竞争较少的核心(SMP 平衡)。由于典型的 isolcpu 与 pthread 亲和力控制一起使用,以通过了解 CPU 布局来固定线程,以获得可预测的性能。

https://www.kernel.org/doc/Documentation/kernel-parameters.txt https://www.kernel.org/doc/Documentation/kernel-parameters.txt

--Edit--

好吧,我明白你为什么感到困惑了。是的,我个人认为这个选项的行为是一致的。问题在于两个函数:select_task_rq_fair 和 select_task_rq_rt,它们负责选择新的 run_queue(本质上是选择要在哪个 next_cpu 上运行)。我对这两个函数进行了快速跟踪(Systemtap),对于 CFS,它总是在掩码中返回相同的第一个核心;对于 RT,它将返回其他核心。我没有机会研究每个选择算法中的逻辑,但您可以向 Linux devel 邮件列表中的维护者发送电子邮件进行修复。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么使用任务集在一组独立的内核上运行多线程 Linux 程序会导致所有线程在一个内核上运行? 的相关文章

随机推荐