首页 > 解决方案 > CentOS8实时FIFO进程未收到XCPU信号

问题描述

背景

我有一个非常精确的计划,我需要为此使用实时调度策略。该程序应该做什么是不可能的。不过,在编写实际程序之前,我想测试一些东西——实时和“正常”调度策略之间的一些差异(例如,我注意到 nanosleep 的实时 FIFO 精度提高了 10 倍调度和 99 优先级),当然还有 SIGXCPU 信号,如果它一次超过软允许的 CPU 时间,则应该将其发送到实时进程。尽管我的进程正在无限循环地消耗 CPU 时间,但我没有收到它。

环境

我正在使用托管在 vultr 上的 CentOS8 - 1 个核心、512MB RAM、最新版本的内核和每个软件包。没有我的实时进程运行,top显示 2-3 个进程正在运行(systemd是主要进程)和 80 多个睡眠。活动进程似乎都有正常的调度策略,优先级设置为 20,这是最低的。
我的实时进程的代码如下所示:

#define _GNU_SOURCE

// most of these are useless yes, were used before for testing
// and I just did not care to remove them, but that shouldn't change anything, right

#include <sched.h>
#include <unistd.h>
#include <sys/types.h>

#include <stdio.h>
#include <stdatomic.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

static uint64_t GetTimeoutTime(const uint64_t nanoseconds) {
  struct timespec tp = { .tv_sec = 0, .tv_nsec = 0 };
  (void) clock_gettime(CLOCK_MONOTONIC, &tp);
  return (uint64_t)(tp.tv_sec) * 1000000000 + (uint64_t)(nanoseconds / 1000000000) * 1000000000 + (uint64_t)(tp.tv_nsec) + nanoseconds - (uint64_t)(nanoseconds / 1000000000) * 1000000000;
}

static int siga(int signum, void (*handler)(int)) {
  return sigaction(signum, &((struct sigaction){ .sa_handler = handler, .sa_flags = 0, .sa_mask = 0 }), NULL);
}

static void xcpu(int sig) {
  puts("xcpu called");
  (void) pthread_yield(); // to not get killed
}

int main() {
  uint64_t g = 0;
  uint64_t t1, t2;
  int err = siga(SIGXCPU, xcpu);
  if(err != 0) {
    puts("e");
    printf("%d\n", err);
  }
  if(sched_setscheduler(getpid(), SCHED_FIFO, &((struct sched_param){ .sched_priority = 99 })) != 0) {
    puts("err");
  }
  while(1) {
    t1 = GetTimeoutTime(0); // just some stuff to make the process busy
    t2 = GetTimeoutTime(0) - t1; // I was using this code before, thus left it there
    g += t2;
  }
  printf("avg %lf\n", (double)(g) / 10000.0); // just to make it seem as g is not useless
  return 0;
}

结果是 - 进程不断占用 90% 以上的 CPU,运行和运行,并且看不到接收到任何信号。我实际上让程序运行了大约 15 分钟,但什么也没发生 - 进程没有被杀死。我的意思是,FIFO调度不应该在线程运行时删除它们,对吗?这就是 Round Robin 所做的,所以我不太明白是什么导致了这种现象。我的线程是否在我不知情的情况下进入睡眠状态?
将截止时间设置为某个 2^63 - (1, 2, 3) 数字的 DEADLINE 调度会比当前的 FIFO 解决方案更好吗?我只是想在大多数时候为自己获得大部分 CPU,因为实际上除了我自己的进程将使用 CPU(唯一的区别是实时调度策略提供了一些好处,其中之一)我在开始时注意到并描述了 - 提高 nanosleep 的精度。还有其他好处吗?)。

标签: creal-timecentos8

解决方案


好吧,我找到了答案。
问题在于 RTIME 软硬限制。我认为默认情况下它们非常低,但现在我仔细检查以确定。软限制和硬限制都是 2^63 个数字。在将软限制降低到 1e6 和硬限制到 1e7 后,我的进程开始每秒接收 XCPU 信号。getrlimit使用and函数检查和降低setrlimit(有关更多信息,请参阅 man )。


推荐阅读