如何在Linux下高效测量bash协程及其子进程组的平均CPU使用率
解决forkrun协程CPU统计与动态数量调整问题
核心思路
要准确统计协程及其所有后代的CPU耗时,需递归遍历每个协程的所有子进程/后代,并累加每个进程自身的用户态+内核态CPU时间(而非依赖cutime/cstime,因为这两个字段仅统计已wait的子进程)。
1. 递归收集协程及其所有后代PID
通过/proc/<PID>/children文件获取直接子进程,递归遍历得到所有后代PID:
collect_descendants() { local pid="$1" echo "$pid" # 读取直接子进程,处理空值或无权限情况 local children [[ -r "/proc/$pid/children" ]] && children=$(< "/proc/$pid/children") for child in $children; do collect_descendants "$child" done }
2. 获取单个进程的CPU时间
从/proc/<PID>/stat提取第14位(utime,用户态CPU时间)和第15位(stime,内核态CPU时间),单位为jiffies:
get_process_cpu() { local pid="$1" # 读取stat文件并提取目标字段 read -r _ _ _ _ _ _ _ _ _ _ _ _ _ utime stime <<< "$(< "/proc/$pid/stat")" echo $((utime + stime)) }
3. 计算单个协程的总CPU耗时
结合上述两个函数,累加协程自身+所有后代的CPU时间:
get_coproc_total_cpu() { local coproc_pid="$1" local total=0 # 遍历所有相关PID,跳过已退出的进程 for pid in $(collect_descendants "$coproc_pid"); do if [[ -f "/proc/$pid/stat" ]]; then total=$((total + $(get_process_cpu "$pid"))) fi done echo "$total" }
4. 动态调整协程数量的实现
步骤:
- 记录基准数据:启动协程时,记录每个协程的PID、初始CPU时间和当前时间(纳秒级):
# 用关联数组存储协程状态 declare -A coproc_cpu_base coproc_time_base coproc_cpu_base[$coproc_pid]=$(get_coproc_total_cpu "$coproc_pid") coproc_time_base[$coproc_pid]=$(date +%s%N) - 定期轮询计算使用率:
calculate_coproc_usage() { local coproc_pid="$1" local current_cpu=$(get_coproc_total_cpu "$coproc_pid") local current_time=$(date +%s%N) local clk_tck=$(getconf CLK_TCK) # 获取系统时钟节拍数,兼容不同系统 # 计算时间差(秒)和CPU时间差(秒) local time_diff=$(( (current_time - coproc_time_base[$coproc_pid]) / 1000000000 )) local cpu_diff=$(( (current_cpu - coproc_cpu_base[$coproc_pid]) / clk_tck )) # 计算单协程的CPU使用率 local usage=$(( time_diff == 0 ? 0 : (cpu_diff * 100) / time_diff )) # 更新基准数据 coproc_cpu_base[$coproc_pid]=$current_cpu coproc_time_base[$coproc_pid]=$current_time echo "$usage" } - 根据使用率调整协程数:
- 当所有协程的平均使用率持续低于阈值(如80%),新增协程
- 当使用率持续高于阈值(如95%),优雅终止闲置协程(需配合forkrun的协程退出逻辑)
关键注意事项
- 避免竞态:遍历
/proc文件时必须判断文件是否存在,防止进程已退出导致的读取错误 - 兼容性:用
getconf CLK_TCK获取系统的jiffies转换系数,避免硬编码100带来的兼容性问题 - 性能控制:所有操作基于
procfs和bash原生功能,开销极小,不会影响forkrun的并行性能
内容的提问来源于stack exchange,提问作者jkool702
相关产品推荐
相关产品推荐

