perf: optimize show_advanced_stats() — replace subshell loops with awk

- Container stats: single awk pass replaces ~10 echo|sed/cut/awk pipes per container
- Container logs: single awk per log file replaces ~8 subshell pipes per container
- Tracker data: awk pre-processing replaces bash while-read loops (slow on large files)
- Bar charts: printf+sed replaces character-by-character loops
- Network info: single ip route call instead of two
- Byte accumulation: bash arithmetic replaces awk subshells
This commit is contained in:
SamNet-dev
2026-02-10 23:49:15 -06:00
parent b06b6b70ac
commit 73b51834d1

View File

@@ -3190,10 +3190,10 @@ show_advanced_stats() {
local cycle_elapsed=$(( (now - cycle_start) % 15 )) local cycle_elapsed=$(( (now - cycle_start) % 15 ))
local time_until_next=$((15 - cycle_elapsed)) local time_until_next=$((15 - cycle_elapsed))
# Build progress bar # Build progress bar (no loop)
local bar="" local _filled=$(printf '%*s' "$cycle_elapsed" '' | sed 's/ /●/g')
for ((i=0; i<cycle_elapsed; i++)); do bar+="●"; done local _empty=$(printf '%*s' "$((15 - cycle_elapsed))" '' | sed 's/ /○/g')
for ((i=cycle_elapsed; i<15; i++)); do bar+="○"; done local bar="${_filled}${_empty}"
# Refresh data every 15 seconds or first run # Refresh data every 15 seconds or first run
if [ $((now - last_refresh)) -ge 15 ] || [ "$last_refresh" -eq 0 ]; then if [ $((now - last_refresh)) -ge 15 ] || [ "$last_refresh" -eq 0 ]; then
@@ -3233,59 +3233,44 @@ show_advanced_stats() {
wait wait
[ -f "$_adv_tmpdir/stats" ] && adv_all_stats=$(cat "$_adv_tmpdir/stats") [ -f "$_adv_tmpdir/stats" ] && adv_all_stats=$(cat "$_adv_tmpdir/stats")
# Parse all container stats + logs in one awk pass each (avoid per-container subshells)
if [ -n "$adv_all_stats" ]; then
local _parsed
_parsed=$(awk -F'|' '{
cpu=$2; gsub(/%/,"",cpu)
split($3,mp,"/"); mem=mp[1]; lim=mp[2]
gsub(/^[ \t]+|[ \t]+$/,"",mem); gsub(/^[ \t]+|[ \t]+$/,"",lim)
mval=mem+0; munit=mem; gsub(/[0-9. ]/,"",munit)
if(munit=="GiB") mval*=1024; else if(munit=="KiB") mval/=1024
tc+=cpu+0; tm+=mval; n++
if(fl=="") fl=lim
} END {printf "%.2f|%.2f|%d|%s", tc, tm, n, fl}' <<< "$adv_all_stats")
total_cpu=${_parsed%%|*}; _parsed=${_parsed#*|}
total_mem_mib=${_parsed%%|*}; _parsed=${_parsed#*|}
container_count=${_parsed%%|*}
first_mem_limit=${_parsed#*|}
fi
# Parse all log files in one pass (connected, up, down per container)
for ci in $(seq 1 $CONTAINER_COUNT); do for ci in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $ci) if [ -f "$_adv_tmpdir/logs_${ci}" ] && [ -s "$_adv_tmpdir/logs_${ci}" ]; then
if echo "$docker_ps_cache" | grep -q "^${cname}$"; then local _lp
container_count=$((container_count + 1)) _lp=$(awk '{
for(i=1;i<=NF;i++){
local stats=$(echo "$adv_all_stats" | grep "^${cname}|" 2>/dev/null) if($i=="Connected:") c=$(i+1)+0
local cpu=$(echo "$stats" | cut -d'|' -f2 | tr -d '%') if($i=="Up:"){v=$(i+1)+0; u=$(i+2); gsub(/[^A-Za-z]/,"",u)
[[ "$cpu" =~ ^[0-9.]+$ ]] && total_cpu=$(awk -v a="$total_cpu" -v b="$cpu" 'BEGIN{printf "%.2f", a+b}') if(u=="GB") ub=v*1073741824; else if(u=="MB") ub=v*1048576
else if(u=="KB") ub=v*1024; else ub=v}
local cmem_str=$(echo "$stats" | cut -d'|' -f3 | awk '{print $1}') if($i=="Down:"){v=$(i+1)+0; u=$(i+2); gsub(/[^A-Za-z]/,"",u)
local cmem_val=$(echo "$cmem_str" | sed 's/[^0-9.]//g') if(u=="GB") db=v*1073741824; else if(u=="MB") db=v*1048576
local cmem_unit=$(echo "$cmem_str" | sed 's/[0-9.]//g') else if(u=="KB") db=v*1024; else db=v}
if [[ "$cmem_val" =~ ^[0-9.]+$ ]]; then }
case "$cmem_unit" in } END {printf "%d|%.0f|%.0f", c+0, ub+0, db+0}' "$_adv_tmpdir/logs_${ci}")
GiB) cmem_val=$(awk -v v="$cmem_val" 'BEGIN{printf "%.2f", v*1024}') ;; local _lconn=${_lp%%|*}; _lp=${_lp#*|}
KiB) cmem_val=$(awk -v v="$cmem_val" 'BEGIN{printf "%.2f", v/1024}') ;; local _lup=${_lp%%|*}; local _ldown=${_lp#*|}
esac total_conn=$((total_conn + _lconn))
total_mem_mib=$(awk -v a="$total_mem_mib" -v b="$cmem_val" 'BEGIN{printf "%.2f", a+b}') total_up_bytes=$((total_up_bytes + _lup))
fi total_down_bytes=$((total_down_bytes + _ldown))
[ -z "$first_mem_limit" ] && first_mem_limit=$(echo "$stats" | cut -d'|' -f3 | awk -F'/' '{print $2}' | xargs)
local logs=""
[ -f "$_adv_tmpdir/logs_${ci}" ] && logs=$(cat "$_adv_tmpdir/logs_${ci}")
local conn=$(echo "$logs" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p')
[[ "$conn" =~ ^[0-9]+$ ]] && total_conn=$((total_conn + conn))
# Parse upload/download to bytes
local up_raw=$(echo "$logs" | sed -n 's/.*Up:[[:space:]]*\([^|]*\).*/\1/p' | xargs)
local down_raw=$(echo "$logs" | sed -n 's/.*Down:[[:space:]]*\([^|]*\).*/\1/p' | xargs)
if [ -n "$up_raw" ]; then
local up_val=$(echo "$up_raw" | sed 's/[^0-9.]//g')
local up_unit=$(echo "$up_raw" | sed 's/[0-9. ]//g')
if [[ "$up_val" =~ ^[0-9.]+$ ]]; then
case "$up_unit" in
GB) total_up_bytes=$(awk -v a="$total_up_bytes" -v v="$up_val" 'BEGIN{printf "%.0f", a+v*1073741824}') ;;
MB) total_up_bytes=$(awk -v a="$total_up_bytes" -v v="$up_val" 'BEGIN{printf "%.0f", a+v*1048576}') ;;
KB) total_up_bytes=$(awk -v a="$total_up_bytes" -v v="$up_val" 'BEGIN{printf "%.0f", a+v*1024}') ;;
B) total_up_bytes=$(awk -v a="$total_up_bytes" -v v="$up_val" 'BEGIN{printf "%.0f", a+v}') ;;
esac
fi
fi
if [ -n "$down_raw" ]; then
local down_val=$(echo "$down_raw" | sed 's/[^0-9.]//g')
local down_unit=$(echo "$down_raw" | sed 's/[0-9. ]//g')
if [[ "$down_val" =~ ^[0-9.]+$ ]]; then
case "$down_unit" in
GB) total_down_bytes=$(awk -v a="$total_down_bytes" -v v="$down_val" 'BEGIN{printf "%.0f", a+v*1073741824}') ;;
MB) total_down_bytes=$(awk -v a="$total_down_bytes" -v v="$down_val" 'BEGIN{printf "%.0f", a+v*1048576}') ;;
KB) total_down_bytes=$(awk -v a="$total_down_bytes" -v v="$down_val" 'BEGIN{printf "%.0f", a+v*1024}') ;;
B) total_down_bytes=$(awk -v a="$total_down_bytes" -v v="$down_val" 'BEGIN{printf "%.0f", a+v}') ;;
esac
fi
fi
fi fi
done done
rm -rf "$_adv_tmpdir" rm -rf "$_adv_tmpdir"
@@ -3307,36 +3292,40 @@ show_advanced_stats() {
echo -e "${CYAN}║${NC} ${RED}No Containers Running${NC}\033[K" echo -e "${CYAN}║${NC} ${RED}No Containers Running${NC}\033[K"
fi fi
# Network info # Network info (single ip route call)
local ip=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}') local _netinfo=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++){if($i=="src")s=$(i+1);if($i=="dev")d=$(i+1)}} END{print s"|"d}')
local iface=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}') local ip="${_netinfo%%|*}" iface="${_netinfo#*|}"
printf "${CYAN}║${NC} Net: ${GREEN}%s${NC} (%s)\033[K\n" "${ip:-N/A}" "${iface:-?}" printf "${CYAN}║${NC} Net: ${GREEN}%s${NC} (%s)\033[K\n" "${ip:-N/A}" "${iface:-?}"
echo -e "${CYAN}╠${D}${NC}\033[K" echo -e "${CYAN}╠${D}${NC}\033[K"
# Load tracker data # Load tracker data (awk for speed — bash while-read is too slow on large files)
local total_active=0 total_in=0 total_out=0 local total_active=0 total_in=0 total_out=0
unset cips cbw_in cbw_out unset cips cbw_in cbw_out
declare -A cips cbw_in cbw_out declare -A cips cbw_in cbw_out
if [ -s "$persist_dir/cumulative_data" ]; then if [ -s "$persist_dir/cumulative_data" ]; then
while IFS='|' read -r country from_bytes to_bytes; do local _cd_parsed
[ -z "$country" ] && continue _cd_parsed=$(awk -F'|' '$1!="" && $1!~/can.t|error/ {f=int($2+0); t=int($3+0); print $1"|"f"|"t; gi+=f; go+=t} END{print "_GI|"gi+0"|"go+0}' "$persist_dir/cumulative_data" 2>/dev/null)
from_bytes=$(printf '%.0f' "${from_bytes:-0}" 2>/dev/null) || from_bytes=0 while IFS='|' read -r _c _f _t; do
to_bytes=$(printf '%.0f' "${to_bytes:-0}" 2>/dev/null) || to_bytes=0 if [ "$_c" = "_GI" ]; then
cbw_in["$country"]=$from_bytes total_in=$_f; total_out=$_t
cbw_out["$country"]=$to_bytes else
total_in=$((total_in + from_bytes)) cbw_in["$_c"]=$_f; cbw_out["$_c"]=$_t
total_out=$((total_out + to_bytes)) fi
done < "$persist_dir/cumulative_data" done <<< "$_cd_parsed"
fi fi
if [ -s "$persist_dir/cumulative_ips" ]; then if [ -s "$persist_dir/cumulative_ips" ]; then
while IFS='|' read -r country ip_addr; do local _ip_parsed
[ -z "$country" ] && continue _ip_parsed=$(awk -F'|' '$1!="" {a[$1]++; t++} END{for(c in a) print c"|"a[c]; print "_GT|"t+0}' "$persist_dir/cumulative_ips" 2>/dev/null)
cips["$country"]=$((${cips["$country"]:-0} + 1)) while IFS='|' read -r _c _n; do
total_active=$((total_active + 1)) if [ "$_c" = "_GT" ]; then
done < "$persist_dir/cumulative_ips" total_active=$_n
else
cips["$_c"]=$_n
fi
done <<< "$_ip_parsed"
fi fi
local tstat="${RED}Off${NC}"; is_tracker_active && tstat="${GREEN}On${NC}" local tstat="${RED}Off${NC}"; is_tracker_active && tstat="${GREEN}On${NC}"
@@ -3351,7 +3340,7 @@ show_advanced_stats() {
[ "$peers" -eq 0 ] && [ "$active_cnt" -gt 0 ] && peers=1 [ "$peers" -eq 0 ] && [ "$active_cnt" -gt 0 ] && peers=1
local pct=$((peers * 100 / total_conn)) local pct=$((peers * 100 / total_conn))
local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14 local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14
local bfill=""; for ((i=0; i<blen; i++)); do bfill+="█"; done local bfill=$(printf '%*s' "$blen" '' | sed 's/ /█/g')
printf "${CYAN}║${NC} %-16.16s %3d%% ${CYAN}%-14s${NC} (%s IPs)\033[K\n" "$country" "$pct" "$bfill" "$(format_number $peers)" printf "${CYAN}║${NC} %-16.16s %3d%% ${CYAN}%-14s${NC} (%s IPs)\033[K\n" "$country" "$pct" "$bfill" "$(format_number $peers)"
done done
elif [ "$total_traffic" -gt 0 ]; then elif [ "$total_traffic" -gt 0 ]; then
@@ -3361,7 +3350,7 @@ show_advanced_stats() {
done | sort -t'|' -k1 -nr | head -7 | while IFS='|' read -r bytes country; do done | sort -t'|' -k1 -nr | head -7 | while IFS='|' read -r bytes country; do
local pct=$((bytes * 100 / total_traffic)) local pct=$((bytes * 100 / total_traffic))
local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14 local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14
local bfill=""; for ((i=0; i<blen; i++)); do bfill+="█"; done local bfill=$(printf '%*s' "$blen" '' | sed 's/ /█/g')
printf "${CYAN}║${NC} %-16.16s %3d%% ${CYAN}%-14s${NC} (%9s)\033[K\n" "$country" "$pct" "$bfill" "by traffic" printf "${CYAN}║${NC} %-16.16s %3d%% ${CYAN}%-14s${NC} (%9s)\033[K\n" "$country" "$pct" "$bfill" "by traffic"
done done
else else
@@ -3374,7 +3363,7 @@ show_advanced_stats() {
for c in "${!cbw_in[@]}"; do echo "${cbw_in[$c]}|$c"; done | sort -t'|' -k1 -nr | head -7 | while IFS='|' read -r bytes country; do for c in "${!cbw_in[@]}"; do echo "${cbw_in[$c]}|$c"; done | sort -t'|' -k1 -nr | head -7 | while IFS='|' read -r bytes country; do
local pct=$((bytes * 100 / total_in)) local pct=$((bytes * 100 / total_in))
local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14 local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14
local bfill=""; for ((i=0; i<blen; i++)); do bfill+="█"; done local bfill=$(printf '%*s' "$blen" '' | sed 's/ /█/g')
printf "${CYAN}║${NC} %-16.16s %3d%% ${GREEN}%-14s${NC} (%9s)\033[K\n" "$country" "$pct" "$bfill" "$(format_bytes $bytes)" printf "${CYAN}║${NC} %-16.16s %3d%% ${GREEN}%-14s${NC} (%9s)\033[K\n" "$country" "$pct" "$bfill" "$(format_bytes $bytes)"
done done
else else
@@ -3387,7 +3376,7 @@ show_advanced_stats() {
for c in "${!cbw_out[@]}"; do echo "${cbw_out[$c]}|$c"; done | sort -t'|' -k1 -nr | head -7 | while IFS='|' read -r bytes country; do for c in "${!cbw_out[@]}"; do echo "${cbw_out[$c]}|$c"; done | sort -t'|' -k1 -nr | head -7 | while IFS='|' read -r bytes country; do
local pct=$((bytes * 100 / total_out)) local pct=$((bytes * 100 / total_out))
local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14 local blen=$((pct / 8)); [ "$blen" -lt 1 ] && blen=1; [ "$blen" -gt 14 ] && blen=14
local bfill=""; for ((i=0; i<blen; i++)); do bfill+="█"; done local bfill=$(printf '%*s' "$blen" '' | sed 's/ /█/g')
printf "${CYAN}║${NC} %-16.16s %3d%% ${YELLOW}%-14s${NC} (%9s)\033[K\n" "$country" "$pct" "$bfill" "$(format_bytes $bytes)" printf "${CYAN}║${NC} %-16.16s %3d%% ${YELLOW}%-14s${NC} (%9s)\033[K\n" "$country" "$pct" "$bfill" "$(format_bytes $bytes)"
done done
else else