#!/bin/sh # proc_monitor_sched.sh - 纳秒级精确CPU监控 # 用法: ./proc_monitor_sched.sh <进程名或PID> [采样间隔秒] [采样次数] # # 数据源优先级: # 1. /proc/PID/task/*/schedstat (纯整数纳秒,所有线程求和) # 2. /proc/PID/task/*/sched (浮点秒,所有线程求和) # 3. /proc/PID/stat (jiffies,100Hz,已含所有线程) TARGET=$1 INTERVAL=${2:-2} COUNT=${3:-0} if [ -z "$TARGET" ]; then echo "Usage: $0 <进程名或PID> [间隔秒] [次数(0=无限)]" echo "Example:" echo " $0 Copilot.bin" echo " $0 1234 1 60" exit 1 fi # 查找PID if echo "$TARGET" | grep -qE '^[0-9]+$'; then PID=$TARGET else PID=$(pidof "$TARGET" 2>/dev/null) if [ -z "$PID" ]; then PID=$(pgrep -x "$TARGET" 2>/dev/null | head -1) fi if [ -z "$PID" ]; then echo "ERROR: 进程 '$TARGET' 未找到" exit 1 fi fi if [ ! -d "/proc/$PID" ]; then echo "ERROR: PID $PID 不存在" exit 1 fi PROC_NAME=$(cat /proc/$PID/comm 2>/dev/null || echo "unknown") CPU_CORES=$(nproc 2>/dev/null || grep -c '^processor' /proc/cpuinfo 2>/dev/null || echo 1) # === 自动选择数据源 === # 注意: schedstat 和 sched 都是 per-thread 的,必须遍历 task/ 下所有线程求和 # /proc/PID/stat 的 utime+stime 已经包含所有线程,无需遍历 DATASRC="none" if [ -d "/proc/$PID/task" ] && [ -n "$(cat /proc/$PID/task/*/schedstat 2>/dev/null | head -1)" ]; then DATASRC="schedstat" elif [ -d "/proc/$PID/task" ] && [ -n "$(grep '^se.sum_exec_runtime' /proc/$PID/task/*/sched 2>/dev/null | head -1)" ]; then DATASRC="sched" elif [ -r "/proc/$PID/stat" ]; then DATASRC="stat" else echo "ERROR: 无可用数据源" exit 1 fi case "$DATASRC" in schedstat) DATASRC_DESC="schedstat (纳秒, 所有线程求和)" ;; sched) DATASRC_DESC="sched (浮点秒, 所有线程求和)" ;; stat) DATASRC_DESC="stat (jiffies 100Hz, 已含所有线程)" ;; esac echo "=========================================" echo " 监控进程: $PROC_NAME (PID: $PID)" echo " CPU核数: $CPU_CORES" echo " 数据源: $DATASRC_DESC" echo " 采样间隔: ${INTERVAL}s" echo "=========================================" echo "" printf "%-20s %8s %10s %8s %8s %8s %8s\n" "时间" "CPU%" "CPU(total)" "RSS(MB)" "VM(MB)" "线程数" "状态" printf "%-20s %8s %10s %8s %8s %8s %8s\n" "----" "-----" "----------" "-------" "------" "------" "----" # === 读取函数 === # schedstat: 遍历所有线程,第1字段求和(纳秒) read_schedstat() { awk '{s+=$1} END {printf "%.0f", s}' /proc/$1/task/*/schedstat 2>/dev/null } # sched: 遍历所有线程,se.sum_exec_runtime求和(秒,浮点) read_sched() { awk '/^se.sum_exec_runtime/{s+=$3} END {printf "%.6f", s}' /proc/$1/task/*/sched 2>/dev/null } # stat: utime(14) + stime(15), 已含所有线程, 单位=USER_HZ read_stat() { awk '{print $14+$15}' /proc/$1/stat 2>/dev/null } # 墙上时钟 read_wall_ns() { awk '{printf "%.0f", $1 * 1000000000}' /proc/uptime } read_wall_hz() { local clk_tck=$(getconf CLK_TCK 2>/dev/null || echo 100) awk -v tck="$clk_tck" '{printf "%.0f", $1 * tck}' /proc/uptime } i=0 # === 初始采样 === case "$DATASRC" in schedstat) t1=$(read_schedstat $PID) w1=$(read_wall_ns) ;; sched) t1=$(read_sched $PID) w1=$(awk '{print $1}' /proc/uptime) ;; stat) CLK_TCK=$(getconf CLK_TCK 2>/dev/null || echo 100) t1=$(read_stat $PID) w1=$(read_wall_hz) ;; esac while true; do if [ ! -d "/proc/$PID" ]; then echo "" echo "[INFO] 进程 PID $PID 已退出" break fi sleep "$INTERVAL" if [ ! -d "/proc/$PID" ]; then echo "" echo "[INFO] 进程 PID $PID 已退出" break fi # === 第二次采样 === case "$DATASRC" in schedstat) t2=$(read_schedstat $PID) w2=$(read_wall_ns) # schedstat字段1已是单核等效时间(与stat的utime+stime一致) result=$(awk -v s1="$t1" -v s2="$t2" \ -v w1="$w1" -v w2="$w2" \ -v cores="$CPU_CORES" 'BEGIN { ds = s2 - s1 dw = w2 - w1 if (dw > 0) { cpu_single = ds / dw * 100 cpu_total = ds / dw / cores * 100 printf "%.1f %.1f", cpu_single, cpu_total } else { printf "0.0 0.0" } }') ;; sched) t2=$(read_sched $PID) w2=$(awk '{print $1}' /proc/uptime) # sched的sum_exec_runtime也是单核等效时间 result=$(awk -v s1="$t1" -v s2="$t2" \ -v w1="$w1" -v w2="$w2" \ -v cores="$CPU_CORES" 'BEGIN { ds = s2 - s1 dw = w2 - w1 if (dw > 0) { cpu_single = ds / dw * 100 cpu_total = ds / dw / cores * 100 printf "%.1f %.1f", cpu_single, cpu_total } else { printf "0.0 0.0" } }') ;; stat) t2=$(read_stat $PID) w2=$(read_wall_hz) # stat的utime+stime也是单核等效时间 result=$(awk -v s1="$t1" -v s2="$t2" \ -v w1="$w1" -v w2="$w2" \ -v cores="$CPU_CORES" 'BEGIN { ds = s2 - s1 dw = w2 - w1 if (dw > 0) { cpu_single = ds / dw * 100 cpu_total = ds / dw / cores * 100 printf "%.1f %.1f", cpu_single, cpu_total } else { printf "0.0 0.0" } }') ;; esac cpu_single=$(echo "$result" | awk '{print $1}') cpu_total=$(echo "$result" | awk '{print $2}') # 内存 rss=$(awk '/VmRSS/{print $2}' /proc/$PID/status 2>/dev/null) vmsize=$(awk '/VmSize/{print $2}' /proc/$PID/status 2>/dev/null) rss_mb=$((rss / 1024)) vm_mb=$((vmsize / 1024)) # 线程数 threads=$(ls /proc/$PID/task/ 2>/dev/null | wc -l) # 状态 state=$(awk '/State:/{print $2}' /proc/$PID/status 2>/dev/null) # 时间 cur_time=$(date +"%H:%M:%S") printf "%-20s %7s%% %8s%% %6dMB %6dMB %6d %8s\n" \ "$cur_time" "$cpu_single" "$cpu_total" "$rss_mb" "$vm_mb" "$threads" "$state" # 滚动更新基准 t1=$t2 w1=$w2 i=$((i+1)) if [ "$COUNT" -gt 0 ] && [ "$i" -ge "$COUNT" ]; then break fi done记录一个比top更加精准的cpu占用统计脚本
张小明
前端开发工程师
告别网盘限速!9大平台直链下载助手让文件下载速度起飞
告别网盘限速!9大平台直链下载助手让文件下载速度起飞 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…
微观的隐形调控网络!小分子标志物为何是当下科研热点?
生命机体的运转,从来不是大分子蛋白、基因的单一调控,而是无数小分子活性物质协同联动的精密结果。相较于大家熟知的蛋白、细胞、基因靶点,分子量小于1000Da的小分子物质,体积微小、含量极低、功能隐蔽,却贯穿人体神经…
泛彩不是反光,别用错了方法
有一种吊牌缺陷看起来像反光,但本质完全不同——泛彩。泛彩不是白色反光,而是彩色条纹或彩色光晕。覆膜吊牌在特定角度光照下,表面出现彩虹色斑,文字和图案被彩色条纹覆盖。泛彩是怎么产生的泛彩是薄膜干涉的结果。覆膜吊牌表面的…
基于AtomCode开源AI编码工具的新能源汽车ACC自适应巡航系统维护改革创新研究
摘要 新能源汽车自适应巡航(ACC)系统作为智能驾驶基础核心模块,长期存在故障定位效率低、线下维保标准化差、软件迭代适配成本高、售后技术人才门槛高等行业痛点。本文依托开源AI编码助手AtomCode完成全流程技术落地与方案验证,从…
掌握Agentic RL:从算法到系统,小白也能学会大模型智能体训练(收藏版)
本文深入探讨了Agentic RL在大模型研究中的核心地位,详细解析了如何将LLM从静态问答模型转变为能与环境交互的智能体。文章系统梳理了Agentic RL的关键工程经验,包括ToRL的工具集成推理、AgentGym-RL的开放式环境接口和课程式长程训练、Agent-R1的step-l…
企业级WebGL 3D可视化架构解析与工业应用解决方案
企业级WebGL 3D可视化架构解析与工业应用解决方案 【免费下载链接】Online3DViewer A solution to visualize and explore 3D models in your browser. 项目地址: https://gitcode.com/gh_mirrors/on/Online3DViewer 在数字化设计、智能制造和建筑信息模型(B…