al0ne / LinuxCheck

Linux应急处置/信息搜集/漏洞检测工具,支持基础配置/网络流量/任务计划/环境变量/用户信息/Services/bash/恶意文件/内核Rootkit/SSH/Webshell/挖矿文件/挖矿进程/供应链/服务器风险等13类70+项检查
MIT License
1.7k stars 380 forks source link

CPU 利用率计算逻辑问题 #21

Open starnightcyber opened 1 month ago

starnightcyber commented 1 month ago

https://github.com/al0ne/LinuxCheck/blob/bebca8ca774963526e2e39d59bce95373e7aa2c8/LinuxCheck.sh#L135-L140

计算逻辑问题: /proc/stat 文件中,CPU 时间是以计时单位(jiffies)提供的,各列分别代表不同状态的累计时间。不能简单地加和然后除来计算 CPU 使用率。导致这种计算值偏差太大。

下面的代码是 GPT 写的,供参考 :)

cpu_use() {
  echo "CPU Core | Usage % | Idle %"
  echo "---------|---------|-------"
  # 读取 CPU 数据前的延迟
  sleep_duration=0.1
  # 第一次读取 /proc/stat 并获取初始值
  read prev_idle prev_total < <(awk '/^cpu /{print $5, $2+$3+$4+$5+$6+$7+$8+$9+$10+$11}' /proc/stat)
  sleep $sleep_duration
  # 第二次读取 /proc/stat 并获取新值
  read idle total < <(awk '/^cpu /{print $5, $2+$3+$4+$5+$6+$7+$8+$9+$10+$11}' /proc/stat)
  # 计算差异和 CPU 使用率
  idle_diff=$((idle - prev_idle))
  total_diff=$((total - prev_total))
  usage=$(awk -v total_diff="$total_diff" -v idle_diff="$idle_diff" 'BEGIN {printf "%.2f", (100 * (total_diff - idle_diff) / total_diff)}')
  idle_rate=$(awk -v idle_diff="$idle_diff" -v total_diff="$total_diff" 'BEGIN {printf "%.2f", (100 * idle_diff / total_diff)}')
  echo "Overall  | $usage%    | $idle_rate%"
  # 对每个 CPU 核心进行相同的操作
  cpu_count=$(grep -c '^processor' /proc/cpuinfo)
  for ((i=0; i<cpu_count; i++)); do
      read prev_idle prev_total < <(awk -v cpu_id="$i" '/^cpu[0-9]+/{if (NR == cpu_id+2) print $5, $2+$3+$4+$5+$6+$7+$8+$9+$10+$11}' /proc/stat)
      sleep $sleep_duration
      read idle total < <(awk -v cpu_id="$i" '/^cpu[0-9]+/{if (NR == cpu_id+2) print $5, $2+$3+$4+$5+$6+$7+$8+$9+$10+$11}' /proc/stat)
      idle_diff=$((idle - prev_idle))
      total_diff=$((total - prev_total))
      usage=$(awk -v total_diff="$total_diff" -v idle_diff="$idle_diff" 'BEGIN {printf "%.2f", (100 * (total_diff - idle_diff) / total_diff)}')
      idle_rate=$(awk -v idle_diff="$idle_diff" -v total_diff="$total_diff" 'BEGIN {printf "%.2f", (100 * idle_diff / total_diff)}')
      echo "CPU$i     | $usage%    | $idle_rate%"
  done
}
starnightcyber commented 1 month ago

print_msg 大大简化了代码,采用 markdown 进行输出简直就是格式的救星