New features: - analyze_proxmox_status() function shows detailed system state - RAM usage and allocation - VM/Container count and status - Total VM memory allocation and overcommit ratio - Storage status (pvesm) - Current kernel parameters vs recommended - CPU governor status - ZFS ARC size (if applicable) - Existing optimizations detection - Added optimize_cpu_governor() function - Sets CPU to 'performance' mode for VMs - Makes persistent via cpufrequtils - Added optimize_zfs_arc() function - Limits ZFS ARC to 25% of RAM - Frees more RAM for VMs - Updates initramfs for persistence Analysis now runs automatically when Proxmox is detected, showing comprehensive system status before mode selection.
1739 lines
66 KiB
Bash
Executable File
1739 lines
66 KiB
Bash
Executable File
#!/bin/bash
|
||
# Working Interactive System Optimizer
|
||
|
||
set -euo pipefail
|
||
|
||
# Colors
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
# Configuration
|
||
BACKUP_DIR="/var/lib/system-tuning/backups"
|
||
LOG_FILE="/var/log/system-optimization.log"
|
||
|
||
log() {
|
||
echo -e "${BLUE}[INFO]${NC} $1"
|
||
[[ -w "$(dirname "$LOG_FILE")" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
|
||
}
|
||
|
||
success() {
|
||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||
[[ -w "$(dirname "$LOG_FILE")" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS: $1" >> "$LOG_FILE"
|
||
}
|
||
|
||
warn() {
|
||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||
[[ -w "$(dirname "$LOG_FILE")" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: $1" >> "$LOG_FILE"
|
||
}
|
||
|
||
error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
[[ -w "$(dirname "$LOG_FILE")" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >> "$LOG_FILE"
|
||
}
|
||
|
||
check_root() {
|
||
if [[ $EUID -ne 0 ]]; then
|
||
error "This script must be run as root"
|
||
echo "Usage: sudo $0"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
analyze_proxmox_status() {
|
||
echo -e "${CYAN}🔍 Proxmox Host Analysis${NC}"
|
||
echo "========================"
|
||
echo ""
|
||
|
||
# System info
|
||
local ram_gb=$(free -g | awk '/^Mem:|^Speicher:/{print $2}')
|
||
local ram_used=$(free -g | awk '/^Mem:|^Speicher:/{print $3}')
|
||
local ram_available=$(free -g | awk '/^Mem:|^Speicher:/{print $7}')
|
||
local cpu_cores=$(nproc)
|
||
local pve_version=$(pveversion | head -1 || echo "Unknown")
|
||
|
||
echo "📊 System Information:"
|
||
echo " 💾 RAM: ${ram_gb}GB (Used: ${ram_used}GB, Available: ${ram_available}GB)"
|
||
echo " 🖥️ CPU: ${cpu_cores} cores"
|
||
echo " 📦 Proxmox: $pve_version"
|
||
echo ""
|
||
|
||
# VM/Container workload
|
||
local vm_count=$(qm list 2>/dev/null | tail -n +2 | wc -l || echo "0")
|
||
local ct_count=$(pct list 2>/dev/null | tail -n +2 | wc -l || echo "0")
|
||
local vm_running=$(qm list 2>/dev/null | grep -c "running" || echo "0")
|
||
local ct_running=$(pct list 2>/dev/null | grep -c "running" || echo "0")
|
||
|
||
echo "🖥️ Workload:"
|
||
echo " 🖼️ VMs: $vm_count total ($vm_running running)"
|
||
echo " 📦 Containers: $ct_count total ($ct_running running)"
|
||
echo ""
|
||
|
||
# Check VM memory allocation
|
||
local total_vm_mem=0
|
||
if command -v qm &>/dev/null; then
|
||
while read -r vmid; do
|
||
local mem=$(qm config "$vmid" 2>/dev/null | grep "^memory:" | awk '{print $2}' || echo "0")
|
||
total_vm_mem=$((total_vm_mem + mem))
|
||
done < <(qm list 2>/dev/null | tail -n +2 | awk '{print $1}')
|
||
local total_vm_mem_gb=$((total_vm_mem / 1024))
|
||
echo " 📊 Total VM memory allocated: ${total_vm_mem_gb}GB"
|
||
local overcommit_ratio=$(echo "scale=1; $total_vm_mem_gb * 100 / $ram_gb" | bc 2>/dev/null || echo "N/A")
|
||
echo " 📈 Memory overcommit: ${overcommit_ratio}%"
|
||
echo ""
|
||
fi
|
||
|
||
# Storage
|
||
echo "💾 Storage:"
|
||
if command -v pvesm &>/dev/null; then
|
||
pvesm status 2>/dev/null | tail -n +2 | while read -r name type status total used avail percent; do
|
||
echo " • $name ($type): ${used}/${total} used"
|
||
done
|
||
fi
|
||
echo ""
|
||
|
||
# Check current kernel parameters
|
||
echo "⚙️ Current Kernel Parameters:"
|
||
local swappiness=$(sysctl -n vm.swappiness 2>/dev/null || echo "60")
|
||
local dirty_ratio=$(sysctl -n vm.dirty_ratio 2>/dev/null || echo "20")
|
||
local dirty_bg=$(sysctl -n vm.dirty_background_ratio 2>/dev/null || echo "10")
|
||
local cache_pressure=$(sysctl -n vm.vfs_cache_pressure 2>/dev/null || echo "100")
|
||
local qdisc=$(sysctl -n net.core.default_qdisc 2>/dev/null || echo "pfifo_fast")
|
||
local tcp_congestion=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || echo "cubic")
|
||
|
||
echo " 📊 Memory:"
|
||
echo " vm.swappiness: $swappiness (Proxmox recommended: 10)"
|
||
echo " vm.dirty_ratio: $dirty_ratio (Proxmox recommended: 10)"
|
||
echo " vm.dirty_background_ratio: $dirty_bg (Proxmox recommended: 5)"
|
||
echo " vm.vfs_cache_pressure: $cache_pressure (Proxmox recommended: 50)"
|
||
echo ""
|
||
echo " 📡 Network:"
|
||
echo " net.core.default_qdisc: $qdisc (Proxmox recommended: fq)"
|
||
echo " net.ipv4.tcp_congestion_control: $tcp_congestion (Proxmox recommended: bbr)"
|
||
echo ""
|
||
|
||
# Check CPU governor
|
||
local governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null || echo "unknown")
|
||
echo "🖥️ CPU Governor: $governor (Recommended: performance)"
|
||
echo ""
|
||
|
||
# Check ZFS if present
|
||
if command -v zpool &>/dev/null && zpool list &>/dev/null 2>&1; then
|
||
echo "🗄️ ZFS Configuration:"
|
||
local arc_max=$(cat /sys/module/zfs/parameters/zfs_arc_max 2>/dev/null || echo "0")
|
||
local arc_max_gb=$((arc_max / 1024 / 1024 / 1024))
|
||
local recommended_arc=$((ram_gb / 4))
|
||
echo " <20> Current ARC max: ${arc_max_gb}GB"
|
||
echo " 💡 Recommended: ${recommended_arc}GB (25% of RAM, leaves more for VMs)"
|
||
echo ""
|
||
fi
|
||
|
||
# Check for existing optimizations
|
||
echo "🔍 Existing Optimizations:"
|
||
local has_optimizations=false
|
||
|
||
if [[ -f /etc/sysctl.d/99-system-optimization.conf ]] || [[ -f /etc/sysctl.d/99-proxmox-tuning.conf ]]; then
|
||
echo " ✅ Custom sysctl configuration found"
|
||
has_optimizations=true
|
||
else
|
||
echo " ❌ No custom sysctl configuration"
|
||
fi
|
||
|
||
if mount | grep -q "tmpfs.*tmpfs-cache"; then
|
||
local tmpfs_count=$(mount | grep -c "tmpfs.*tmpfs-cache")
|
||
echo " ⚠️ tmpfs mounts found: $tmpfs_count (may use RAM needed by VMs)"
|
||
has_optimizations=true
|
||
else
|
||
echo " ✅ No tmpfs cache mounts (good for Proxmox)"
|
||
fi
|
||
|
||
if [[ -e /dev/zram0 ]] && swapon --show | grep -q zram0; then
|
||
local zram_size=$(swapon --show | grep zram0 | awk '{print $3}')
|
||
echo " ⚠️ zram active: $zram_size (reduces RAM for VMs)"
|
||
has_optimizations=true
|
||
else
|
||
echo " ✅ No zram (good for Proxmox)"
|
||
fi
|
||
echo ""
|
||
|
||
# Assessment
|
||
echo "📋 Assessment:"
|
||
local needs_optimization=false
|
||
|
||
if [[ "$swappiness" != "10" ]] || [[ "$dirty_ratio" != "10" ]] || [[ "$qdisc" != "fq" ]] || [[ "$tcp_congestion" != "bbr" ]]; then
|
||
echo " ⚠️ Kernel parameters not optimized for hypervisor workload"
|
||
needs_optimization=true
|
||
else
|
||
echo " ✅ Kernel parameters look good"
|
||
fi
|
||
|
||
if [[ "$governor" != "performance" ]] && [[ "$governor" != "unknown" ]]; then
|
||
echo " ⚠️ CPU governor not set to 'performance'"
|
||
needs_optimization=true
|
||
fi
|
||
|
||
if command -v zpool &>/dev/null && zpool list &>/dev/null 2>&1; then
|
||
if [[ $arc_max_gb -gt $recommended_arc ]]; then
|
||
echo " ⚠️ ZFS ARC could be limited to give VMs more RAM"
|
||
needs_optimization=true
|
||
fi
|
||
fi
|
||
|
||
if [[ "$needs_optimization" == "false" ]]; then
|
||
echo " ✅ System is already well-optimized for Proxmox!"
|
||
fi
|
||
|
||
echo ""
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo ""
|
||
}
|
||
|
||
check_proxmox() {
|
||
# Detect if running on Proxmox host
|
||
if [[ -f /etc/pve/.version ]] || [[ -d /etc/pve ]] || pveversion &>/dev/null; then
|
||
IS_PROXMOX_HOST=true
|
||
warn "⚠️ Proxmox VE host detected!"
|
||
echo ""
|
||
|
||
# Show detailed analysis
|
||
analyze_proxmox_status
|
||
|
||
echo "This tool has TWO modes:"
|
||
echo ""
|
||
echo " 1️⃣ Proxmox Host Mode (Hypervisor Optimization)"
|
||
echo " • Optimized kernel params for VM workloads"
|
||
echo " • Minimal RAM allocation (2GB APT cache only)"
|
||
echo " • CPU performance governor"
|
||
echo " • ZFS ARC limiting (if applicable)"
|
||
echo " • No desktop app configuration"
|
||
echo ""
|
||
echo " 2️⃣ Desktop Mode (NOT recommended for host)"
|
||
echo " • Heavy RAM usage (zram + tmpfs = 40-50%)"
|
||
echo " • Desktop-focused optimizations"
|
||
echo " • Will reduce memory available for VMs"
|
||
echo ""
|
||
echo " 3️⃣ Abort (Recommended: Run inside your desktop VMs)"
|
||
echo ""
|
||
read -p "Choose mode (1=Proxmox/2=Desktop/3=Abort) [1]: " -n 1 -r
|
||
echo
|
||
echo ""
|
||
|
||
case "$REPLY" in
|
||
1|"")
|
||
log "Running in Proxmox Host Mode"
|
||
PROXMOX_MODE=true
|
||
;;
|
||
2)
|
||
warn "Running in Desktop Mode on Proxmox host - this may affect VMs!"
|
||
read -p "Are you sure? This is NOT recommended. (yes/N): " confirm
|
||
if [[ "$confirm" != "yes" ]]; then
|
||
log "Aborted by user"
|
||
exit 0
|
||
fi
|
||
PROXMOX_MODE=false
|
||
warn "Proceeding with desktop optimizations - monitor VM performance!"
|
||
echo ""
|
||
;;
|
||
3|*)
|
||
log "Aborted by user. Consider running inside VMs instead."
|
||
echo ""
|
||
echo "💡 To optimize your desktop VMs:"
|
||
echo " 1. SSH into your VM"
|
||
echo " 2. Run: sudo ./one-button-optimizer.sh"
|
||
echo " 3. Enjoy full desktop optimizations safely!"
|
||
exit 0
|
||
;;
|
||
esac
|
||
else
|
||
IS_PROXMOX_HOST=false
|
||
PROXMOX_MODE=false
|
||
fi
|
||
}
|
||
|
||
analyze_and_prompt() {
|
||
log "Analyzing current system optimizations..."
|
||
|
||
# Get system info
|
||
local ram_gb=$(free -g | awk '/^Mem:|^Speicher:/{print $2}')
|
||
local cpu_cores=$(nproc)
|
||
|
||
echo ""
|
||
echo "📊 System Information:"
|
||
echo " 💾 RAM: ${ram_gb}GB"
|
||
echo " 🖥️ CPU: ${cpu_cores} cores"
|
||
if [[ "${PROXMOX_MODE:-false}" == "true" ]]; then
|
||
echo " 🖥️ Mode: Proxmox Host Optimization"
|
||
fi
|
||
echo ""
|
||
|
||
# Check and prompt for each optimization
|
||
local needs_changes=false
|
||
|
||
# === ZRAM CHECK ===
|
||
if [[ "${PROXMOX_MODE:-false}" == "true" ]]; then
|
||
# Proxmox mode: Skip zram entirely
|
||
echo "🗜️ zram Compressed Swap Analysis:"
|
||
echo " ⏭️ Skipped (not recommended for Proxmox hosts)"
|
||
echo " 💡 Reason: VMs need direct RAM access for performance"
|
||
SETUP_ZRAM=false
|
||
else
|
||
# Desktop mode: Original zram logic
|
||
echo "🗜️ zram Compressed Swap Analysis:"
|
||
local optimal_size=$((ram_gb / 2))
|
||
[[ $optimal_size -lt 2 ]] && optimal_size=2
|
||
|
||
if [[ -e /dev/zram0 ]] && swapon --show | grep -q zram0; then
|
||
local zram_size=$(swapon --show | grep zram0 | awk '{print $3}')
|
||
local zram_gb=$(echo "$zram_size" | sed 's/[^0-9.]//g' | cut -d. -f1)
|
||
|
||
echo " 📈 Current: $zram_size"
|
||
echo " 📊 Optimal: ${optimal_size}GB"
|
||
|
||
if [[ $zram_gb -gt $((optimal_size + 2)) ]] || [[ $zram_gb -lt $((optimal_size - 1)) ]]; then
|
||
echo " ⚠️ Current size is suboptimal"
|
||
needs_changes=true
|
||
read -p " Would you like to reconfigure zram to ${optimal_size}GB? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
SETUP_ZRAM=true
|
||
else
|
||
SETUP_ZRAM=false
|
||
fi
|
||
else
|
||
echo " ✅ Size is optimal"
|
||
SETUP_ZRAM=false
|
||
fi
|
||
else
|
||
echo " ❌ Not configured"
|
||
echo " 📊 Recommended: ${optimal_size}GB"
|
||
needs_changes=true
|
||
read -p " Would you like to configure zram? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
SETUP_ZRAM=true
|
||
else
|
||
SETUP_ZRAM=false
|
||
fi
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# === TMPFS CHECK ===
|
||
echo "💾 tmpfs Cache System Analysis:"
|
||
|
||
if [[ "${PROXMOX_MODE:-false}" == "true" ]]; then
|
||
# Proxmox mode: Minimal tmpfs for APT cache only
|
||
echo " 📦 Proxmox Host Mode: Minimal tmpfs allocation"
|
||
local apt_cache_size=$(du -sm /var/cache/apt/archives 2>/dev/null | awk '{print $1}' || echo "0")
|
||
echo " 📊 Current APT cache: ${apt_cache_size}MB"
|
||
echo " 💡 Recommended: 2GB tmpfs for package cache (minimal RAM impact)"
|
||
echo ""
|
||
read -p " Configure minimal tmpfs for APT cache? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
SETUP_TMPFS=true
|
||
TMPFS_PROFILE="proxmox"
|
||
else
|
||
SETUP_TMPFS=false
|
||
fi
|
||
else
|
||
# Desktop mode: Original tmpfs logic
|
||
local tmpfs_count=$(mount | grep "tmpfs.*tmpfs-cache" | wc -l)
|
||
if [[ $tmpfs_count -gt 0 ]]; then
|
||
echo " ✅ Well configured ($tmpfs_count active mounts)"
|
||
echo " 📁 Current mounted caches:"
|
||
mount | grep "tmpfs.*tmpfs-cache" | head -3 | awk '{print " " $3 " (" $6 ")"}' | tr -d '()'
|
||
[[ $tmpfs_count -gt 3 ]] && echo " ... and $((tmpfs_count - 3)) more"
|
||
echo ""
|
||
echo " 🔍 Scanning for additional optimization opportunities..."
|
||
else
|
||
echo " ❌ Not configured"
|
||
echo " 🔍 Scanning system for cache directories..."
|
||
fi
|
||
|
||
# === OVERLAY FILESYSTEM CHECK ===
|
||
echo "🗂️ Overlay Filesystem Analysis:"
|
||
local overlay_count=$(mount -t overlay | wc -l)
|
||
if [[ $overlay_count -gt 0 ]]; then
|
||
echo " ⚠️ Found $overlay_count overlay mounts (deprecated for desktop use)"
|
||
echo " 📁 Current overlay mounts:"
|
||
mount -t overlay | head -3 | awk '{print " " $3 " (overlay)"}'
|
||
[[ $overlay_count -gt 3 ]] && echo " ... and $((overlay_count - 3)) more"
|
||
echo ""
|
||
echo " 💡 Overlays are complex and rarely needed on desktop systems."
|
||
echo " 💡 Consider removing them unless specifically required."
|
||
needs_changes=true
|
||
read -p " Would you like to remove overlay mounts? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
REMOVE_OVERLAYS=true
|
||
else
|
||
REMOVE_OVERLAYS=false
|
||
fi
|
||
else
|
||
echo " ✅ No overlay mounts found (good - not needed for desktop)"
|
||
REMOVE_OVERLAYS=false
|
||
fi
|
||
echo ""
|
||
|
||
# Always analyze potential tmpfs candidates (even if already configured)
|
||
local cache_analysis=""
|
||
local total_cache_size=0
|
||
local additional_opportunities=""
|
||
|
||
# Check browser caches
|
||
for user_home in /home/*; do
|
||
if [[ -d "$user_home" ]]; then
|
||
local browser_cache_size=0
|
||
for cache_dir in "$user_home/.cache/google-chrome" "$user_home/.cache/firefox" "$user_home/.cache/chromium" "$user_home/.cache/microsoft-edge" "$user_home/.cache/brave" "$user_home/.cache/opera"; do
|
||
if [[ -d "$cache_dir" ]]; then
|
||
local size=$(du -sm "$cache_dir" 2>/dev/null | cut -f1 || echo 0)
|
||
browser_cache_size=$((browser_cache_size + size))
|
||
fi
|
||
done
|
||
if [[ $browser_cache_size -gt 0 ]]; then
|
||
cache_analysis="${cache_analysis} Browser caches: ${browser_cache_size}MB\n"
|
||
total_cache_size=$((total_cache_size + browser_cache_size))
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Check development tool caches
|
||
for user_home in /home/*; do
|
||
if [[ -d "$user_home" ]]; then
|
||
local dev_cache_size=0
|
||
|
||
# Node.js/npm cache
|
||
if [[ -d "$user_home/.npm" ]]; then
|
||
local npm_size=$(du -sm "$user_home/.npm" 2>/dev/null | cut -f1 || echo 0)
|
||
dev_cache_size=$((dev_cache_size + npm_size))
|
||
fi
|
||
|
||
# Python pip cache
|
||
if [[ -d "$user_home/.cache/pip" ]]; then
|
||
local pip_size=$(du -sm "$user_home/.cache/pip" 2>/dev/null | cut -f1 || echo 0)
|
||
dev_cache_size=$((dev_cache_size + pip_size))
|
||
fi
|
||
|
||
# VS Code cache
|
||
if [[ -d "$user_home/.vscode" ]]; then
|
||
local vscode_size=$(du -sm "$user_home/.vscode" 2>/dev/null | cut -f1 || echo 0)
|
||
dev_cache_size=$((dev_cache_size + vscode_size))
|
||
fi
|
||
|
||
if [[ $dev_cache_size -gt 0 ]]; then
|
||
cache_analysis="${cache_analysis} Development caches: ${dev_cache_size}MB\n"
|
||
total_cache_size=$((total_cache_size + dev_cache_size))
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Check KDE/Plasma caches if detected
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
for user_home in /home/*; do
|
||
if [[ -d "$user_home" ]]; then
|
||
local kde_cache_size=0
|
||
for kde_dir in ".cache/baloo" ".cache/plasma" ".cache/krunner" ".cache/thumbnails" ".cache/mesa_shader_cache"; do
|
||
if [[ -d "$user_home/$kde_dir" ]]; then
|
||
local size=$(du -sm "$user_home/$kde_dir" 2>/dev/null | cut -f1 || echo 0)
|
||
kde_cache_size=$((kde_cache_size + size))
|
||
fi
|
||
done
|
||
if [[ $kde_cache_size -gt 0 ]]; then
|
||
cache_analysis="${cache_analysis} KDE/Plasma caches: ${kde_cache_size}MB\n"
|
||
total_cache_size=$((total_cache_size + kde_cache_size))
|
||
fi
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Look for additional optimization opportunities
|
||
for user_home in /home/*; do
|
||
if [[ -d "$user_home" ]]; then
|
||
# Check for gaming caches
|
||
if [[ -d "$user_home/.steam" ]]; then
|
||
local steam_cache_size=$(du -sm "$user_home/.steam/steam/appcache" 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $steam_cache_size -gt 50 ]]; then
|
||
additional_opportunities="${additional_opportunities} Steam cache: ${steam_cache_size}MB (gaming profile recommended)\n"
|
||
fi
|
||
fi
|
||
|
||
# Check for shader caches (important for gaming/graphics)
|
||
if [[ -d "$user_home/.local/share/Steam/steamapps/shadercache" ]]; then
|
||
local shader_cache_size=$(du -sm "$user_home/.local/share/Steam/steamapps/shadercache" 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $shader_cache_size -gt 100 ]]; then
|
||
additional_opportunities="${additional_opportunities} GPU shader cache: ${shader_cache_size}MB (CRITICAL for gaming performance)\n"
|
||
fi
|
||
fi
|
||
|
||
# Check for container development caches
|
||
if [[ -d "$user_home/.docker" ]]; then
|
||
local docker_cache_size=$(du -sm "$user_home/.docker" 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $docker_cache_size -gt 100 ]]; then
|
||
additional_opportunities="${additional_opportunities} Docker cache: ${docker_cache_size}MB (development profile)\n"
|
||
fi
|
||
fi
|
||
|
||
# Check for large build caches
|
||
if [[ -d "$user_home/.gradle/caches" ]]; then
|
||
local gradle_cache_size=$(du -sm "$user_home/.gradle/caches" 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $gradle_cache_size -gt 200 ]]; then
|
||
additional_opportunities="${additional_opportunities} Gradle build cache: ${gradle_cache_size}MB (development profile)\n"
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Check system-level opportunities
|
||
if [[ -d /var/lib/flatpak ]]; then
|
||
local flatpak_size=$(du -sm /var/lib/flatpak 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $flatpak_size -gt 1000 ]]; then
|
||
additional_opportunities="${additional_opportunities} Flatpak apps: ${flatpak_size}MB (consider tmpfs for .cache)\n"
|
||
fi
|
||
fi
|
||
|
||
# Check package cache
|
||
if [[ -d /var/cache/apt ]]; then
|
||
local apt_cache_size=$(du -sm /var/cache/apt 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $apt_cache_size -gt 0 ]]; then
|
||
cache_analysis="${cache_analysis} Package cache: ${apt_cache_size}MB\n"
|
||
total_cache_size=$((total_cache_size + apt_cache_size))
|
||
fi
|
||
fi
|
||
|
||
# Check temp directories
|
||
local tmp_size=$(du -sm /tmp 2>/dev/null | cut -f1 || echo 0)
|
||
if [[ $tmp_size -gt 100 ]]; then
|
||
cache_analysis="${cache_analysis} Temp files: ${tmp_size}MB\n"
|
||
fi
|
||
|
||
if [[ $total_cache_size -gt 0 ]]; then
|
||
echo " 📊 Found cacheable data:"
|
||
echo -e "$cache_analysis"
|
||
echo " 💡 Total cache size: ${total_cache_size}MB"
|
||
|
||
# Recommend profile based on cache size and RAM
|
||
local recommended_profile="medium"
|
||
if [[ $ram_gb -ge 16 ]] && [[ $total_cache_size -gt 2000 ]]; then
|
||
recommended_profile="large"
|
||
echo " 📈 Recommended: Large profile (${ram_gb}GB RAM, ${total_cache_size}MB cache)"
|
||
elif [[ $ram_gb -le 8 ]] || [[ $total_cache_size -lt 1000 ]]; then
|
||
recommended_profile="small"
|
||
echo " 📈 Recommended: Small profile (${ram_gb}GB RAM, ${total_cache_size}MB cache)"
|
||
else
|
||
echo " 📈 Recommended: Medium profile (${ram_gb}GB RAM, ${total_cache_size}MB cache)"
|
||
fi
|
||
else
|
||
echo " 📊 No significant cache data found"
|
||
echo " 💡 tmpfs can still improve performance for future cache usage"
|
||
fi
|
||
|
||
# Check for additional opportunities regardless of current setup
|
||
if [[ -n "$additional_opportunities" ]]; then
|
||
echo ""
|
||
echo " 🎯 Additional Optimization Opportunities:"
|
||
echo -e "$additional_opportunities"
|
||
fi
|
||
|
||
# Determine if changes are needed
|
||
if [[ $tmpfs_count -gt 0 ]]; then
|
||
# Already configured - check if improvements are possible
|
||
local current_mounts=$(mount | grep "tmpfs.*tmpfs-cache" | wc -l)
|
||
local recommended_mounts=4
|
||
|
||
# Check if KDE is detected and we don't have a KDE-specific mount
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
if ! mount | grep -q "tmpfs-cache/kde"; then
|
||
recommended_mounts=5
|
||
echo " 💡 KDE environment detected - could add dedicated KDE cache mount"
|
||
fi
|
||
fi
|
||
|
||
# Check if development mount exists
|
||
if ! mount | grep -q "tmpfs-cache/development" && [[ $total_cache_size -gt 500 ]]; then
|
||
echo " 💡 Development caches detected - could add dedicated development mount"
|
||
recommended_mounts=$((recommended_mounts + 1))
|
||
fi
|
||
|
||
if [[ $current_mounts -lt $recommended_mounts ]] || [[ $total_cache_size -gt 3000 ]]; then
|
||
echo " ⚠️ Current setup could be enhanced"
|
||
needs_changes=true
|
||
read -p " Would you like to enhance your tmpfs setup? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
SETUP_TMPFS=true
|
||
else
|
||
SETUP_TMPFS=false
|
||
fi
|
||
else
|
||
echo " ✅ Current tmpfs setup is optimal for detected cache usage"
|
||
SETUP_TMPFS=false
|
||
fi
|
||
else
|
||
# Not configured at all
|
||
needs_changes=true
|
||
read -p " Would you like to set up tmpfs caches? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
SETUP_TMPFS=true
|
||
else
|
||
SETUP_TMPFS=false
|
||
fi
|
||
fi
|
||
fi # End desktop mode tmpfs check
|
||
echo ""
|
||
|
||
# === KERNEL PARAMS CHECK ===
|
||
echo "⚙️ Kernel Parameters Analysis:"
|
||
|
||
if [[ "${PROXMOX_MODE:-false}" == "true" ]]; then
|
||
# Proxmox mode: Different kernel parameters
|
||
local swappiness=$(sysctl -n vm.swappiness 2>/dev/null || echo "60")
|
||
local dirty_ratio=$(sysctl -n vm.dirty_ratio 2>/dev/null || echo "20")
|
||
local qdisc=$(sysctl -n net.core.default_qdisc 2>/dev/null || echo "pfifo_fast")
|
||
local tcp_congestion=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || echo "cubic")
|
||
|
||
echo " 📊 Current: swappiness=$swappiness, dirty_ratio=$dirty_ratio"
|
||
echo " 📊 Network: qdisc=$qdisc, tcp_congestion=$tcp_congestion"
|
||
echo " 📊 Proxmox Recommended: swappiness=10, dirty_ratio=10, qdisc=fq, tcp_congestion=bbr"
|
||
echo ""
|
||
|
||
if [[ "$swappiness" != "10" ]] || [[ "$dirty_ratio" != "10" ]] || [[ "$qdisc" != "fq" ]]; then
|
||
echo " ⚠️ Parameters could be optimized for Proxmox workload"
|
||
read -p " Apply Proxmox-optimized kernel parameters? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
TUNE_KERNEL=true
|
||
KERNEL_PROFILE="proxmox"
|
||
else
|
||
TUNE_KERNEL=false
|
||
fi
|
||
else
|
||
echo " ✅ Parameters are optimal for Proxmox"
|
||
TUNE_KERNEL=false
|
||
fi
|
||
else
|
||
# Desktop mode: Original kernel parameter logic
|
||
if [[ -f /etc/sysctl.d/99-system-optimization.conf ]]; then
|
||
local swappiness=$(sysctl -n vm.swappiness 2>/dev/null)
|
||
local dirty_ratio=$(sysctl -n vm.dirty_ratio 2>/dev/null)
|
||
echo " ✅ Configuration exists"
|
||
echo " 📊 Current: swappiness=$swappiness, dirty_ratio=$dirty_ratio"
|
||
|
||
# Check if optimal
|
||
local opt_swap=5
|
||
local opt_dirty=5
|
||
if [[ $ram_gb -ge 16 ]]; then
|
||
opt_swap=1; opt_dirty=3
|
||
elif [[ $ram_gb -le 4 ]]; then
|
||
opt_swap=10; opt_dirty=10
|
||
fi
|
||
|
||
echo " 📊 Optimal: swappiness=$opt_swap, dirty_ratio=$opt_dirty"
|
||
|
||
if [[ "$swappiness" != "$opt_swap" ]] || [[ "$dirty_ratio" != "$opt_dirty" ]]; then
|
||
echo " ⚠️ Parameters could be optimized"
|
||
needs_changes=true
|
||
read -p " Would you like to optimize kernel parameters? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
TUNE_KERNEL=true
|
||
KERNEL_PROFILE="desktop"
|
||
else
|
||
TUNE_KERNEL=false
|
||
fi
|
||
else
|
||
echo " ✅ Parameters are optimal"
|
||
TUNE_KERNEL=false
|
||
fi
|
||
else
|
||
echo " ❌ Not optimized"
|
||
needs_changes=true
|
||
read -p " Would you like to optimize kernel parameters? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
TUNE_KERNEL=true
|
||
KERNEL_PROFILE="desktop"
|
||
else
|
||
TUNE_KERNEL=false
|
||
fi
|
||
fi
|
||
fi # End desktop mode kernel check
|
||
echo ""
|
||
|
||
# === SERVICE CHECK ===
|
||
echo "🔄 Systemd Service Analysis:"
|
||
if systemctl is-enabled system-optimization.service &>/dev/null; then
|
||
echo " ✅ Service is installed and enabled"
|
||
SETUP_SERVICE=false
|
||
else
|
||
echo " ❌ Service not installed"
|
||
needs_changes=true
|
||
read -p " Would you like to install the systemd service? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
SETUP_SERVICE=true
|
||
else
|
||
SETUP_SERVICE=false
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# Summary
|
||
if [[ $needs_changes == false ]]; then
|
||
success "🎉 All optimizations are already in great shape!"
|
||
echo ""
|
||
echo "📋 Current Optimization Details:"
|
||
echo "==============================="
|
||
|
||
# Show detailed zram info
|
||
if [[ -e /dev/zram0 ]] && swapon --show | grep -q zram0; then
|
||
local zram_size=$(swapon --show | grep zram0 | awk '{print $3}')
|
||
local zram_used=$(swapon --show | grep zram0 | awk '{print $4}')
|
||
echo ""
|
||
echo "🗜️ zram Compressed Swap:"
|
||
echo " 💾 Size: $zram_size (currently using: ${zram_used:-0B})"
|
||
echo " ⚡ Purpose: Compressed swap in RAM for better performance"
|
||
echo " 📈 Benefit: ~2-4x compression ratio reduces memory pressure"
|
||
echo " 🔧 Algorithm: $(cat /sys/block/zram0/comp_algorithm 2>/dev/null | grep -o '\[.*\]' | tr -d '[]' || echo 'lz4')"
|
||
fi
|
||
|
||
# Show detailed tmpfs info
|
||
local tmpfs_count=$(mount | grep "tmpfs.*tmpfs-cache" | wc -l)
|
||
if [[ $tmpfs_count -gt 0 ]]; then
|
||
echo ""
|
||
echo "💾 tmpfs Cache System:"
|
||
echo " 📊 Active Mounts: $tmpfs_count cache filesystems in RAM"
|
||
echo ""
|
||
echo " 📁 Mount Details:"
|
||
mount | grep "tmpfs.*tmpfs-cache" | while read -r line; do
|
||
local mount_point=$(echo "$line" | awk '{print $3}')
|
||
local mount_name=$(basename "$mount_point")
|
||
local size_info=$(echo "$line" | grep -o 'size=[^,]*' | cut -d= -f2)
|
||
local df_info=$(df -h "$mount_point" 2>/dev/null | tail -1)
|
||
local used=$(echo "$df_info" | awk '{print $3}')
|
||
local use_percent=$(echo "$df_info" | awk '{print $5}')
|
||
|
||
printf " • %-12s: %8s (%s used, %s)\n" "$mount_name" "$size_info" "$used" "$use_percent"
|
||
|
||
# Explain what each mount is for
|
||
case "$mount_name" in
|
||
"browser")
|
||
echo " 📝 Purpose: Browser caches (Chrome, Firefox, etc.)"
|
||
echo " ⚡ Benefit: Faster page loading, reduced SSD wear"
|
||
;;
|
||
"ide")
|
||
echo " 📝 Purpose: IDE and editor caches (VS Code, JetBrains)"
|
||
echo " ⚡ Benefit: Faster project loading, syntax highlighting"
|
||
;;
|
||
"packages")
|
||
echo " 📝 Purpose: Package manager cache (APT, etc.)"
|
||
echo " ⚡ Benefit: Faster package operations, reduced downloads"
|
||
;;
|
||
"development")
|
||
echo " 📝 Purpose: Development tool caches (npm, pip, Docker)"
|
||
echo " ⚡ Benefit: Faster builds, dependency resolution"
|
||
;;
|
||
"kde")
|
||
echo " 📝 Purpose: KDE/Plasma desktop caches (Baloo, thumbnails)"
|
||
echo " ⚡ Benefit: Faster file indexing, desktop responsiveness"
|
||
;;
|
||
"thumbnails")
|
||
echo " 📝 Purpose: File manager thumbnail cache"
|
||
echo " ⚡ Benefit: Instant thumbnail generation"
|
||
;;
|
||
esac
|
||
echo ""
|
||
done
|
||
|
||
# Calculate total tmpfs allocation
|
||
local total_kb=0
|
||
while read -r line; do
|
||
local size_kb=$(echo "$line" | grep -o 'size=[^,]*' | cut -d= -f2 | sed 's/k$//')
|
||
total_kb=$((total_kb + size_kb))
|
||
done < <(mount | grep "tmpfs.*tmpfs-cache")
|
||
local total_mb=$((total_kb / 1024))
|
||
|
||
# Get RAM info with proper fallback and locale support
|
||
local ram_gb=$(free -g | awk '/^Mem:|^Speicher:/{print $2}')
|
||
local ram_mb=$(free -m | awk '/^Mem:|^Speicher:/{print $2}')
|
||
|
||
# Handle edge cases for RAM detection
|
||
if [[ $ram_gb -eq 0 && $ram_mb -gt 0 ]]; then
|
||
ram_gb=$((ram_mb / 1024))
|
||
[[ $ram_gb -eq 0 ]] && ram_gb=1 # Minimum 1GB for display
|
||
fi
|
||
|
||
# Calculate percentage safely
|
||
local ram_percent=0
|
||
if [[ $ram_gb -gt 0 ]]; then
|
||
ram_percent=$(( (total_mb * 100) / (ram_gb * 1024) ))
|
||
elif [[ $ram_mb -gt 0 ]]; then
|
||
ram_percent=$(( (total_mb * 100) / ram_mb ))
|
||
fi
|
||
|
||
echo " 📊 Total tmpfs allocation: ${total_mb}MB (${ram_percent}% of ${ram_gb}GB RAM)"
|
||
echo " 🚀 Performance gain: Cache operations run at RAM speed (~50-100x faster)"
|
||
echo " 💿 SSD protection: Reduces write cycles by ~60-80% for cached data"
|
||
fi
|
||
|
||
# Show kernel parameter details
|
||
if [[ -f /etc/sysctl.d/99-system-optimization.conf ]]; then
|
||
local swappiness=$(sysctl -n vm.swappiness 2>/dev/null)
|
||
local dirty_ratio=$(sysctl -n vm.dirty_ratio 2>/dev/null)
|
||
local dirty_bg_ratio=$(sysctl -n vm.dirty_background_ratio 2>/dev/null)
|
||
echo ""
|
||
echo "⚙️ Kernel Parameter Optimizations:"
|
||
echo " 🔧 vm.swappiness = $swappiness (how aggressively to use swap)"
|
||
echo " 📝 Purpose: $(if [[ $swappiness -le 5 ]]; then echo "Prefer RAM over swap for better performance"; else echo "Balanced RAM/swap usage"; fi)"
|
||
echo ""
|
||
echo " 🔧 vm.dirty_ratio = $dirty_ratio (% RAM for write cache)"
|
||
echo " 📝 Purpose: Controls when dirty pages are written to disk"
|
||
echo ""
|
||
echo " 🔧 vm.dirty_background_ratio = $dirty_bg_ratio (background write threshold)"
|
||
echo " 📝 Purpose: When background writing starts"
|
||
echo ""
|
||
|
||
# Use the ram_gb variable calculated above, or recalculate if needed
|
||
local ram_display_gb=${ram_gb:-$(free -g | awk '/^Mem:|^Speicher:/{print $2}')}
|
||
if [[ $ram_display_gb -eq 0 ]]; then
|
||
local ram_display_mb=$(free -m | awk '/^Mem:|^Speicher:/{print $2}')
|
||
ram_display_gb=$((ram_display_mb / 1024))
|
||
[[ $ram_display_gb -eq 0 ]] && ram_display_gb=1
|
||
fi
|
||
|
||
echo " ⚡ Combined benefit: Optimized memory management for your ${ram_display_gb}GB system"
|
||
fi
|
||
|
||
# Show service status
|
||
if systemctl is-enabled system-optimization.service &>/dev/null; then
|
||
echo ""
|
||
echo "🔄 Persistence Service:"
|
||
echo " ✅ system-optimization.service enabled"
|
||
echo " 📝 Purpose: Automatically recreates optimizations after reboot"
|
||
echo " 🔧 Restores: zram device, tmpfs mounts, bind mounts"
|
||
fi
|
||
|
||
echo ""
|
||
echo "💡 Quick Reference Commands:"
|
||
echo " ./tmpfs-info.sh # Detailed tmpfs status and configuration"
|
||
echo " ./quick-status-check.sh # Quick system overview"
|
||
echo " df -h /tmp/tmpfs-cache/* # Check tmpfs usage"
|
||
echo " swapon --show # Check zram status"
|
||
echo ""
|
||
|
||
# Check if applications are configured for tmpfs
|
||
local current_user=$(logname 2>/dev/null || echo $SUDO_USER)
|
||
local user_home=$(eval echo ~$current_user)
|
||
|
||
echo "📱 Application Configuration Status:"
|
||
local configured_browsers=0
|
||
local total_browsers=0
|
||
|
||
# Check each browser
|
||
if [[ -d "$user_home/.mozilla/firefox" ]]; then
|
||
total_browsers=$((total_browsers + 1))
|
||
if grep -q "tmpfs-cache" "$user_home/.mozilla/firefox"/*default*/prefs.js 2>/dev/null; then
|
||
echo " ✅ Firefox: Configured"
|
||
configured_browsers=$((configured_browsers + 1))
|
||
else
|
||
echo " ⚠️ Firefox: Not configured"
|
||
fi
|
||
fi
|
||
|
||
if [[ -d "$user_home/.config/BraveSoftware" ]]; then
|
||
total_browsers=$((total_browsers + 1))
|
||
if [[ -f "$user_home/.local/share/applications/brave-browser.desktop" ]] && \
|
||
grep -q "tmpfs-cache" "$user_home/.local/share/applications/brave-browser.desktop" 2>/dev/null; then
|
||
echo " ✅ Brave: Configured"
|
||
configured_browsers=$((configured_browsers + 1))
|
||
else
|
||
echo " ⚠️ Brave: Not configured"
|
||
fi
|
||
fi
|
||
|
||
if [[ -d "$user_home/.config/google-chrome" ]]; then
|
||
total_browsers=$((total_browsers + 1))
|
||
if [[ -f "$user_home/.local/share/applications/google-chrome.desktop" ]] && \
|
||
grep -q "tmpfs-cache" "$user_home/.local/share/applications/google-chrome.desktop" 2>/dev/null; then
|
||
echo " ✅ Chrome: Configured"
|
||
configured_browsers=$((configured_browsers + 1))
|
||
else
|
||
echo " ⚠️ Chrome: Not configured"
|
||
fi
|
||
fi
|
||
|
||
if [[ -d "$user_home/.config/chromium" ]]; then
|
||
total_browsers=$((total_browsers + 1))
|
||
if [[ -f "$user_home/.local/share/applications/chromium-browser.desktop" ]] && \
|
||
grep -q "tmpfs-cache" "$user_home/.local/share/applications/chromium-browser.desktop" 2>/dev/null; then
|
||
echo " ✅ Chromium: Configured"
|
||
configured_browsers=$((configured_browsers + 1))
|
||
else
|
||
echo " ⚠️ Chromium: Not configured"
|
||
fi
|
||
fi
|
||
|
||
# Check dev tools
|
||
local npm_configured=false
|
||
if command -v npm &>/dev/null; then
|
||
local npm_cache=$(sudo -u $current_user npm config get cache 2>/dev/null)
|
||
if [[ "$npm_cache" == *"tmpfs-cache"* ]]; then
|
||
echo " ✅ NPM: Configured"
|
||
npm_configured=true
|
||
else
|
||
echo " ⚠️ NPM: Not configured"
|
||
fi
|
||
fi
|
||
|
||
local pip_configured=false
|
||
if command -v pip3 &>/dev/null || command -v pip &>/dev/null; then
|
||
if [[ -f "$user_home/.config/pip/pip.conf" ]] && \
|
||
grep -q "tmpfs-cache" "$user_home/.config/pip/pip.conf" 2>/dev/null; then
|
||
echo " ✅ Pip: Configured"
|
||
pip_configured=true
|
||
else
|
||
echo " ⚠️ Pip: Not configured"
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
if [[ $configured_browsers -lt $total_browsers ]] || [[ $npm_configured == false ]] || [[ $pip_configured == false ]]; then
|
||
read -p " Would you like to configure/reconfigure your applications? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
echo ""
|
||
configure_applications_for_tmpfs
|
||
echo ""
|
||
success "Configuration complete! Restart your applications to use tmpfs caches."
|
||
fi
|
||
else
|
||
echo " ✅ Applications are configured to use tmpfs caches"
|
||
fi
|
||
echo ""
|
||
echo "🎯 Your system is fully optimized for maximum performance!"
|
||
exit 0
|
||
fi
|
||
|
||
# Show what will be done
|
||
local actions=()
|
||
[[ $SETUP_ZRAM == true ]] && actions+=("zram")
|
||
[[ $SETUP_TMPFS == true ]] && actions+=("tmpfs")
|
||
[[ $SETUP_KERNEL == true ]] && actions+=("kernel")
|
||
[[ $SETUP_SERVICE == true ]] && actions+=("service")
|
||
[[ $REMOVE_OVERLAYS == true ]] && actions+=("remove-overlays")
|
||
|
||
if [[ ${#actions[@]} -gt 0 ]]; then
|
||
echo "📋 Selected optimizations: ${actions[*]}"
|
||
echo ""
|
||
read -p "Proceed with these optimizations? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
log "User cancelled optimization"
|
||
exit 0
|
||
fi
|
||
else
|
||
log "No optimizations selected"
|
||
exit 0
|
||
fi
|
||
|
||
# Export variables for the optimization functions
|
||
export SETUP_ZRAM SETUP_TMPFS SETUP_KERNEL SETUP_SERVICE REMOVE_OVERLAYS
|
||
export SYSTEM_RAM_GB=$ram_gb
|
||
}
|
||
|
||
setup_zram() {
|
||
if [[ $SETUP_ZRAM != true ]]; then
|
||
return 0
|
||
fi
|
||
|
||
log "Configuring zram..."
|
||
|
||
# Calculate optimal size
|
||
local zram_size=$((SYSTEM_RAM_GB / 2))
|
||
[[ $zram_size -lt 2 ]] && zram_size=2
|
||
|
||
# Remove existing zram properly
|
||
if [[ -e /dev/zram0 ]]; then
|
||
log "Removing existing zram configuration..."
|
||
# Disable swap first
|
||
swapoff /dev/zram0 2>/dev/null || true
|
||
sleep 1
|
||
|
||
# Reset the device
|
||
echo 1 > /sys/block/zram0/reset 2>/dev/null || true
|
||
sleep 1
|
||
|
||
# Remove the device if possible
|
||
if [[ -e /sys/class/zram-control/hot_remove ]]; then
|
||
echo 0 > /sys/class/zram-control/hot_remove 2>/dev/null || true
|
||
fi
|
||
sleep 1
|
||
fi
|
||
|
||
# Unload and reload zram module for clean state
|
||
rmmod zram 2>/dev/null || true
|
||
sleep 1
|
||
|
||
# Configure new zram
|
||
log "Setting up new zram with ${zram_size}GB..."
|
||
modprobe zram num_devices=1
|
||
|
||
# Wait for device to be ready
|
||
local attempts=0
|
||
while [[ ! -e /dev/zram0 && $attempts -lt 10 ]]; do
|
||
sleep 1
|
||
((attempts++))
|
||
done
|
||
|
||
if [[ ! -e /dev/zram0 ]]; then
|
||
error "Failed to create zram device"
|
||
return 1
|
||
fi
|
||
|
||
# Configure the new device
|
||
echo "${zram_size}G" > /sys/block/zram0/disksize
|
||
mkswap /dev/zram0
|
||
swapon /dev/zram0
|
||
|
||
success "zram reconfigured with ${zram_size}GB"
|
||
}
|
||
|
||
remove_overlays() {
|
||
if [[ $REMOVE_OVERLAYS != true ]]; then
|
||
return 0
|
||
fi
|
||
|
||
log "Removing overlay filesystem mounts..."
|
||
|
||
# Get list of overlay mounts
|
||
local overlay_mounts=$(mount -t overlay | awk '{print $3}')
|
||
|
||
if [[ -z "$overlay_mounts" ]]; then
|
||
log "No overlay mounts found to remove"
|
||
return 0
|
||
fi
|
||
|
||
# Unmount each overlay
|
||
echo "$overlay_mounts" | while read -r mount_point; do
|
||
if [[ -n "$mount_point" ]]; then
|
||
log " Unmounting overlay: $mount_point"
|
||
if umount "$mount_point" 2>/dev/null; then
|
||
success " Successfully unmounted: $mount_point"
|
||
|
||
# Clean up overlay work directories if they exist in /tmp
|
||
local work_dir="/tmp/overlay-work$(basename "$mount_point")"
|
||
local upper_dir="/tmp/overlay-upper$(basename "$mount_point")"
|
||
|
||
if [[ -d "$work_dir" ]]; then
|
||
rm -rf "$work_dir"
|
||
log " Cleaned up work directory: $work_dir"
|
||
fi
|
||
|
||
if [[ -d "$upper_dir" ]]; then
|
||
rm -rf "$upper_dir"
|
||
log " Cleaned up upper directory: $upper_dir"
|
||
fi
|
||
else
|
||
warn " Failed to unmount: $mount_point (may be in use)"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Remove any overlay entries from fstab
|
||
if [[ -f /etc/fstab ]] && grep -q "overlay" /etc/fstab; then
|
||
log "Removing overlay entries from /etc/fstab..."
|
||
cp /etc/fstab /etc/fstab.backup.$(date +%s)
|
||
grep -v "overlay" /etc/fstab > /etc/fstab.tmp && mv /etc/fstab.tmp /etc/fstab
|
||
success "Removed overlay entries from /etc/fstab"
|
||
fi
|
||
|
||
success "Overlay filesystem cleanup completed"
|
||
}
|
||
|
||
setup_tmpfs() {
|
||
if [[ $SETUP_TMPFS != true ]]; then
|
||
return 0
|
||
fi
|
||
|
||
log "Setting up tmpfs cache optimization..."
|
||
|
||
# Check if Proxmox mode
|
||
if [[ "${TMPFS_PROFILE:-}" == "proxmox" ]]; then
|
||
# Proxmox minimal tmpfs: only for APT cache
|
||
mkdir -p /tmp/tmpfs-cache/apt
|
||
|
||
# Remove existing mount if it exists
|
||
if mount | grep -q "/tmp/tmpfs-cache/apt"; then
|
||
umount "/tmp/tmpfs-cache/apt" 2>/dev/null || true
|
||
fi
|
||
|
||
mount -t tmpfs -o size=2G tmpfs /tmp/tmpfs-cache/apt
|
||
|
||
# Configure APT to use tmpfs
|
||
mkdir -p /etc/apt/apt.conf.d
|
||
echo 'Dir::Cache::Archives "/tmp/tmpfs-cache/apt";' > /etc/apt/apt.conf.d/00tmpfs-cache
|
||
|
||
# Add to fstab for persistence
|
||
if ! grep -q "/tmp/tmpfs-cache/apt" /etc/fstab; then
|
||
echo "tmpfs /tmp/tmpfs-cache/apt tmpfs size=2G,mode=0755 0 0" >> /etc/fstab
|
||
fi
|
||
|
||
success "Proxmox minimal tmpfs configured (2GB for APT cache)"
|
||
return 0
|
||
fi
|
||
|
||
# Desktop mode: Full tmpfs setup
|
||
# Determine profile based on RAM
|
||
local profile="medium"
|
||
if [[ $SYSTEM_RAM_GB -ge 16 ]]; then
|
||
profile="large"
|
||
elif [[ $SYSTEM_RAM_GB -le 8 ]]; then
|
||
profile="small"
|
||
fi
|
||
|
||
# Create tmpfs directories
|
||
mkdir -p /tmp/tmpfs-cache/{browser,ide,packages,thumbnails,development,kde}
|
||
|
||
# Remove existing mounts if they exist
|
||
for dir in browser ide packages thumbnails development kde; do
|
||
if mount | grep -q "/tmp/tmpfs-cache/$dir"; then
|
||
umount "/tmp/tmpfs-cache/$dir" 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# Set up tmpfs mounts based on profile
|
||
case "$profile" in
|
||
"large")
|
||
mount -t tmpfs -o size=4G tmpfs /tmp/tmpfs-cache/browser
|
||
mount -t tmpfs -o size=2G tmpfs /tmp/tmpfs-cache/ide
|
||
mount -t tmpfs -o size=3G tmpfs /tmp/tmpfs-cache/packages
|
||
mount -t tmpfs -o size=512M tmpfs /tmp/tmpfs-cache/thumbnails
|
||
mount -t tmpfs -o size=2G tmpfs /tmp/tmpfs-cache/development
|
||
# KDE-specific cache if detected
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
mount -t tmpfs -o size=1G tmpfs /tmp/tmpfs-cache/kde
|
||
fi
|
||
;;
|
||
"medium")
|
||
mount -t tmpfs -o size=2G tmpfs /tmp/tmpfs-cache/browser
|
||
mount -t tmpfs -o size=1G tmpfs /tmp/tmpfs-cache/ide
|
||
mount -t tmpfs -o size=2G tmpfs /tmp/tmpfs-cache/packages
|
||
mount -t tmpfs -o size=256M tmpfs /tmp/tmpfs-cache/thumbnails
|
||
mount -t tmpfs -o size=1G tmpfs /tmp/tmpfs-cache/development
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
mount -t tmpfs -o size=512M tmpfs /tmp/tmpfs-cache/kde
|
||
fi
|
||
;;
|
||
"small")
|
||
mount -t tmpfs -o size=1G tmpfs /tmp/tmpfs-cache/browser
|
||
mount -t tmpfs -o size=512M tmpfs /tmp/tmpfs-cache/ide
|
||
mount -t tmpfs -o size=1G tmpfs /tmp/tmpfs-cache/packages
|
||
mount -t tmpfs -o size=128M tmpfs /tmp/tmpfs-cache/thumbnails
|
||
mount -t tmpfs -o size=512M tmpfs /tmp/tmpfs-cache/development
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
mount -t tmpfs -o size=256M tmpfs /tmp/tmpfs-cache/kde
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
# Bind mount package cache if apt is available
|
||
if [[ -d /var/cache/apt ]]; then
|
||
# Backup existing cache
|
||
if [[ ! -L /var/cache/apt ]] && [[ -d /var/cache/apt ]] && [[ ! -d /var/cache/apt.backup ]]; then
|
||
cp -a /var/cache/apt /var/cache/apt.backup
|
||
fi
|
||
|
||
# Create bind mount
|
||
mount --bind /tmp/tmpfs-cache/packages /var/cache/apt
|
||
fi
|
||
|
||
# Add fstab entries for persistence
|
||
local fstab_tmpfs="/etc/fstab.tmpfs"
|
||
local browser_size ide_size packages_size thumbnails_size development_size kde_size
|
||
|
||
case "$profile" in
|
||
"large")
|
||
browser_size="4G"
|
||
ide_size="2G"
|
||
packages_size="3G"
|
||
thumbnails_size="512M"
|
||
development_size="2G"
|
||
kde_size="1G"
|
||
;;
|
||
"medium")
|
||
browser_size="2G"
|
||
ide_size="1G"
|
||
packages_size="2G"
|
||
thumbnails_size="256M"
|
||
development_size="1G"
|
||
kde_size="512M"
|
||
;;
|
||
"small")
|
||
browser_size="1G"
|
||
ide_size="512M"
|
||
packages_size="1G"
|
||
thumbnails_size="128M"
|
||
development_size="512M"
|
||
kde_size="256M"
|
||
;;
|
||
esac
|
||
|
||
cat > "$fstab_tmpfs" << EOF
|
||
# tmpfs cache mounts - Generated $(date)
|
||
# Profile: $profile for ${SYSTEM_RAM_GB}GB RAM
|
||
tmpfs /tmp/tmpfs-cache/browser tmpfs size=${browser_size},noatime,nosuid,nodev 0 0
|
||
tmpfs /tmp/tmpfs-cache/ide tmpfs size=${ide_size},noatime,nosuid,nodev 0 0
|
||
tmpfs /tmp/tmpfs-cache/packages tmpfs size=${packages_size},noatime,nosuid,nodev 0 0
|
||
tmpfs /tmp/tmpfs-cache/thumbnails tmpfs size=${thumbnails_size},noatime,nosuid,nodev 0 0
|
||
tmpfs /tmp/tmpfs-cache/development tmpfs size=${development_size},noatime,nosuid,nodev 0 0
|
||
EOF
|
||
|
||
# Add KDE-specific mount if KDE is detected
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
echo "tmpfs /tmp/tmpfs-cache/kde tmpfs size=${kde_size},noatime,nosuid,nodev 0 0" >> "$fstab_tmpfs"
|
||
fi
|
||
|
||
success "tmpfs cache optimization enabled ($profile profile)"
|
||
|
||
# Automatically configure detected applications
|
||
configure_applications_for_tmpfs
|
||
|
||
# Show summary of what was configured
|
||
echo ""
|
||
echo "📋 tmpfs Setup Complete:"
|
||
echo "======================="
|
||
echo ""
|
||
echo "🔧 Created tmpfs mount points:"
|
||
mount | grep "tmpfs.*tmpfs-cache" | while read -r line; do
|
||
mount_point=$(echo "$line" | awk '{print $3}')
|
||
size=$(echo "$line" | grep -o 'size=[^,]*' | cut -d= -f2)
|
||
echo " 📁 $mount_point - Size: $size"
|
||
done
|
||
|
||
echo ""
|
||
echo "⚡ Performance Benefits:"
|
||
echo " • <20> Faster cache access (RAM speed vs SSD)"
|
||
echo " • 💿 Reduced SSD wear and tear"
|
||
echo " • 🧹 Automatic cleanup on reboot"
|
||
echo " • 🔋 Lower power consumption for cache operations"
|
||
}
|
||
|
||
configure_applications_for_tmpfs() {
|
||
log "Auto-configuring applications to use tmpfs caches..."
|
||
echo ""
|
||
|
||
local configured_count=0
|
||
local current_user=$(logname 2>/dev/null || echo $SUDO_USER)
|
||
local user_home=$(eval echo ~$current_user)
|
||
|
||
# Browser Configuration
|
||
echo "🌐 Configuring Browsers:"
|
||
|
||
# Firefox
|
||
for firefox_profile in "$user_home"/.mozilla/firefox/*.default* "$user_home"/.mozilla/firefox/*.default-release*; do
|
||
if [[ -d "$firefox_profile" ]]; then
|
||
local prefs_file="$firefox_profile/prefs.js"
|
||
if [[ -f "$prefs_file" ]]; then
|
||
# Backup original
|
||
cp "$prefs_file" "$prefs_file.backup.$(date +%s)" 2>/dev/null || true
|
||
|
||
# Remove old cache settings
|
||
sed -i '/browser.cache.disk.parent_directory/d' "$prefs_file" 2>/dev/null || true
|
||
|
||
# Add new cache location
|
||
echo 'user_pref("browser.cache.disk.parent_directory", "/tmp/tmpfs-cache/browser/firefox");' >> "$prefs_file"
|
||
|
||
# Create cache directory
|
||
mkdir -p /tmp/tmpfs-cache/browser/firefox
|
||
chown -R $current_user:$current_user /tmp/tmpfs-cache/browser/firefox
|
||
|
||
success " ✅ Firefox configured to use tmpfs cache"
|
||
configured_count=$((configured_count + 1))
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Brave Browser
|
||
if [[ -d "$user_home/.config/BraveSoftware" ]]; then
|
||
mkdir -p /tmp/tmpfs-cache/browser/brave
|
||
mkdir -p "$user_home/.local/share/applications"
|
||
chown -R $current_user:$current_user /tmp/tmpfs-cache/browser/brave
|
||
|
||
local brave_desktop="$user_home/.local/share/applications/brave-browser.desktop"
|
||
cat > "$brave_desktop" << 'BRAVEEOF'
|
||
[Desktop Entry]
|
||
Version=1.0
|
||
Name=Brave Browser (tmpfs optimized)
|
||
Exec=brave-browser --disk-cache-dir=/tmp/tmpfs-cache/browser/brave %U
|
||
StartupNotify=true
|
||
Terminal=false
|
||
Icon=brave-browser
|
||
Type=Application
|
||
Categories=Network;WebBrowser;
|
||
MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;
|
||
BRAVEEOF
|
||
chown $current_user:$current_user "$brave_desktop" 2>/dev/null || true
|
||
chmod +x "$brave_desktop" 2>/dev/null || true
|
||
success " ✅ Brave Browser configured to use tmpfs cache"
|
||
configured_count=$((configured_count + 1))
|
||
fi
|
||
|
||
# Google Chrome
|
||
if [[ -d "$user_home/.config/google-chrome" ]]; then
|
||
mkdir -p /tmp/tmpfs-cache/browser/google-chrome
|
||
mkdir -p "$user_home/.local/share/applications"
|
||
chown -R $current_user:$current_user /tmp/tmpfs-cache/browser/google-chrome
|
||
|
||
local chrome_desktop="$user_home/.local/share/applications/google-chrome.desktop"
|
||
cat > "$chrome_desktop" << 'CHROMEOF'
|
||
[Desktop Entry]
|
||
Version=1.0
|
||
Name=Google Chrome (tmpfs optimized)
|
||
Exec=google-chrome --disk-cache-dir=/tmp/tmpfs-cache/browser/google-chrome %U
|
||
StartupNotify=true
|
||
Terminal=false
|
||
Icon=google-chrome
|
||
Type=Application
|
||
Categories=Network;WebBrowser;
|
||
MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;
|
||
CHROMEOF
|
||
chown $current_user:$current_user "$chrome_desktop" 2>/dev/null || true
|
||
chmod +x "$chrome_desktop" 2>/dev/null || true
|
||
success " ✅ Google Chrome configured to use tmpfs cache"
|
||
configured_count=$((configured_count + 1))
|
||
fi
|
||
|
||
# Chromium
|
||
if [[ -d "$user_home/.config/chromium" ]]; then
|
||
mkdir -p /tmp/tmpfs-cache/browser/chromium
|
||
mkdir -p "$user_home/.local/share/applications"
|
||
chown -R $current_user:$current_user /tmp/tmpfs-cache/browser/chromium
|
||
|
||
local chromium_desktop="$user_home/.local/share/applications/chromium-browser.desktop"
|
||
cat > "$chromium_desktop" << 'CHROMIUMEOF'
|
||
[Desktop Entry]
|
||
Version=1.0
|
||
Name=Chromium (tmpfs optimized)
|
||
Exec=chromium --disk-cache-dir=/tmp/tmpfs-cache/browser/chromium %U
|
||
StartupNotify=true
|
||
Terminal=false
|
||
Icon=chromium
|
||
Type=Application
|
||
Categories=Network;WebBrowser;
|
||
MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;
|
||
CHROMIUMEOF
|
||
chown $current_user:$current_user "$chromium_desktop" 2>/dev/null || true
|
||
chmod +x "$chromium_desktop" 2>/dev/null || true
|
||
success " ✅ Chromium configured to use tmpfs cache"
|
||
configured_count=$((configured_count + 1))
|
||
fi
|
||
|
||
# Development Tools Configuration
|
||
echo ""
|
||
echo "💻 Configuring Development Tools:"
|
||
|
||
# NPM
|
||
if command -v npm &>/dev/null; then
|
||
sudo -u $current_user npm config set cache /tmp/tmpfs-cache/development/npm 2>/dev/null && \
|
||
success " ✅ NPM cache configured" && configured_count=$((configured_count + 1))
|
||
fi
|
||
|
||
# Pip
|
||
if command -v pip3 &>/dev/null || command -v pip &>/dev/null; then
|
||
mkdir -p "$user_home/.config/pip"
|
||
cat > "$user_home/.config/pip/pip.conf" << 'PIPEOF'
|
||
[global]
|
||
cache-dir = /tmp/tmpfs-cache/development/pip
|
||
PIPEOF
|
||
chown $current_user:$current_user "$user_home/.config/pip/pip.conf" 2>/dev/null || true
|
||
success " ✅ Pip cache configured" && configured_count=$((configured_count + 1))
|
||
fi
|
||
|
||
# KDE/Plasma Configuration
|
||
if [[ "$XDG_CURRENT_DESKTOP" == *"KDE"* ]] || [[ "$DESKTOP_SESSION" == *"plasma"* ]]; then
|
||
echo ""
|
||
echo "🖥️ Configuring KDE/Plasma:"
|
||
|
||
# Link thumbnails
|
||
if [[ -d "$user_home/.cache/thumbnails" ]]; then
|
||
mv "$user_home/.cache/thumbnails" "$user_home/.cache/thumbnails.backup.$(date +%s)" 2>/dev/null || true
|
||
fi
|
||
mkdir -p /tmp/tmpfs-cache/kde/thumbnails
|
||
ln -sf /tmp/tmpfs-cache/kde/thumbnails "$user_home/.cache/thumbnails"
|
||
chown -R $current_user:$current_user /tmp/tmpfs-cache/kde/thumbnails
|
||
success " ✅ KDE thumbnail cache linked to tmpfs"
|
||
configured_count=$((configured_count + 1))
|
||
fi
|
||
|
||
echo ""
|
||
if [[ $configured_count -gt 0 ]]; then
|
||
success "🎉 Automatically configured $configured_count applications!"
|
||
echo ""
|
||
log "💡 Changes will take effect when you restart the configured applications"
|
||
else
|
||
log "ℹ️ No applications detected for automatic configuration"
|
||
echo " You can manually configure other applications to use:"
|
||
echo " • Browser cache: /tmp/tmpfs-cache/browser/"
|
||
echo " • Dev tools: /tmp/tmpfs-cache/development/"
|
||
echo " • IDE cache: /tmp/tmpfs-cache/ide/"
|
||
fi
|
||
}
|
||
|
||
tune_kernel() {
|
||
if [[ ${TUNE_KERNEL:-false} != true ]]; then
|
||
return 0
|
||
fi
|
||
|
||
log "Optimizing kernel parameters..."
|
||
|
||
local sysctl_conf="/etc/sysctl.d/99-system-optimization.conf"
|
||
|
||
# Determine optimal values based on mode
|
||
local swappiness=5
|
||
local dirty_ratio=5
|
||
local profile="desktop"
|
||
|
||
if [[ "${KERNEL_PROFILE:-desktop}" == "proxmox" ]]; then
|
||
# Proxmox-specific parameters
|
||
swappiness=10
|
||
dirty_ratio=10
|
||
profile="proxmox-host"
|
||
|
||
cat > "$sysctl_conf" << EOF
|
||
# Proxmox Host Optimization - Generated $(date)
|
||
# Profile: $profile for ${SYSTEM_RAM_GB}GB RAM
|
||
|
||
# Memory management (for hypervisor workload)
|
||
vm.swappiness = $swappiness
|
||
vm.dirty_ratio = $dirty_ratio
|
||
vm.dirty_background_ratio = 5
|
||
vm.vfs_cache_pressure = 50
|
||
vm.min_free_kbytes = 67584
|
||
|
||
# Networking (for VM/CT traffic)
|
||
net.core.default_qdisc = fq
|
||
net.ipv4.tcp_congestion_control = bbr
|
||
net.core.netdev_max_backlog = 5000
|
||
net.ipv4.tcp_max_syn_backlog = 8192
|
||
net.core.rmem_max = 16777216
|
||
net.core.wmem_max = 16777216
|
||
|
||
# File system
|
||
fs.file-max = 2097152
|
||
fs.inotify.max_user_watches = 524288
|
||
|
||
# Kernel
|
||
kernel.panic = 10
|
||
kernel.panic_on_oops = 1
|
||
EOF
|
||
else
|
||
# Desktop-specific parameters
|
||
if [[ $SYSTEM_RAM_GB -ge 16 ]]; then
|
||
swappiness=1
|
||
dirty_ratio=3
|
||
profile="high-memory-desktop"
|
||
elif [[ $SYSTEM_RAM_GB -le 4 ]]; then
|
||
swappiness=10
|
||
dirty_ratio=10
|
||
profile="low-memory-desktop"
|
||
fi
|
||
|
||
cat > "$sysctl_conf" << EOF
|
||
# Desktop System Optimization - Generated $(date)
|
||
# Profile: $profile for ${SYSTEM_RAM_GB}GB RAM
|
||
|
||
# Memory management
|
||
vm.swappiness = $swappiness
|
||
vm.dirty_ratio = $dirty_ratio
|
||
vm.dirty_background_ratio = $((dirty_ratio / 2))
|
||
vm.vfs_cache_pressure = 50
|
||
|
||
# Network optimizations
|
||
net.core.rmem_max = 16777216
|
||
net.core.wmem_max = 16777216
|
||
|
||
# General performance
|
||
kernel.sched_autogroup_enabled = 1
|
||
EOF
|
||
fi
|
||
|
||
# Apply immediately
|
||
sysctl -p "$sysctl_conf"
|
||
success "Kernel parameters optimized ($profile profile)"
|
||
}
|
||
|
||
optimize_cpu_governor() {
|
||
if [[ "${PROXMOX_MODE:-false}" != "true" ]]; then
|
||
return 0
|
||
fi
|
||
|
||
log "Optimizing CPU governor for Proxmox..."
|
||
|
||
# Check current governor
|
||
local current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null || echo "unknown")
|
||
|
||
if [[ "$current_governor" == "performance" ]]; then
|
||
success "CPU governor already set to 'performance'"
|
||
return 0
|
||
fi
|
||
|
||
if [[ "$current_governor" == "unknown" ]]; then
|
||
warn "CPU frequency scaling not available on this system"
|
||
return 0
|
||
fi
|
||
|
||
# Install cpufrequtils if needed
|
||
if ! command -v cpufreq-set &>/dev/null; then
|
||
log "Installing cpufrequtils..."
|
||
apt-get update -qq
|
||
apt-get install -y cpufrequtils >/dev/null 2>&1
|
||
fi
|
||
|
||
# Set governor to performance
|
||
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
|
||
if [[ -f "$cpu/cpufreq/scaling_governor" ]]; then
|
||
echo "performance" > "$cpu/cpufreq/scaling_governor" 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# Make persistent
|
||
cat > /etc/default/cpufrequtils << 'EOF'
|
||
# CPU governor for Proxmox host
|
||
GOVERNOR="performance"
|
||
EOF
|
||
|
||
success "CPU governor set to 'performance' (full speed for VMs)"
|
||
}
|
||
|
||
optimize_zfs_arc() {
|
||
if [[ "${PROXMOX_MODE:-false}" != "true" ]]; then
|
||
return 0
|
||
fi
|
||
|
||
# Check if ZFS is present
|
||
if ! command -v zpool &>/dev/null || ! zpool list &>/dev/null 2>&1; then
|
||
return 0
|
||
fi
|
||
|
||
log "Optimizing ZFS ARC limit..."
|
||
|
||
local ram_gb=$(free -g | awk '/^Mem:|^Speicher:/{print $2}')
|
||
local current_arc=$(cat /sys/module/zfs/parameters/zfs_arc_max 2>/dev/null || echo "0")
|
||
local current_arc_gb=$((current_arc / 1024 / 1024 / 1024))
|
||
local recommended_arc=$((ram_gb / 4)) # 25% of RAM
|
||
|
||
if [[ $current_arc_gb -le $recommended_arc ]] && [[ $current_arc_gb -gt 0 ]]; then
|
||
success "ZFS ARC already limited to ${current_arc_gb}GB (good for VMs)"
|
||
return 0
|
||
fi
|
||
|
||
local arc_bytes=$((recommended_arc * 1024 * 1024 * 1024))
|
||
|
||
# Set immediately
|
||
echo "$arc_bytes" > /sys/module/zfs/parameters/zfs_arc_max 2>/dev/null || true
|
||
|
||
# Make persistent
|
||
mkdir -p /etc/modprobe.d
|
||
if ! grep -q "zfs_arc_max" /etc/modprobe.d/zfs.conf 2>/dev/null; then
|
||
echo "options zfs zfs_arc_max=$arc_bytes" >> /etc/modprobe.d/zfs.conf
|
||
else
|
||
sed -i "s/zfs_arc_max=[0-9]*/zfs_arc_max=$arc_bytes/" /etc/modprobe.d/zfs.conf
|
||
fi
|
||
|
||
# Update initramfs
|
||
update-initramfs -u -k all >/dev/null 2>&1 || true
|
||
|
||
success "ZFS ARC limited to ${recommended_arc}GB (frees RAM for VMs)"
|
||
}
|
||
|
||
create_service() {
|
||
if [[ $SETUP_SERVICE != true ]]; then
|
||
return 0
|
||
fi
|
||
|
||
log "Creating systemd service..."
|
||
|
||
# Create startup script
|
||
cat > /usr/local/bin/system-optimization-startup.sh << 'EOF'
|
||
#!/bin/bash
|
||
# Recreate optimizations after reboot
|
||
|
||
# Ensure zram if not present
|
||
if [[ ! -e /dev/zram0 ]]; then
|
||
ram_gb=$(free -g | awk '/^Mem:|^Speicher:/{print $2}')
|
||
zram_size=$((ram_gb / 2))
|
||
[[ $zram_size -lt 2 ]] && zram_size=2
|
||
|
||
modprobe zram num_devices=1 2>/dev/null || true
|
||
if [[ -e /sys/block/zram0/disksize ]]; then
|
||
echo "${zram_size}G" > /sys/block/zram0/disksize
|
||
mkswap /dev/zram0
|
||
swapon /dev/zram0
|
||
fi
|
||
fi
|
||
|
||
# Recreate tmpfs mounts if configured
|
||
if [[ -f /etc/fstab.tmpfs ]]; then
|
||
# Create directories
|
||
mkdir -p /tmp/tmpfs-cache/{browser,ide,packages,thumbnails,development,kde}
|
||
|
||
# Mount tmpfs filesystems
|
||
while IFS= read -r line; do
|
||
if [[ $line =~ ^tmpfs ]]; then
|
||
# Parse the fstab line and mount
|
||
eval "mount $line" 2>/dev/null || true
|
||
fi
|
||
done < /etc/fstab.tmpfs
|
||
|
||
# Restore package cache bind mount
|
||
if [[ -d /var/cache/apt ]] && [[ -d /tmp/tmpfs-cache/packages ]]; then
|
||
mount --bind /tmp/tmpfs-cache/packages /var/cache/apt 2>/dev/null || true
|
||
fi
|
||
fi
|
||
EOF
|
||
|
||
chmod +x /usr/local/bin/system-optimization-startup.sh
|
||
|
||
# Create systemd service
|
||
cat > /etc/systemd/system/system-optimization.service << EOF
|
||
[Unit]
|
||
Description=System Performance Optimization
|
||
After=multi-user.target
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
ExecStart=/usr/local/bin/system-optimization-startup.sh
|
||
RemainAfterExit=yes
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
systemctl daemon-reload
|
||
systemctl enable system-optimization.service
|
||
|
||
success "Systemd service created and enabled"
|
||
}
|
||
|
||
show_final_status() {
|
||
echo ""
|
||
echo "🎉 Optimization Complete!"
|
||
echo "========================"
|
||
echo ""
|
||
|
||
# Show current status with more details
|
||
echo "📊 Current Optimization Status:"
|
||
|
||
# zram with usage info
|
||
if [[ -e /dev/zram0 ]] && swapon --show | grep -q zram0; then
|
||
local zram_size=$(swapon --show | grep zram0 | awk '{print $3}')
|
||
local zram_used=$(swapon --show | grep zram0 | awk '{print $4}')
|
||
echo " 🗜️ zram: $zram_size (used: ${zram_used:-0B})"
|
||
fi
|
||
|
||
# tmpfs with detailed mount info
|
||
local tmpfs_count=$(mount | grep "tmpfs.*tmpfs-cache" | wc -l)
|
||
echo " 💾 tmpfs: $tmpfs_count cache mounts active"
|
||
if [[ $tmpfs_count -gt 0 ]]; then
|
||
local total_tmpfs_size=0
|
||
echo " 📁 Active mounts:"
|
||
mount | grep "tmpfs.*tmpfs-cache" | while read -r line; do
|
||
local mount_point=$(echo "$line" | awk '{print $3}' | sed 's|/tmp/tmpfs-cache/||')
|
||
local size_kb=$(echo "$line" | grep -o 'size=[^,]*' | cut -d= -f2 | sed 's/k$//')
|
||
local size_mb=$((size_kb / 1024))
|
||
local usage=$(df "$line" 2>/dev/null | tail -1 | awk '{print $5}' || echo "0%")
|
||
printf " • %-12s: %4dMB (%s used)\n" "$mount_point" "$size_mb" "$usage"
|
||
done
|
||
|
||
# Calculate total allocated tmpfs space
|
||
local total_kb=0
|
||
while read -r line; do
|
||
local size_kb=$(echo "$line" | grep -o 'size=[^,]*' | cut -d= -f2 | sed 's/k$//')
|
||
total_kb=$((total_kb + size_kb))
|
||
done < <(mount | grep "tmpfs.*tmpfs-cache")
|
||
local total_mb=$((total_kb / 1024))
|
||
echo " 📊 Total tmpfs allocated: ${total_mb}MB"
|
||
fi
|
||
|
||
# overlay status
|
||
local overlay_count=$(mount -t overlay | wc -l)
|
||
if [[ $overlay_count -eq 0 ]]; then
|
||
echo " 🗂️ overlays: None (optimal for desktop systems)"
|
||
else
|
||
echo " ⚠️ overlays: $overlay_count mounts found (consider removal)"
|
||
fi
|
||
|
||
# kernel with current values
|
||
if [[ -f /etc/sysctl.d/99-system-optimization.conf ]]; then
|
||
local swappiness=$(sysctl -n vm.swappiness 2>/dev/null)
|
||
local dirty_ratio=$(sysctl -n vm.dirty_ratio 2>/dev/null)
|
||
echo " ⚙️ kernel: swappiness=$swappiness, dirty_ratio=$dirty_ratio"
|
||
fi
|
||
|
||
# service status
|
||
if systemctl is-enabled system-optimization.service &>/dev/null; then
|
||
echo " 🔄 service: enabled (will restore tmpfs on reboot)"
|
||
fi
|
||
|
||
echo ""
|
||
echo "🎯 Next Steps:"
|
||
echo " 1. 🔄 Restart configured applications (browsers, IDEs) to use new cache locations"
|
||
echo " 2. 📊 Monitor cache usage: df -h | grep tmpfs-cache"
|
||
echo " 3. 🔍 Check status anytime: ./quick-status-check.sh"
|
||
echo " 4. <20> Optional: Reboot to verify all optimizations persist"
|
||
echo ""
|
||
echo "💡 Useful Commands:"
|
||
echo " • Check tmpfs usage: df -h /tmp/tmpfs-cache/*"
|
||
echo " • Monitor performance: iotop -ao"
|
||
echo " • View mount details: mount | grep tmpfs-cache"
|
||
echo ""
|
||
echo "🔧 Changes applied successfully!"
|
||
if [[ $tmpfs_count -gt 0 ]]; then
|
||
# Calculate total tmpfs space for the final message
|
||
local final_total_kb=0
|
||
while read -r line; do
|
||
local size_kb=$(echo "$line" | grep -o 'size=[^,]*' | cut -d= -f2 | sed 's/k$//')
|
||
final_total_kb=$((final_total_kb + size_kb))
|
||
done < <(mount | grep "tmpfs.*tmpfs-cache")
|
||
local final_total_mb=$((final_total_kb / 1024))
|
||
echo "🚀 Your system now has ${final_total_mb}MB of high-speed cache storage in RAM!"
|
||
fi
|
||
}
|
||
|
||
main() {
|
||
echo "🚀 Interactive System Optimizer"
|
||
echo "==============================="
|
||
echo ""
|
||
|
||
check_root
|
||
check_proxmox
|
||
|
||
# Setup directories
|
||
mkdir -p "$(dirname "$LOG_FILE")" "$BACKUP_DIR"
|
||
touch "$LOG_FILE" 2>/dev/null || true
|
||
|
||
# Analyze and get user input
|
||
analyze_and_prompt
|
||
|
||
# Apply selected optimizations
|
||
remove_overlays
|
||
setup_zram
|
||
setup_tmpfs
|
||
tune_kernel
|
||
|
||
# Proxmox-specific optimizations
|
||
optimize_cpu_governor
|
||
optimize_zfs_arc
|
||
|
||
create_service
|
||
|
||
# Show results
|
||
show_final_status
|
||
|
||
log "Optimization completed successfully"
|
||
}
|
||
|
||
main "$@" |