psi:poll机制bug修复

本文详细探讨了Facebook提出的PSI(Pressure Stall Information)机制的技术细节,重点解析了PSI在内核中的工作原理,包括触发机制、守护进程的创建与销毁流程等。并通过一个具体的bug案例,展示了如何定位和解决问题。
部署运行你感兴趣的模型镜像

前言:

  1. 本文是纯技术细节文档,不涉及PSI整体机制等内容。
  2. 本文以bug为驱动,写下调查跟踪思路,和定位方法。

 

一、简介

PSI = Pressure Stall Information,由facebook提出的新特性,目的是结合cgroup用于监控内核三大项数据memory/cpu/io。

 

必备的关键词:

  1. trigger:当用户对/proc/pressure/{cpu, io, mem}三个文件任意一个发起poll监听,内核则会创建trigger,因此trigger可以有多个。
  2. psi poll work:即为[psimon]进程,是指的内核psi模块的用于监听poll事件的守护进程,内核中代码是用group->poll_work来表示。此进程只有一个,只有当trigger数量减为0时,此进程才能被销毁。

 

二、背景

在内核源码树中的Documentation/accounting/psi.txt文件介绍了PSI的基本概念,并给出了如何监控(monitor)PSI文件。给出的代码思路如下:通过poll函数发起对/proc/pressure/io(psi.txt是mem)文件的监听,如果内核中有事件接受到,则用户态返回接受数值,正常情况是能够“event triggered"。

但是,当第一次poll监听程序发起后正常退出,第二次以及后面更多次再重新启动poll监听,会发现总是无法得到内核的事件返回值。这个就是很明显的bug,我们要动手开始去解决!

 

三、PSI原理分析

内核态关键函数:

  1. poll对接函数:psi_fop_poll()->psi_trigger_poll();此函数是用户态发起poll()系统调用后,会有psi此函数对接,检查在此poll之前的时间内是否有事件发生,如果有则设置相应事件signal,如果无则通过poll_wait()让其等待。所以用户每次监听io/mem/cpu的任一文件,都会引发此对接函数的调用,根据已有的trigger判断事件监听情况。总结,这里只做一次’询问‘而已,并不操作psi事件。
  2. psi poll work创建:psi_trigger_create();通过此函数创建和初始化trigger,并在内核创建work,通过kthread_init_delayed_work()函数初始化交由kthread管理,即为[psimon]守护进程,在内核态接受调度负责设置psi事件。
  3. psi poll work销毁:psi_trigger_destroy();销毁psi_fop_poll()时候创建的trigger,如果是最后一个trigger,则销毁psi_trigger_create()阶段创建的work。
  4. psi poll work入口:psi_poll_work();是内核守护进程[psimon]的入口调用函数。在psi poll work创建过程中,交给kthreadd管理。

疑问点:此psi poll work何时调度?

  1. psi的状态切换:psi_task_change();由enqueue_task()/dequeue_task()进程进入和退出引发调用,此函数会调用psi_schedule_poll_work()函数来让psi poll work加入queue队列然后执行,首先它会判断一个标志poll_scheduled是否为0,如果为0,那么就将poll_work进程通过kthread_queue_delayed_work()函数放入队列中延迟执行,并且设置poll_scheduled标志为1;如果为1,那么将不放入到队列中,不设置poll_scheduled。这么看来,psi poll work是有可能不能够得到运行机会的。

疑问点:poll_scheduled何时设置?

  1. poll_scheduled设置点:1)在函数最初group_init()初始化时候会设置poll_scheduled为0;2)在入口函数中会设置poll_scheduled为0,因为进入到入口函数说明此psi poll work已经在运行了;

 

四、定位问题

重新捋一遍执行过程,

  1. 首先内核创建psi poll work,并不执行,也未放在run的队列中。
  2. 用户态发起poll系统调用,内核判断poll_scheduled标志位是0还是1,如果0,则调度work。
  3. 触发成功poll事件,销毁trigger,销毁[psimon]守护进程。
  4. 第二次创建work,同上。
  5. 用户态发起系统调用,此时,poll_scheduled为1,无论[psi的状态切换]如何变化,内核都需要判断此标志位是否为0,否则不加入kthread queue。
  6. 用户态再次发起系统调用,同上,不调度。这样就一直处于死状态。

因此,寻找为什么poll_scheduled为1,又究竟何时变为了1,顺藤摸瓜撸完源码后,答案很清楚:在destroy销毁后poll_scheduled并未重新设置(reinitialize)为0。

解决方案在psi_trigger_destroy()函数的[psimon]销毁操作后加入atomic_set(&group->poll_scheduled, 0);即可。

 

五、后记

有些感想,

  1. 需要对kthreadd机制的了解。如果不熟悉则会容易跑偏,认为是不是因为kthreadd的驱动进程运行部分有问题。
  2. 需要对poll()机制的熟悉。除了用户态的poll()调用以外,还是要熟悉内核态如何构建一个poll监听机制。
  3. 需要做充分且必要的实验。每一步的操作都会带来不同的细微的差别,需要总结结果来大胆猜测。

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

### 头歌平台第2关中关于poll机制的实现与原理 在头歌平台的第2关中,`poll`机制的核心思想是通过休眠和唤醒的方式等待事件的发生。其主要目标是避免进程长时间处于空转状态,从而提高系统的效率[^2]。 #### 1. `poll`机制的基本概念 `poll`机制是一种基于事件驱动的多路复用技术,用于监控多个文件描述符的状态变化。它通过内核中的回调函数和事件队列来实现高效的事件监听[^1]。 #### 2. 实现流程 `poll`机制的实现可以分为以下几个关键步骤: - **用户态调用**:用户程序通过系统调用`poll`或`epoll`请求内核监听一组文件描述符。 - **内核态处理**: - 系统调用进入内核后,会调用`sys_poll`函数[^1]。 - `sys_poll`进一步调用`do_sys_poll`函数,该函数负责初始化等待队列,并设置超时时间。 - 调用`poll_initwait`函数注册回调函数`__pollwait`,当驱动程序执行`poll_wait`时,会调用此回调函数。 - **事件触发**:当某个文件描述符上的事件发生时(如可读、可写等),内核会唤醒等待队列中的进程。 - **返回结果**:内核将事件通知给用户程序,用户程序根据返回的结果进行相应的处理。 #### 3. 内核中的核心函数 以下是`poll`机制在Linux内核中的核心函数及其作用: - **`poll_initwait`**:初始化等待结构体,并注册回调函数`__pollwait`[^1]。 - **`__pollwait`**:将当前进程加入到等待队列中,以便在事件发生时被唤醒。 - **`poll_wait`**:驱动程序调用此函数,将当前进程挂起,直到事件发生。 #### 4. 示例代码 以下是一个简单的`poll`机制使用示例: ```c #include <poll.h> #include <stdio.h> #include <unistd.h> int main() { struct pollfd fds[1]; int ret; fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN; ret = poll(fds, 1, -1); if (ret == -1) { perror("poll"); return 1; } if (fds[0].revents & POLLIN) { printf("Data is available for reading\n"); } return 0; } ``` #### 5. 优缺点分析 - **优点**:`poll`机制能够同时监听多个文件描述符的状态变化,适用于需要处理多个I/O流的场景。 - **缺点**:在文件描述符数量较多时,`poll`的性能可能会下降,因为它需要遍历所有的文件描述符以检查状态。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值