- Intelligent hardware detection and analysis - Modular optimization system with profiles - Automatic tmpfs, zram, and kernel tuning - Real-time monitoring and health checks - Support for desktop, gaming, and development workloads - Safe backup and rollback capabilities - Systemd integration for persistent optimizations
426 lines
12 KiB
Bash
Executable File
426 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# System Monitoring and Health Check
|
|
# Part of Linux System Tuning Suite
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
LOG_DIR="/var/log/system-tuning"
|
|
METRICS_FILE="$LOG_DIR/metrics.log"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log() {
|
|
echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
show_usage() {
|
|
cat << EOF
|
|
System Monitoring Tool
|
|
|
|
Usage: $0 [OPTIONS] [MODE]
|
|
|
|
OPTIONS:
|
|
-h, --help Show this help message
|
|
-l, --log Log metrics to file
|
|
-d, --duration SEC Monitoring duration in seconds (default: continuous)
|
|
|
|
MODES:
|
|
status Show current status (default)
|
|
live Live monitoring with updates
|
|
benchmark Run performance benchmarks
|
|
health Health check of optimizations
|
|
compare Compare performance before/after
|
|
export Export metrics for external analysis
|
|
|
|
EXAMPLES:
|
|
$0 # Show current status
|
|
$0 live # Live monitoring
|
|
$0 health # Health check
|
|
$0 benchmark # Run benchmarks
|
|
|
|
EOF
|
|
}
|
|
|
|
setup_logging() {
|
|
if [[ ! -d "$LOG_DIR" ]]; then
|
|
sudo mkdir -p "$LOG_DIR"
|
|
sudo chown $USER:$USER "$LOG_DIR" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
collect_metrics() {
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
# Memory metrics
|
|
local mem_info=$(free -m | awk '/^Mem:/{printf "total:%s,used:%s,free:%s,available:%s", $2,$3,$4,$7}')
|
|
local swap_info=$(free -m | awk '/^Swap:/{printf "total:%s,used:%s,free:%s", $2,$3,$4}')
|
|
|
|
# zram metrics
|
|
local zram_info=""
|
|
if [[ -e /dev/zram0 ]]; then
|
|
local zram_size=$(cat /sys/block/zram0/disksize 2>/dev/null || echo "0")
|
|
local zram_used=$(cat /sys/block/zram0/compr_data_size 2>/dev/null || echo "0")
|
|
local zram_orig=$(cat /sys/block/zram0/orig_data_size 2>/dev/null || echo "0")
|
|
zram_info="size:$zram_size,used:$zram_used,orig:$zram_orig"
|
|
fi
|
|
|
|
# tmpfs metrics
|
|
local tmpfs_count=$(mount -t tmpfs | wc -l)
|
|
local tmpfs_total=$(df -t tmpfs --total | tail -1 | awk '{print $2}' 2>/dev/null || echo "0")
|
|
local tmpfs_used=$(df -t tmpfs --total | tail -1 | awk '{print $3}' 2>/dev/null || echo "0")
|
|
|
|
# System load
|
|
local load_avg=$(uptime | awk -F'load average:' '{print $2}' | sed 's/^ *//')
|
|
|
|
# I/O stats
|
|
local io_stats=""
|
|
if command -v iostat >/dev/null 2>&1; then
|
|
io_stats=$(iostat -d 1 2 | tail -n +4 | awk 'NR>1{tps+=$2; read+=$3; write+=$4} END{printf "tps:%.2f,read:%.2f,write:%.2f", tps, read, write}')
|
|
fi
|
|
|
|
cat << EOF
|
|
{
|
|
"timestamp": "$timestamp",
|
|
"memory": {$mem_info},
|
|
"swap": {$swap_info},
|
|
"zram": {$zram_info},
|
|
"tmpfs": {"count": $tmpfs_count, "total_kb": $tmpfs_total, "used_kb": $tmpfs_used},
|
|
"load": "$load_avg",
|
|
"io": {$io_stats}
|
|
}
|
|
EOF
|
|
}
|
|
|
|
show_status() {
|
|
echo "🚀 System Tuning Status"
|
|
echo "======================="
|
|
echo ""
|
|
|
|
# Memory overview
|
|
echo "💾 Memory Overview:"
|
|
free -h | while IFS= read -r line; do
|
|
echo " $line"
|
|
done
|
|
echo ""
|
|
|
|
# zram status
|
|
echo "🔄 Compression (zram):"
|
|
if [[ -e /dev/zram0 ]]; then
|
|
if command -v zramctl >/dev/null 2>&1; then
|
|
zramctl | while IFS= read -r line; do
|
|
echo " $line"
|
|
done
|
|
else
|
|
local zram_size=$(cat /sys/block/zram0/disksize 2>/dev/null)
|
|
local zram_used=$(cat /sys/block/zram0/compr_data_size 2>/dev/null)
|
|
echo " Size: $((zram_size / 1024 / 1024 / 1024))GB"
|
|
echo " Used: $((zram_used / 1024 / 1024))MB"
|
|
fi
|
|
else
|
|
echo " Not configured"
|
|
fi
|
|
echo ""
|
|
|
|
# tmpfs overview
|
|
echo "📁 tmpfs Filesystems:"
|
|
df -h -t tmpfs | while IFS= read -r line; do
|
|
echo " $line"
|
|
done
|
|
echo ""
|
|
|
|
# Kernel parameters
|
|
echo "⚙️ Key Kernel Parameters:"
|
|
echo " Swappiness: $(cat /proc/sys/vm/swappiness)"
|
|
echo " Dirty ratio: $(cat /proc/sys/vm/dirty_ratio)"
|
|
echo " Dirty background ratio: $(cat /proc/sys/vm/dirty_background_ratio)"
|
|
echo " VFS cache pressure: $(cat /proc/sys/vm/vfs_cache_pressure)"
|
|
echo ""
|
|
|
|
# Service status
|
|
echo "🔧 Services:"
|
|
if systemctl is-enabled system-tuning.service >/dev/null 2>&1; then
|
|
echo " System tuning service: ✅ ENABLED"
|
|
else
|
|
echo " System tuning service: ❌ DISABLED"
|
|
fi
|
|
|
|
# Performance score
|
|
echo ""
|
|
echo "📊 Performance Score: $(calculate_performance_score)/100"
|
|
}
|
|
|
|
live_monitoring() {
|
|
local duration=${1:-0}
|
|
local count=0
|
|
|
|
echo "📊 Live System Monitoring"
|
|
echo "========================"
|
|
echo "Press Ctrl+C to stop"
|
|
echo ""
|
|
|
|
while true; do
|
|
clear
|
|
echo "🔄 Live Monitor - $(date) (Update #$((++count)))"
|
|
echo "=================================================="
|
|
echo ""
|
|
|
|
# Real-time metrics
|
|
echo "Memory Usage:"
|
|
free -h | head -2
|
|
echo ""
|
|
|
|
echo "Top tmpfs by usage:"
|
|
df -h -t tmpfs | sort -k5 -nr | head -5 | while IFS= read -r line; do
|
|
echo " $line"
|
|
done
|
|
echo ""
|
|
|
|
echo "zram compression ratio:"
|
|
if [[ -e /dev/zram0 ]]; then
|
|
local orig=$(cat /sys/block/zram0/orig_data_size 2>/dev/null || echo "0")
|
|
local compr=$(cat /sys/block/zram0/compr_data_size 2>/dev/null || echo "0")
|
|
if [[ $orig -gt 0 && $compr -gt 0 ]]; then
|
|
local ratio=$(echo "scale=2; $orig / $compr" | bc -l 2>/dev/null || echo "N/A")
|
|
echo " Compression: ${ratio}:1"
|
|
echo " Original: $((orig / 1024 / 1024))MB"
|
|
echo " Compressed: $((compr / 1024 / 1024))MB"
|
|
else
|
|
echo " No compression data available"
|
|
fi
|
|
else
|
|
echo " zram not active"
|
|
fi
|
|
echo ""
|
|
|
|
echo "System Load: $(uptime | awk -F'load average:' '{print $2}')"
|
|
|
|
# Log metrics if enabled
|
|
if [[ -f "$METRICS_FILE" ]]; then
|
|
collect_metrics >> "$METRICS_FILE"
|
|
fi
|
|
|
|
sleep 2
|
|
|
|
# Exit if duration specified and reached
|
|
if [[ $duration -gt 0 && $count -ge $duration ]]; then
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
run_benchmark() {
|
|
echo "🏁 Performance Benchmark"
|
|
echo "========================"
|
|
echo ""
|
|
|
|
log "Running memory performance tests..."
|
|
|
|
# Memory speed test
|
|
echo "Memory Performance:"
|
|
if command -v dd >/dev/null 2>&1; then
|
|
echo " Write test (1GB to tmpfs):"
|
|
time (dd if=/dev/zero of=/tmp/benchmark-test bs=1M count=1024 2>/dev/null && sync)
|
|
rm -f /tmp/benchmark-test
|
|
echo ""
|
|
fi
|
|
|
|
# Application startup test
|
|
echo "Application Startup Test:"
|
|
if command -v time >/dev/null 2>&1; then
|
|
echo " Shell startup:"
|
|
time bash -c "exit" 2>&1 | grep real || echo " Could not measure"
|
|
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
echo " Python startup:"
|
|
time python3 -c "pass" 2>&1 | grep real || echo " Could not measure"
|
|
fi
|
|
fi
|
|
echo ""
|
|
|
|
# I/O performance
|
|
if command -v iostat >/dev/null 2>&1; then
|
|
echo "Current I/O performance:"
|
|
iostat -x 1 1 | tail -n +4
|
|
fi
|
|
echo ""
|
|
|
|
success "Benchmark completed"
|
|
}
|
|
|
|
health_check() {
|
|
echo "🏥 System Health Check"
|
|
echo "====================="
|
|
echo ""
|
|
|
|
local issues=0
|
|
local warnings=0
|
|
|
|
# Check zram
|
|
if [[ -e /dev/zram0 ]]; then
|
|
if swapon --show | grep -q zram0; then
|
|
success "zram swap is active"
|
|
else
|
|
error "zram device exists but swap is not active"
|
|
((issues++))
|
|
fi
|
|
else
|
|
warn "zram not configured"
|
|
((warnings++))
|
|
fi
|
|
|
|
# Check tmpfs mounts
|
|
local tmpfs_count=$(mount -t tmpfs | wc -l)
|
|
if [[ $tmpfs_count -gt 5 ]]; then
|
|
success "Multiple tmpfs mounts detected ($tmpfs_count)"
|
|
else
|
|
warn "Few tmpfs mounts detected ($tmpfs_count) - consider more optimizations"
|
|
((warnings++))
|
|
fi
|
|
|
|
# Check memory usage
|
|
local mem_usage=$(free | awk '/^Mem:/{printf "%.0f", $3/$2*100}')
|
|
if [[ $mem_usage -lt 80 ]]; then
|
|
success "Memory usage is healthy ($mem_usage%)"
|
|
else
|
|
warn "High memory usage ($mem_usage%) - monitor for performance impact"
|
|
((warnings++))
|
|
fi
|
|
|
|
# Check swap usage
|
|
local swap_usage=$(free | awk '/^Swap:/{if($2>0) printf "%.0f", $3/$2*100; else print "0"}')
|
|
if [[ $swap_usage -lt 50 ]]; then
|
|
success "Swap usage is reasonable ($swap_usage%)"
|
|
else
|
|
warn "High swap usage ($swap_usage%) - consider adding more RAM"
|
|
((warnings++))
|
|
fi
|
|
|
|
# Check service status
|
|
if systemctl is-active system-tuning.service >/dev/null 2>&1; then
|
|
success "System tuning service is running"
|
|
else
|
|
warn "System tuning service is not running"
|
|
((warnings++))
|
|
fi
|
|
|
|
echo ""
|
|
echo "Health Summary:"
|
|
echo " Issues: $issues"
|
|
echo " Warnings: $warnings"
|
|
|
|
if [[ $issues -eq 0 && $warnings -eq 0 ]]; then
|
|
success "System is optimally configured! 🎉"
|
|
elif [[ $issues -eq 0 ]]; then
|
|
warn "System is mostly optimized with $warnings minor warnings"
|
|
else
|
|
error "System has $issues issues that need attention"
|
|
fi
|
|
}
|
|
|
|
calculate_performance_score() {
|
|
local score=0
|
|
|
|
# Base score
|
|
score=30
|
|
|
|
# zram bonus
|
|
[[ -e /dev/zram0 ]] && score=$((score + 20))
|
|
|
|
# tmpfs bonus
|
|
local tmpfs_count=$(mount -t tmpfs | wc -l)
|
|
if [[ $tmpfs_count -gt 8 ]]; then
|
|
score=$((score + 25))
|
|
elif [[ $tmpfs_count -gt 5 ]]; then
|
|
score=$((score + 15))
|
|
fi
|
|
|
|
# Kernel parameter optimization
|
|
local swappiness=$(cat /proc/sys/vm/swappiness)
|
|
[[ $swappiness -le 10 ]] && score=$((score + 10))
|
|
|
|
# Service bonus
|
|
systemctl is-enabled system-tuning.service >/dev/null 2>&1 && score=$((score + 15))
|
|
|
|
echo $score
|
|
}
|
|
|
|
main() {
|
|
local mode="status"
|
|
local log_metrics=false
|
|
local duration=0
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-h|--help)
|
|
show_usage
|
|
exit 0
|
|
;;
|
|
-l|--log)
|
|
log_metrics=true
|
|
shift
|
|
;;
|
|
-d|--duration)
|
|
duration="$2"
|
|
shift 2
|
|
;;
|
|
status|live|benchmark|health|compare|export)
|
|
mode="$1"
|
|
shift
|
|
;;
|
|
*)
|
|
error "Unknown option: $1"
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Setup logging if requested
|
|
if [[ "$log_metrics" == "true" ]]; then
|
|
setup_logging
|
|
fi
|
|
|
|
# Execute requested mode
|
|
case "$mode" in
|
|
status)
|
|
show_status
|
|
;;
|
|
live)
|
|
live_monitoring "$duration"
|
|
;;
|
|
benchmark)
|
|
run_benchmark
|
|
;;
|
|
health)
|
|
health_check
|
|
;;
|
|
*)
|
|
error "Mode '$mode' not implemented yet"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Run if called directly
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi |