|
|
|
#!/usr/bin/env bash
|
|
|
|
###################################################################
|
|
|
|
#Script Name : get_proc_mem.sh
|
|
|
|
#Description : Get Process Memory information.
|
|
|
|
#Create Date : 2020-10-15
|
|
|
|
#Author : lework
|
|
|
|
#Email : lework@yeah.net
|
|
|
|
###################################################################
|
|
|
|
|
|
|
|
|
|
|
|
[[ -n $DEBUG ]] && set -x || true
|
|
|
|
set -o errtrace # Make sure any error trap is inherited
|
|
|
|
set -o nounset # Disallow expansion of unset variables
|
|
|
|
set -o pipefail # Use last non-zero exit code in a pipeline
|
|
|
|
|
|
|
|
|
|
|
|
######################################################################################################
|
|
|
|
# environment configuration
|
|
|
|
######################################################################################################
|
|
|
|
|
|
|
|
PID="${PID:-1}"
|
|
|
|
RETRIES="${RETRIES:-0}"
|
|
|
|
WAIT="${WAIT:-1}"
|
|
|
|
|
|
|
|
COLOR_RED="${COLOR_RED:-\e[1;31m}"
|
|
|
|
COLOR_GREEN="${COLOR_GREEN:-\e[1;32m}"
|
|
|
|
COLOR_YELLOW="${COLOR_RED:-\e[1;33m}"
|
|
|
|
COLOR_BLUE="${COLOR_BLUE:-\e[1;34m}"
|
|
|
|
COLOR_PURPLE="${COLOR_PURPLE:-\e[1;35m}"
|
|
|
|
COLOR_CYAN="${COLOR_CYAN:-\e[1;36m}"
|
|
|
|
COLOR_GRAY="${COLOR_GRAY:-\e[1;90m}"
|
|
|
|
COLOR_OFF="${COLOR_OFF:-\e[0m}"
|
|
|
|
NOCOLOR="${NOCOLOR:-false}"
|
|
|
|
|
|
|
|
time_data=""
|
|
|
|
mem_total_data=""
|
|
|
|
mem_free_data=""
|
|
|
|
mem_available_data=""
|
|
|
|
mem_rss_data=""
|
|
|
|
mem_pss_data=""
|
|
|
|
mem_uss_data=""
|
|
|
|
cpu_used_data=""
|
|
|
|
|
|
|
|
trap trap::info 1 2 3 15 EXIT
|
|
|
|
|
|
|
|
######################################################################################################
|
|
|
|
# function
|
|
|
|
######################################################################################################
|
|
|
|
|
|
|
|
function trap::info() {
|
|
|
|
cat << EOF > pid_${PID}_line.json
|
|
|
|
option = {
|
|
|
|
title: {
|
|
|
|
text: '内存监控',
|
|
|
|
subtext: 'PID: ${PID}'
|
|
|
|
},
|
|
|
|
tooltip: {
|
|
|
|
trigger: 'axis'
|
|
|
|
},
|
|
|
|
legend: {
|
|
|
|
data: ['mem_total', 'mem_free', 'mem_available', 'pid_mem_rss', 'pid_mem_pss', 'pid_mem_uss', 'pid_cpu_used']
|
|
|
|
},
|
|
|
|
grid: {
|
|
|
|
left: '3%',
|
|
|
|
right: '4%',
|
|
|
|
bottom: '3%',
|
|
|
|
containLabel: true
|
|
|
|
},
|
|
|
|
toolbox: {
|
|
|
|
feature: {
|
|
|
|
saveAsImage: {}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
xAxis: {
|
|
|
|
type: 'category',
|
|
|
|
boundaryGap: false,
|
|
|
|
data: [${time_data/,}]
|
|
|
|
},
|
|
|
|
yAxis: [
|
|
|
|
{
|
|
|
|
type: "value",
|
|
|
|
name: "内存 / MB",
|
|
|
|
nameLocation: 'center',
|
|
|
|
nameGap: 45
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: "value",
|
|
|
|
name: "CPU使用率 / %",
|
|
|
|
nameLocation: 'center',
|
|
|
|
nameGap: 45
|
|
|
|
}
|
|
|
|
],
|
|
|
|
series: [
|
|
|
|
{
|
|
|
|
name: 'mem_total',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
data: [${mem_total_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最大值',
|
|
|
|
type: 'max'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'mem_free',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
data: [${mem_free_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最小值',
|
|
|
|
type: 'min'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'mem_available',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
data: [${mem_available_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最小值',
|
|
|
|
type: 'min'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'pid_mem_rss',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
data: [${mem_rss_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最大值',
|
|
|
|
type: 'max'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'pid_mem_pss',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
data: [${mem_pss_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最大值',
|
|
|
|
type: 'max'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'pid_mem_uss',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
data: [${mem_uss_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最大值',
|
|
|
|
type: 'max'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'pid_cpu_used',
|
|
|
|
type: 'line',
|
|
|
|
smooth: true,
|
|
|
|
yAxisIndex: 1,
|
|
|
|
data: [${cpu_used_data/,}],
|
|
|
|
markPoint: {
|
|
|
|
data: [{
|
|
|
|
name: '最大值',
|
|
|
|
type: 'max'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
EOF
|
|
|
|
echo -e "
|
|
|
|
\n${COLOR_GREEN}
|
|
|
|
Config File: pid_${PID}_line.json
|
|
|
|
GO TO URL: https://echarts.apache.org/next/examples/en/editor.html
|
|
|
|
${COLOR_OFF}
|
|
|
|
"
|
|
|
|
trap '' EXIT
|
|
|
|
exit
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
######################################################################################################
|
|
|
|
# function
|
|
|
|
######################################################################################################
|
|
|
|
|
|
|
|
function get::meminfo() {
|
|
|
|
|
|
|
|
[ ! -f "/proc/${PID}/smaps" ] && { echo -e "${COLOR_RED}[Error]${COLOR_OFF} not found $PID smaps file!"; exit 1; }
|
|
|
|
|
|
|
|
pid_smaps=$(cat /proc/${PID}/smaps)
|
|
|
|
[ "$pid_smaps" == "" ] && { echo -e "${COLOR_RED}[Error]${COLOR_OFF} /proc/${PID}/smaps is empty!"; exit 1; }
|
|
|
|
|
|
|
|
cpu_used=$(ps -opcpu= -p "${PID}")
|
|
|
|
mem_info=$(cat /proc/meminfo)
|
|
|
|
|
|
|
|
mem_total=$(printf "%s" "${mem_info}"| awk '/^MemTotal:/ {print $2}')
|
|
|
|
mem_free=$(printf "%s" "${mem_info}"| awk '/^MemFree:/ {print $2}')
|
|
|
|
mem_available=$(printf "%s" "${mem_info}"| awk '/^MemAvailable:/ {print $2}')
|
|
|
|
size=$(printf "%s" "${pid_smaps}" | awk '/^Size/{sum += $2}END{print sum}')
|
|
|
|
rss=$(printf "%s" "${pid_smaps}" | awk '/^Rss/{sum += $2}END{print sum}')
|
|
|
|
pss=$(printf "%s" "${pid_smaps}" | awk '/^Pss/{sum += $2}END{print sum}')
|
|
|
|
|
|
|
|
shared_clean=$(printf "%s" "${pid_smaps}" | awk '/^Shared_Clean/{sum += $2}END{print sum}')
|
|
|
|
shared_dirty=$(printf "%s" "${pid_smaps}" | awk '/^Shared_Dirty/{sum += $2}END{print sum}')
|
|
|
|
private_clean=$(printf "%s" "${pid_smaps}" | awk '/^Private_Clean/{sum += $2}END{print sum}')
|
|
|
|
private_dirty=$(printf "%s" "${pid_smaps}" | awk '/^Private_Dirty/{sum += $2}END{print sum}')
|
|
|
|
swap=$(printf "%s" "${pid_smaps}" | awk '/^Swap/{sum += $2}END{print sum}')
|
|
|
|
swap_pss=$(printf "%s" "${pid_smaps}" | awk '/^SwapPss/{sum += $2}END{print sum}')
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function get::pidinfo() {
|
|
|
|
echo -e "${COLOR_PURPLE}
|
|
|
|
Pid: ${PID}
|
|
|
|
Cmd: $(tr -d '\0' < /proc/${PID}/cmdline | cut -c1-80)
|
|
|
|
User: $(id -nu < /proc/${PID}/loginuid )
|
|
|
|
Threads: $(awk '/Threads:/ {print $2}' /proc/${PID}/status)
|
|
|
|
File: /proc/${PID}/smaps
|
|
|
|
${COLOR_OFF}"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function get::meminfo_loop() {
|
|
|
|
local count=0
|
|
|
|
get::pidinfo
|
|
|
|
while [ $count -lt $RETRIES ] ; do
|
|
|
|
get::meminfo
|
|
|
|
d=$(date +'%Y-%m-%d %T')
|
|
|
|
mem_total=$((mem_total/1024))
|
|
|
|
mem_free=$((mem_free/1024))
|
|
|
|
mem_available=$((mem_available/1024))
|
|
|
|
mem_rss=$((${rss}/1024))
|
|
|
|
mem_pss=$((${pss}/1024))
|
|
|
|
mem_uss=$(( (${private_clean} + ${private_dirty}) /1024 ))
|
|
|
|
echo -e "Date: ${d} ${COLOR_PURPLE}MemTotal: ${mem_total}MB${COLOR_OFF} ${COLOR_GREEN}MemFree: ${mem_free}MB${COLOR_OFF} ${COLOR_BLUE}MemAvailable: ${mem_available}MB${COLOR_OFF} ${COLOR_YELLOW}RSS: ${mem_rss}MB${COLOR_OFF} ${COLOR_CYAN}PSS: ${mem_pss}MB${COLOR_OFF} ${COLOR_RED}USS: ${mem_uss}MB${COLOR_OFF} CPU: ${cpu_used}%"
|
|
|
|
time_data="${time_data},'${d}'"
|
|
|
|
mem_total_data="${mem_total_data},'${mem_total}'"
|
|
|
|
mem_free_data="${mem_free_data},'${mem_free}'"
|
|
|
|
mem_available_data="${mem_available_data},'${mem_available}'"
|
|
|
|
mem_rss_data="${mem_rss_data},'${mem_rss}'"
|
|
|
|
mem_uss_data="${mem_uss_data},'${mem_uss}'"
|
|
|
|
mem_pss_data="${mem_pss_data},'${mem_pss}'"
|
|
|
|
cpu_used_data="${cpu_used_data},'${cpu_used}'"
|
|
|
|
sleep $WAIT
|
|
|
|
count=$(($count + 1))
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function get::meminfo_once() {
|
|
|
|
|
|
|
|
get::meminfo
|
|
|
|
|
|
|
|
echo -e "${COLOR_GRAY}
|
|
|
|
# OS meminfo
|
|
|
|
MemTotal:内存总数
|
|
|
|
MemFree:空闲内存数
|
|
|
|
MemAvailable:可用内存数,包括cache/buffer、slab
|
|
|
|
|
|
|
|
# Process smaps
|
|
|
|
Size:表示该映射区域在虚拟内存空间中的大小。
|
|
|
|
Rss: 表示该映射区域当前在物理内存中占用了多少空间
|
|
|
|
Rss=Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty
|
|
|
|
Pss: 该虚拟内存区域平摊计算后使用的物理内存大小(有些内存会和其他进程共享,例如mmap进来的)
|
|
|
|
实际上包含下面private_clean+private_dirty,和按比例均分的shared_clean、shared_dirty。
|
|
|
|
Uss: Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
|
|
|
|
USS=Private_Clean+Private_Dirty
|
|
|
|
Shared_Clean: 和其他进程共享的未被改写的page的大小
|
|
|
|
Shared_Dirty: 和其他进程共享的被改写的page的大小
|
|
|
|
Private_Clean: 未被改写的私有页面的大小。
|
|
|
|
Private_Dirty: 已被改写的私有页面的大小。
|
|
|
|
Swap: 存在于交换分区的数据大小(如果物理内存有限,可能存在一部分在主存一部分在交换分区)
|
|
|
|
SwapPss: 计算逻辑就跟pss一样,只不过针对的是交换分区的内存。${COLOR_OFF}
|
|
|
|
"
|
|
|
|
get::pidinfo
|
|
|
|
|
|
|
|
echo -e "${COLOR_GREEN}# Os meminfo
|
|
|
|
MemTotal: ${mem_total} KB
|
|
|
|
MemFree: ${mem_free} KB
|
|
|
|
MemAvailable: ${mem_available} KB ${COLOR_OFF}
|
|
|
|
|
|
|
|
${COLOR_CYAN}# Process smaps
|
|
|
|
Size: ${size} KB
|
|
|
|
RSS: ${rss} kB
|
|
|
|
PSS: ${pss} kB
|
|
|
|
Shared_Clean: ${shared_clean} kB
|
|
|
|
Shared_Dirty: ${shared_dirty} kB
|
|
|
|
Private_Clean: ${private_clean} kB
|
|
|
|
Private_Dirty: ${private_dirty} kB
|
|
|
|
Swap: ${swap} kB
|
|
|
|
SwapPss: ${swap_pss} kB
|
|
|
|
|
|
|
|
USS: ${private_clean} + ${private_dirty} = $(( ${private_clean} + ${private_dirty} )) kB
|
|
|
|
${COLOR_OFF}
|
|
|
|
"
|
|
|
|
}
|
|
|
|
|
|
|
|
function help::usage {
|
|
|
|
cat << EOF
|
|
|
|
|
|
|
|
Get Process Memory information.
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
$(basename $0) [options]
|
|
|
|
|
|
|
|
Options:
|
|
|
|
-p,--pid Process id
|
|
|
|
-r,--retries Retries number
|
|
|
|
-w,--wait Retries wit time
|
|
|
|
-h,--help View help
|
|
|
|
--nocolor Do not output color
|
|
|
|
|
|
|
|
EOF
|
|
|
|
exit
|
|
|
|
}
|
|
|
|
######################################################################################################
|
|
|
|
# main
|
|
|
|
######################################################################################################
|
|
|
|
|
|
|
|
#[ "$#" == "0" ] && help::usage
|
|
|
|
|
|
|
|
while [ "${1:-}" != "" ]; do
|
|
|
|
case $1 in
|
|
|
|
-p | --pid ) shift
|
|
|
|
PID=${1:-$PID}
|
|
|
|
;;
|
|
|
|
-r | --retries ) shift
|
|
|
|
RETRIES=${1:-$RETRIES}
|
|
|
|
;;
|
|
|
|
-w | --wait ) shift
|
|
|
|
WAIT=${1:-$WAIT}
|
|
|
|
;;
|
|
|
|
-h | --help ) help::usage
|
|
|
|
;;
|
|
|
|
--nocolor ) NOCOLOR=true
|
|
|
|
;;
|
|
|
|
* ) help::usage
|
|
|
|
exit 1
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ "${NOCOLOR}" == "true" ]; then
|
|
|
|
COLOR_RED=""
|
|
|
|
COLOR_GREEN=""
|
|
|
|
COLOR_YELLOW=""
|
|
|
|
COLOR_BLUE=""
|
|
|
|
COLOR_PURPLE=""
|
|
|
|
COLOR_CYAN=""
|
|
|
|
COLOR_GRAY=""
|
|
|
|
COLOR_OFF=""
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [[ ${RETRIES} -gt 0 ]]; then
|
|
|
|
get::meminfo_loop
|
|
|
|
else
|
|
|
|
get::meminfo_once
|
|
|
|
fi
|