metrics
监控/proc/下pid各项指标
cpu、内存、磁盘io、磁盘读写带宽、exe、cmdline
可以结合管道符进行排序 如:bash metrics.sh |sort -k 2 -r -q
INTERVAL=${1:-1}
if (( BASH_VERSINFO[0] < 4 )); then
echo "err: need bash4.0 or later" >&2
exit 1
fi
if [[ $EUID -ne 0 ]]; then
echo "err: suggest root exec " >&2
fi
CLK_TCK=$(getconf CLK_TCK)
human_readable() {
local bytes=$1
local unit="B"
if (( bytes >= 1024 )); then
bytes=$(( bytes / 1024 ))
unit="K"
if (( bytes >= 1024 )); then
bytes=$(( bytes / 1024 ))
unit="M"
if (( bytes >= 1024 )); then
bytes=$(( bytes / 1024 ))
unit="G"
fi
fi
fi
echo "$bytes$unit"
}
echo "Collecting first data snapshot (interval ${INTERVAL}s)..."
declare -A s1_cpu s1_read_bytes s1_write_bytes s1_read_iops s1_write_iops
for pid_dir in /proc/[0-9]*; do
pid="${pid_dir##*/}"
[[ -d "$pid_dir" ]] || continue
if [[ -r "${pid_dir}/stat" ]]; then
read -r -a stat_data < "${pid_dir}/stat"
s1_cpu[$pid]=$(( ${stat_data[13]} + ${stat_data[14]} ))
fi
if [[ -r "${pid_dir}/io" ]]; then
while read -r key value; do
case "$key" in
rchar:) s1_read_bytes[$pid]=$value ;;
wchar:) s1_write_bytes[$pid]=$value ;;
syscr:) s1_read_iops[$pid]=$value ;;
syscw:) s1_write_iops[$pid]=$value ;;
esac
done < "${pid_dir}/io"
fi
done
sleep "$INTERVAL"
printf "%-8s %-10s %-10s %-8s %-8s %-10s %-10s %-8s %s\n" \
"PID" "CPU(%)" "MEM(RSS)" "R_IOPS" "W_IOPS" "DISK_R/s" "DISK_W/s" "EXE" "COMMAND-LINE"
for pid_dir in /proc/[0-9]*; do
pid="${pid_dir##*/}"
[[ -v "s1_cpu[$pid]" ]] || continue
mem_rss_kb=0
if [[ -r "${pid_dir}/status" ]]; then
while read -r key value _; do
if [[ "$key" == "VmRSS:" ]]; then
mem_rss_kb=$value; break
fi
done < "${pid_dir}/status"
fi
mem_rss_hr=$(human_readable $(( mem_rss_kb * 1024 )))
cmdline="-"
if [[ -r "${pid_dir}/cmdline" ]]; then
read -r -d '' cmdline_raw < "${pid_dir}/cmdline"
if [[ -z "$cmdline_raw" ]]; then
cmdline="[$(<"${pid_dir}/comm")]"
else
cmdline="${cmdline_raw//$'\0'/ }"
fi
fi
exe="-"
exe=$(readlink -f "/proc/${pid}/exe" 2>/dev/null)
cpu_usage="0.00"
if [[ -r "${pid_dir}/stat" ]]; then
read -r -a stat_data2 < "${pid_dir}/stat"
cpu_ticks_diff=$(( (${stat_data2[13]} + ${stat_data2[14]}) - ${s1_cpu[$pid]:-0} ))
total_ticks=$(( CLK_TCK * INTERVAL ))
if (( total_ticks > 0 )); then
cpu_usage_scaled=$(( cpu_ticks_diff * 10000 / total_ticks ))
cpu_usage=$(printf "%d.%02d" $((cpu_usage_scaled / 100)) $((cpu_usage_scaled % 100)))
fi
fi
#-----------split-----------#
read_rate=0; write_rate=0; read_iops=0; write_iops=0
if [[ -r "${pid_dir}/io" ]]; then
s2_read_bytes=0; s2_write_bytes=0; s2_read_iops=0; s2_write_iops=0
while read -r key value; do
case "$key" in
rchar:) s2_read_bytes=$value ;;
wchar:) s2_write_bytes=$value ;;
syscr:) s2_read_iops=$value ;;
syscw:) s2_write_iops=$value ;;
esac
done < "${pid_dir}/io"
read_rate=$(( (s2_read_bytes - ${s1_read_bytes[$pid]:-0}) / INTERVAL ))
write_rate=$(( (s2_write_bytes - ${s1_write_bytes[$pid]:-0}) / INTERVAL ))
read_iops=$(( (s2_read_iops - ${s1_read_iops[$pid]:-0}) / INTERVAL ))
write_iops=$(( (s2_write_iops - ${s1_write_iops[$pid]:-0}) / INTERVAL ))
fi
read_rate_hr=$(human_readable $read_rate)
write_rate_hr=$(human_readable $write_rate)
printf "%-8s %-10s %-10s %-8s %-8s %-10s %-10s %-8s %s\n" \
"$pid" \
"$cpu_usage" \
"$mem_rss_hr" \
"$read_iops" \
"$write_iops" \
"$read_rate_hr" \
"$write_rate_hr" \
"$exe" \
"${cmdline}"
done