|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# Shared Memory Monitoring Script |
| 4 | +# Optimized for systems with many cores |
| 5 | + |
| 6 | +# Colors for output |
| 7 | +GREEN='\033[0;32m' |
| 8 | +YELLOW='\033[1;33m' |
| 9 | +BLUE='\033[0;34m' |
| 10 | +RED='\033[0;31m' |
| 11 | +CYAN='\033[0;36m' |
| 12 | +NC='\033[0m' # No Color |
| 13 | + |
| 14 | +# History arrays (store last 60 data points = 1 minute) |
| 15 | +HISTORY_SIZE=60 |
| 16 | +shmem_history=() |
| 17 | +devshm_history=() |
| 18 | + |
| 19 | +# Track observed maximums (for stable scaling) |
| 20 | +# Initialize to current values instead of 1 to avoid massive initial spike |
| 21 | +shmem_max=$(grep "^Shmem:" /proc/meminfo | awk '{printf "%.2f", $2/1024/1024}') |
| 22 | +devshm_max=$(df --output=used /dev/shm | tail -1 | awk '{printf "%.2f", $1/1024/1024}') |
| 23 | + |
| 24 | +# Ensure they're not zero |
| 25 | +if (( $(echo "$shmem_max < 1" | bc -l) )); then shmem_max=1; fi |
| 26 | +if (( $(echo "$devshm_max < 1" | bc -l) )); then devshm_max=1; fi |
| 27 | + |
| 28 | +# Function to draw ASCII sparkline with fixed scale |
| 29 | +draw_plot() { |
| 30 | + local -n data=$1 |
| 31 | + local label=$2 |
| 32 | + local color=$3 |
| 33 | + local max_val=$4 |
| 34 | + |
| 35 | + # Avoid division by zero |
| 36 | + if (( $(echo "$max_val == 0" | bc -l) )); then |
| 37 | + max_val=1 |
| 38 | + fi |
| 39 | + |
| 40 | + # Draw the sparkline (using block characters) |
| 41 | + local chars=("▁" "▂" "▃" "▄" "▅" "▆" "▇" "█") |
| 42 | + local line="${color}${label}: " |
| 43 | + |
| 44 | + for val in "${data[@]}"; do |
| 45 | + # Scale to 0-7 range |
| 46 | + local scaled=$(echo "scale=0; ($val / $max_val) * 7" | bc -l) |
| 47 | + scaled=${scaled%.*} # Remove decimal |
| 48 | + # Clamp to 0-7 range (in case value exceeds max) |
| 49 | + if [ $scaled -gt 7 ]; then scaled=7; fi |
| 50 | + if [ $scaled -lt 0 ]; then scaled=0; fi |
| 51 | + line+="${chars[$scaled]}" |
| 52 | + done |
| 53 | + |
| 54 | + line+=" (max: $(printf "%.1f" $max_val) GB)${NC}" |
| 55 | + echo -e "$line" |
| 56 | +} |
| 57 | + |
| 58 | +while true; do |
| 59 | + # Capture current values for plotting (in GB) |
| 60 | + shmem_gb=$(grep "^Shmem:" /proc/meminfo | awk '{printf "%.2f", $2/1024/1024}') |
| 61 | + devshm_gb=$(df --output=used /dev/shm | tail -1 | awk '{printf "%.2f", $1/1024/1024}') |
| 62 | + |
| 63 | + # Update observed maximums (only increase, with slow decay) |
| 64 | + if (( $(echo "$shmem_gb > $shmem_max" | bc -l) )); then |
| 65 | + shmem_max=$shmem_gb |
| 66 | + else |
| 67 | + # Slowly decay max (0.1% per second) to allow adaptation to lower values |
| 68 | + shmem_max=$(echo "$shmem_max * 0.999" | bc -l) |
| 69 | + fi |
| 70 | + |
| 71 | + if (( $(echo "$devshm_gb > $devshm_max" | bc -l) )); then |
| 72 | + devshm_max=$devshm_gb |
| 73 | + else |
| 74 | + devshm_max=$(echo "$devshm_max * 0.999" | bc -l) |
| 75 | + fi |
| 76 | + |
| 77 | + # Add to history arrays |
| 78 | + shmem_history+=("$shmem_gb") |
| 79 | + devshm_history+=("$devshm_gb") |
| 80 | + |
| 81 | + # Trim history to max size |
| 82 | + if [ ${#shmem_history[@]} -gt $HISTORY_SIZE ]; then |
| 83 | + shmem_history=("${shmem_history[@]:1}") |
| 84 | + fi |
| 85 | + if [ ${#devshm_history[@]} -gt $HISTORY_SIZE ]; then |
| 86 | + devshm_history=("${devshm_history[@]:1}") |
| 87 | + fi |
| 88 | + |
| 89 | + # Build entire output in a variable first (prevents flickering) |
| 90 | + output="" |
| 91 | + |
| 92 | + output+="${GREEN}=== System Memory Overview ===${NC}\n" |
| 93 | + output+="$(free -h --wide)\n" |
| 94 | + |
| 95 | + output+="\n${YELLOW}=== /dev/shm Usage ===${NC}\n" |
| 96 | + output+="$(df -h /dev/shm | tail -n +2)\n" |
| 97 | + output+="Largest 5 files/dirs (top-level only):\n" |
| 98 | + output+="$(ls -lhS /dev/shm 2>/dev/null | grep '^[-d]' | head -5 | awk '{printf " %8s %s\n", $5, $9}')\n" |
| 99 | + |
| 100 | + output+="\n${BLUE}=== Shared Memory Segments (IPC) ===${NC}\n" |
| 101 | + output+="$(ipcs -m --human 2>/dev/null | head -20 || ipcs -m | head -20)\n" |
| 102 | + |
| 103 | + output+="\n${GREEN}=== Top 10 Processes by Memory ===${NC}\n" |
| 104 | + output+="$(ps aux --sort=-%mem | head -11 | awk 'NR==1 {print $0} NR>1 {printf "%-10s %6s %6s %10s %s\n", $1, $2, $4, $6, $11}')\n" |
| 105 | + |
| 106 | + output+="\n${YELLOW}=== Memory Stats ===${NC}\n" |
| 107 | + output+="MemTotal: $(grep MemTotal /proc/meminfo | awk '{printf "%.1f GB", $2/1024/1024}')\n" |
| 108 | + output+="MemFree: $(grep MemFree /proc/meminfo | awk '{printf "%.1f GB", $2/1024/1024}')\n" |
| 109 | + output+="MemAvailable: $(grep MemAvailable /proc/meminfo | awk '{printf "%.1f GB", $2/1024/1024}')\n" |
| 110 | + output+="Shmem: $(grep "^Shmem:" /proc/meminfo | awk '{printf "%.1f GB", $2/1024/1024}')\n" |
| 111 | + output+="Buffers: $(grep Buffers /proc/meminfo | awk '{printf "%.1f GB", $2/1024/1024}')\n" |
| 112 | + output+="Cached: $(grep "^Cached:" /proc/meminfo | awk '{printf "%.1f GB", $2/1024/1024}')\n" |
| 113 | + |
| 114 | + # Add time-series plots |
| 115 | + output+="\n${CYAN}=== Shared Memory Trend (last ${#shmem_history[@]}s) ===${NC}\n" |
| 116 | + output+="$(draw_plot shmem_history "Shmem (total) " "$YELLOW" "$shmem_max")\n" |
| 117 | + output+="$(draw_plot devshm_history "/dev/shm (files)" "$GREEN" "$devshm_max")\n" |
| 118 | + output+="Each character = 1 second | Scale adapts slowly to avoid jitter\n" |
| 119 | + |
| 120 | + output+="\n${BLUE}Last update: $(date '+%H:%M:%S')${NC} | Press Ctrl+C to exit\n" |
| 121 | + |
| 122 | + # Now clear and display everything at once (atomic operation) |
| 123 | + clear |
| 124 | + echo -e "$output" |
| 125 | + |
| 126 | + sleep 1 |
| 127 | +done |
0 commit comments