You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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. 动态调整协程数量的实现

步骤:

  1. 记录基准数据:启动协程时,记录每个协程的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)
    
  2. 定期轮询计算使用率:
    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"
    }
    
  3. 根据使用率调整协程数:
    • 当所有协程的平均使用率持续低于阈值(如80%),新增协程
    • 当使用率持续高于阈值(如95%),优雅终止闲置协程(需配合forkrun的协程退出逻辑)

关键注意事项

  • 避免竞态:遍历/proc文件时必须判断文件是否存在,防止进程已退出导致的读取错误
  • 兼容性:用getconf CLK_TCK获取系统的jiffies转换系数,避免硬编码100带来的兼容性问题
  • 性能控制:所有操作基于procfs和bash原生功能,开销极小,不会影响forkrun的并行性能

内容的提问来源于stack exchange,提问作者jkool702

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:16:11