【问题标题】:Posix Timer on SCHED_RR Thread is using 100% CPUSCHED_RR 线程上的 Posix 计时器正在使用 100% 的 CPU
【发布时间】:2019-12-15 13:26:23
【问题描述】:

我有以下代码sn-p:

#include <iostream>
#include <thread>

#include <unistd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>

int main() {
    std::thread rr_thread([](){
      struct sched_param params = {5};
      pthread_setschedparam(pthread_self(), SCHED_RR, &params);

      struct itimerspec ts;
      struct epoll_event ev;
      int tfd ,epfd;

      ts.it_interval.tv_sec = 0;
        ts.it_interval.tv_nsec = 0;
        ts.it_value.tv_sec = 0;
        ts.it_value.tv_nsec = 20000; // 50 kHz timer

      tfd = timerfd_create(CLOCK_MONOTONIC, 0);
      timerfd_settime(tfd, 0, &ts, NULL);
      epfd = epoll_create(1);

      ev.events = EPOLLIN;
      epoll_ctl(epfd, EPOLL_CTL_ADD, tfd, &ev);

      while (true) {
        epoll_wait(epfd, &ev, 1, -1); // wait forever for the timer
        read(tfd, &missed, sizeof(missed));

        // Here i have a blocking function (dummy in this example) which
        // takes on average 15ns to execute, less than the timer period anyways
        func15ns();
      }

    });

    rr_thread.join();
}

我有一个使用 SCHED_RR 策略的 posix 线程,在这个线程上有一个 POSIX 计时器正在运行,超时时间为 20000ns = 50KHz = 50000 滴答/秒。

定时器触发后,我正在执行一个比定时器周期少大约 15ns 的函数,但这并不重要。

当我执行此操作时,我得到 100% 的 CPU 使用率,整个系统变慢,但我不明白为什么会发生这种情况,而且有些事情令人困惑。

  1. 为什么 100% 的 CPU 使用率,因为线程应该在等待计时器触发时处于休眠状态,所以理论上可以安排其他任务,对吗?即使这是一个高优先级线程。

  2. 我使用 pidstat 检查了上下文切换的数量,它似乎非常小,接近 0,无论是自愿的还是非自愿的。这是正常的吗?在等待计时器触发调度程序时,应该安排其他任务吗?我应该看到至少 20000 * 2 上下文切换/秒

【问题讨论】:

  • 50 kHz 对于计时器来说是非常核心的。如果您能得到它,那么您将花费大量时间对其进行维修。
  • @JohnBollinger 是的,对不起,我的错,来晚了,我会改变的
  • 我不确定 50kHz 在大多数常见硬件上是否可行。计时器很可能“尽可能快”地关闭(因此 CPU 使用率为 100%),但不是每秒 50,000 次。

标签: c++ linux pthreads scheduled-tasks scheduler


【解决方案1】:

如前所述,您的程序不像您描述的那样运行。这是因为您将计时器编程为一次性计时器,而不是重复计时器。对于每 20000 ns 触发的计时器,您需要设置 20000-ns 间隔:

    ts.it_interval.tv_nsec = 20000;

修改后,我得到了一个可以在一个内核上产生重负载的程序。

  1. 为什么 100% CPU 使用率,因为线程应该在等待计时器触发时处于休眠状态,因此可以安排其他任务 理论上对吗?即使这是一个高优先级线程。

当然,您的线程在epoll_wait() 中阻塞以等待计时器滴答,如果事实上它设法在计时器再次滴答之前循环回到那里。在我的机器上,你的程序只消耗一个内核的 30% 左右,这似乎证实了这种阻塞确实会发生。您看到 100% 的 CPU 使用率表明无论出于何种原因,我的计算机运行程序的效率都比您的高。

但您必须意识到负载非常很重。您要求每 20000 ns 执行一次计时器本身、epoll 调用、读取和func15ns() 的所有处理。是的,无论剩下多少时间,如果有的话,都可以安排另一个任务,但是任务交换又需要更多时间。 20000 ns 不是很多时间。考虑一下fetching a word from main memory costs about 100 ns(虽然从缓存中读取一个当然更快)。

尤其不要忽视func15ns()以外的工作。如果后者确实只需要 15 ns 即可运行,那么您最不必担心。您正在执行两个系统调用,这些调用很昂贵。到底有多贵取决于很多因素,但考虑到删除 epoll_wait() 调用将我的核心负载从 30% 减少到 25%(请注意,整个 epoll 设置在这里是多余的,因为只需允许 @987654327 @ 阻止服务的目的)。

  1. 我用pidstat检查了上下文切换的次数,似乎很小,接近0,自愿和非自愿 那些。这是正常的吗?在等待计时器触发 调度程序应该安排其他任务吗?我至少应该看到 20000 * 2 次上下文切换/秒

您正在为一个高优先级任务占用一个完整的 CPU,那么您为什么要切换?

另一方面,我还观察到运行(修改后的)程序的进程的上下文切换次数很少,尽管它只占用了 25% 的内核。我目前还没有准备好解释为什么会这样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多