Linux psi_task_change任务状态切换PSI计算

发布时间:2026/6/22 12:04:34

Linux psi_task_change任务状态切换PSI计算 Linux psi_task_change任务状态切换PSI计算psi_task_change是PSI(Pressure Stall Information)子系统的核心函数负责在任务状态发生切换时更新per-CPU的stall追踪状态。任务状态的变化直接决定了cgroup当前是否处于IO、内存或CPU资源压力的stall状态以及stall的严重程度(some vs full)。函数核心逻辑psi_task_change接收当前任务、新旧任务状态flags以及是否睡眠等参数根据这些信息判断stall状态是否发生变化并更新per-CPU的统计累积时间。cvoid psi_task_change(struct task_struct *task, int clear, int set){struct psi_group *group;int cpu task_cpu(task);struct psi_group_cpu *groupc;u64 now;int state_mask;if (!task-pid)return;group task_psi_group(task);if (!group)return;now cpu_clock(cpu);groupc per_cpu_ptr(group-pcpu, cpu);raw_spin_lock(groupc-lock);/** 计算新状态掩码先清除旧flags再设置新flags* 排除TASK_NONIDLE等非PSI状态位*/state_mask (groupc-state_mask ~clear) | set;state_mask PSI_TASK_STATE_MASK;if (state_mask ! groupc-state_mask) {u64 delta;/** 计算从上次状态改变到现在的stall持续时间* 累加到对应状态的times数组中*/delta now - groupc-state_start;if (delta 0) {int s;for (s 0; s NR_PSI_STATES; s) {if (groupc-state_mask (1 s))groupc-times[s][groupc-state_mask] delta;}}groupc-state_mask state_mask;groupc-state_start now;/** 如果新状态包含非空闲标志需要设置* nonidle_start时间戳用于非idle时间跟踪*/if (state_mask TASK_NONIDLE) {if (!groupc-nonidle_start)groupc-nonidle_start now;} else {if (groupc-nonidle_start) {delta now - groupc-nonidle_start;groupc-nonidle_time delta;groupc-nonidle_start 0;}}}raw_spin_unlock(groupc-lock);/** 如果状态变化涉及可运行状态(running/runnable)的切换* 需要通知调度器更新psi_sched统计*/if (task-psi_flags TSK_RUNNING) {if (!(set TSK_RUNNING)) {psi_sched_account(task, true);}}}PSI状态的分类体系PSI定义了三种资源类型(IO、Memory、CPU)和两种stall严重程度(Some、Full)。Some表示至少有一个任务处于stall状态但非全部Full表示所有非idle任务都处于stall状态。cenum psi_states {PSI_IO_SOME,PSI_IO_FULL,PSI_MEM_SOME,PSI_MEM_FULL,PSI_CPU_SOME,PSI_CPU_FULL,NR_PSI_STATES,};psi_task_switch调度器入口调度器在进程切换时调用psi_task_switch该函数包装了psi_task_change并提供额外的上下文信息是调度器与PSI子系统的主要接口。cvoid psi_task_switch(struct task_struct *prev, struct task_struct *next,bool sleep){struct psi_group *group, *prev_group;if (!static_branch_likely(psi_disabled))return;if (prev-pid) {prev_group task_psi_group(prev);if (prev-state TASK_RUNNING) {psi_task_change(prev, TSK_RUNNING, 0);} else if (sleep) {/** 任务进入睡眠状态设置TSK_SLEEP标志* 此时该任务不再贡献活跃度*/psi_task_change(prev, TSK_RUNNING, TSK_SLEEP);if (prev-in_iowait)psi_task_change(prev, 0, TSK_IOWAIT);}}if (next-pid) {group task_psi_group(next);if (next-state TASK_RUNNING) {psi_task_change(next, 0, TSK_RUNNING);}}/** 如果任务迁移到不同cgroup需要同步* per-CPU的psi_group_cpu统计*/if (prev_group ! group prev-pid next-pid)psi_group_change_sync(prev, prev_group, next, group, cpu);}memstall与iowait的处理当任务因缺页等待IO时内核标记PF_MEMSTALL标志。psi_memstall_enter和psi_memstall_leave通过psi_task_change切换TSK_MEMSTALL状态使PSI能够追踪内存stall导致的任务等待。cvoid psi_memstall_enter(unsigned long *flags){struct task_struct *task current;if (!static_branch_likely(psi_disabled))return;*flags task-flags PF_MEMSTALL;task-flags | PF_MEMSTALL;if (!(*flags PF_MEMSTALL))psi_task_change(task, 0, TSK_MEMSTALL);}void psi_memstall_leave(unsigned long *flags){struct task_struct *task current;if (!static_branch_likely(psi_disabled))return;if (*flags PF_MEMSTALL)return;task-flags ~PF_MEMSTALL;psi_task_change(task, TSK_MEMSTALL, 0);}通过psi_task_change的精细状态追踪PSI能够准确区分不同资源类型的stall并为系统管理员提供精确的拥塞度量这是cgroup v2资源隔离能力的关键组成部分。

相关新闻