CentOS8实时FIFO进程收不到XCPU信号
CentOS8 real-time FIFO process not receiving XCPU signal
背景
我有一个非常精确的程序,我需要为它使用实时调度策略。该程序应该做什么是不可能的。不过,在编写实际程序之前,我想稍微测试一下 - 实时和“正常”调度策略之间的一些差异(例如,我注意到 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;
}
结果是 - 进程不断占用 CPU、运行 和 运行 的 90% 以上,并且没有看到接收到信号。实际上,我将程序 运行 保留了大约 15 分钟,但什么也没有发生——进程没有被杀死。我的意思是,FIFO 调度不应该在 运行 时删除线程,对吗?这就是 Round Robin 所做的,所以我不太明白是什么导致了这种现象。我的线程是否在我不知情的情况下进入睡眠状态?
将截止时间设置为 2^63 - (1, 2, 3) 数字的 DEADLINE 调度是否会比当前的 FIFO 解决方案更好?大多数时候我只是想为自己获得大部分 CPU,因为除了我自己的进程之外真的什么都不会使用 CPU(唯一的区别是实时调度策略给一些额外的好处,其中一个我在开头注意到并描述过 - 提高了 nanosleep 的精度。还有其他好处吗?)。
好的,我找到答案了。
问题在于 RTIME 的软硬限制。我认为默认情况下它们非常低,但现在我仔细检查以确保。软硬限制均为 2^63 个数字。在将软限制降低到 1e6 和硬限制到 1e7 之后,我的进程开始每秒接收 XCPU 信号。使用 getrlimit
和 setrlimit
函数检查并降低(有关更多信息,请参阅 man)。
背景
我有一个非常精确的程序,我需要为它使用实时调度策略。该程序应该做什么是不可能的。不过,在编写实际程序之前,我想稍微测试一下 - 实时和“正常”调度策略之间的一些差异(例如,我注意到 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;
}
结果是 - 进程不断占用 CPU、运行 和 运行 的 90% 以上,并且没有看到接收到信号。实际上,我将程序 运行 保留了大约 15 分钟,但什么也没有发生——进程没有被杀死。我的意思是,FIFO 调度不应该在 运行 时删除线程,对吗?这就是 Round Robin 所做的,所以我不太明白是什么导致了这种现象。我的线程是否在我不知情的情况下进入睡眠状态?
将截止时间设置为 2^63 - (1, 2, 3) 数字的 DEADLINE 调度是否会比当前的 FIFO 解决方案更好?大多数时候我只是想为自己获得大部分 CPU,因为除了我自己的进程之外真的什么都不会使用 CPU(唯一的区别是实时调度策略给一些额外的好处,其中一个我在开头注意到并描述过 - 提高了 nanosleep 的精度。还有其他好处吗?)。
好的,我找到答案了。
问题在于 RTIME 的软硬限制。我认为默认情况下它们非常低,但现在我仔细检查以确保。软硬限制均为 2^63 个数字。在将软限制降低到 1e6 和硬限制到 1e7 之后,我的进程开始每秒接收 XCPU 信号。使用 getrlimit
和 setrlimit
函数检查并降低(有关更多信息,请参阅 man)。