Linux 2.6.31调度程序和多线程作业

6
我在一台拥有24核的共享Linux计算机上运行大规模并行科学计算作业。当这台计算机上没有其他任务运行时,我的作业通常可以扩展到24个核心。但是,即使有一个单线程的非我自己的作业正在运行,我的24线程作业(我将其设置为高优先级)似乎也只能获得约1800%的CPU(使用Linux表示法)。同时,大约500%的CPU周期(再次使用Linux表示法)处于空闲状态。有人能解释这种行为以及我该怎么做才能获得其他未被他人使用的23个核心吗?
注: 1. 如果相关,我曾在略微不同的内核版本上观察到这种情况,尽管我无法立即记住具体是哪个版本。 2. CPU架构是x64。我的24核心作业是32位的,而我正在竞争的其他作业是64位的,这是否相关?
编辑:我刚刚注意到的一件事是,增加到30个线程似乎在一定程度上缓解了问题。它让我达到了约2100%的CPU。

重新设置优先级只会影响您所拥有的进程,如果只运行一个产生 n 个线程的进程...那么...您只与单个进程竞争。该机器上是否有 root / sudo 权限? - Tim Post
如果您将线程数降至23个,为其他作业留出一个核心,会发生什么? - caf
5个回答

7
可能是由于调度程序试图让每个任务在之前运行的同一CPU上继续运行(这是因为该任务可能已经将其工作集带入了该CPU的缓存中 - 它是“缓存热点”),从而导致此问题的出现。
以下是您可以尝试的几个方法:
  • 运行两倍于您拥有的核心数的线程;
  • 运行比您拥有的核心数少一到两个线程;
  • 降低/ proc / sys / kernel / sched_migration_cost 的值(可能降至零);
  • / proc / sys / kernel / sched_domain / ... / imbalance_pct 的值降低到接近100。

2
如果你的线程需要同步,那么你可能会遇到以下问题:
假设你有一个4核CPU系统和一个由4个线程组成的任务。当单独运行时,线程会扇出并使用所有4个核心,总使用率接近完美(我们称之为400%)。
如果添加一个单线程干扰任务,则调度程序可能会将你的2个线程放置在同一个CPU上。这意味着你的2个线程现在以实际上正常速度的一半运行(戏剧性地简化),如果你的线程需要定期同步,则作业的进度可能会受到最慢线程的限制,在这种情况下,最慢线程以正常速度的一半运行。您将看到仅利用了200%(从您的工作运行4x 50%)加上100%(干扰工作)= 300%。
同样地,如果您假设干扰工作仅使用一个处理器时间的25%,则您可能会看到其中一个线程和干扰者在同一个CPU上。在这种情况下,最慢的线程以3/4正常速度运行,导致总利用率为300%(4x 75%)+ 25%= 325%。玩弄这些数字并不难得出类似于您所看到的东西。
如果是这个问题,你可以尝试调整优先级,只给不受欢迎的任务极小的CPU份额(假设I/O延迟不是一个因素)。或者,像你发现的那样,尝试增加线程数,以便每个CPU有2个线程,减去一些以供系统任务使用。以这种方式,一个24核心系统可能最佳运行46个线程(总是留下2个核心时间的一半用于系统任务)。

当然,Caf建议使用23个线程比我的建议46个线程更好,以获得2300%的利用率。 - Eric Seppanen

1

你的线程之间是否进行通信?

尝试使用 sched_setaffinitypthread_setaffinity_np 手动绑定每个线程到 CPU。当处理大量相关线程时,调度程序可能会变得相当愚笨。


0
你认为瓶颈在你的应用程序还是内核的调度算法中?在开始调整调度参数之前,我建议你尝试运行一个简单的多线程应用程序,看看它是否表现出与你的应用程序相同的行为。
// COMPILE WITH: gcc threads.c -lpthread -o thread
#include <pthread.h>
#define NUM_CORES 24

void* loop_forever(void* argument) {
    int a;
    while(1) a++;
}

void main() {
    int i;
    pthread_t threads[NUM_CORES];

    for (i = 0; i < NUM_CORES; i++)
        pthread_create(&threads[i], 0, loop_forever, 0);

    for (i = 0; i < NUM_CORES; i++)
        pthread_join(threads[i], 0);
}

0

使用mpstatsysstat软件包的一部分)可能是值得的,以确定是否有整个CPU处于空闲状态,而其他CPU则完全被利用。它应该会给你比top或vmstat更详细的利用率视图:运行mpstat -P ALL以查看每个CPU的1行。

作为一个实验,您可以尝试设置每个线程的CPU亲和力,使每个线程都绑定到单独的CPU;这将让您看到如果不让内核调度程序决定任务在哪个CPU上调度时的性能如何。这不是一个好的永久解决方案,但如果它有很大帮助,它可以让您了解调度程序的不足之处。


很遗憾,我没有管理员权限,也没有安装sysstat。 - dsimcha
1
从源代码构建sysstat并不难。 - Eric Seppanen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接