#!/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_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" echo "" # Check and prompt for each optimization local needs_changes=false # === ZRAM CHECK === 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 echo "" # === TMPFS CHECK === echo "💾 tmpfs Cache System Analysis:" # Get unique mount points to avoid counting duplicates local unique_mounts=$(mount | grep "tmpfs.*tmpfs-cache" | awk '{print $3}' | sort -u || true) local unique_count=0 local total_count=$(mount | grep "tmpfs.*tmpfs-cache" | wc -l) # Count unique mounts properly if [[ -n "$unique_mounts" ]]; then unique_count=$(echo "$unique_mounts" | wc -l) fi if [[ $unique_count -gt 0 ]]; then # Check for duplicates if [[ $total_count -gt $unique_count ]]; then echo " ⚠️ Found $total_count mounts but only $unique_count unique paths (duplicates detected!)" echo " 📁 Unique mounted caches:" echo "$unique_mounts" | head -3 | while read mount_point; do options=$(mount | grep "tmpfs.*tmpfs-cache" | grep " $mount_point " | head -1 | awk '{print $6}' | tr -d '()') echo " $mount_point ($options)" done [[ $unique_count -gt 3 ]] && echo " ... and $((unique_count - 3)) more" echo " 💡 Recommendation: Clean up duplicates first" read -p " Would you like to clean up duplicate mounts? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then SETUP_TMPFS=true # Will cleanup and recreate properly else SETUP_TMPFS=false fi else echo " ✅ Well configured ($unique_count active mounts)" echo " 📁 Some mounted caches:" echo "$unique_mounts" | head -3 | while read mount_point; do options=$(mount | grep "tmpfs.*tmpfs-cache" | grep " $mount_point " | head -1 | awk '{print $6}' | tr -d '()') echo " $mount_point ($options)" done [[ $unique_count -gt 3 ]] && echo " ... and $((unique_count - 3)) more" SETUP_TMPFS=false fi else echo " ❌ Not configured" 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 echo "" # === KERNEL PARAMS CHECK === echo "⚙️ Kernel Parameters Analysis:" 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 SETUP_KERNEL=true else SETUP_KERNEL=false fi else echo " ✅ Parameters are optimal" SETUP_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 SETUP_KERNEL=true else SETUP_KERNEL=false fi fi 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!" 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") 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 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" } setup_tmpfs() { if [[ $SETUP_TMPFS != true ]]; then return 0 fi log "Setting up tmpfs cache optimizations..." # Clean up any existing duplicate mounts first log "Cleaning up any existing tmpfs-cache mounts..." # Get list of mount points to unmount local mount_points_file="/tmp/tmpfs_mounts_to_remove.$$" mount | grep "tmpfs.*tmpfs-cache" | awk '{print $3}' | sort -u > "$mount_points_file" || true if [[ -s "$mount_points_file" ]]; then while IFS= read -r mount_point; do if mountpoint -q "$mount_point"; then log " Unmounting existing: $mount_point" umount "$mount_point" 2>/dev/null || warn " Failed to unmount $mount_point" fi done < "$mount_points_file" fi rm -f "$mount_points_file" # Remove and recreate the base directory if [[ -d /tmp/tmpfs-cache ]]; then rm -rf /tmp/tmpfs-cache fi # Load usage analysis module if available local modules_dir="$(dirname "$0")/modules" if [[ -f "$modules_dir/usage-analysis.sh" ]]; then source "$modules_dir/usage-analysis.sh" fi # Create tmpfs cache directory structure mkdir -p /tmp/tmpfs-cache/{browser,ide,packages,thumbnails,node_modules,python_cache} # Determine sizes based on available RAM local browser_size="1G" local ide_size="512M" local packages_size="1G" local thumbnails_size="256M" if [[ $SYSTEM_RAM_GB -ge 16 ]]; then browser_size="4G" ide_size="2G" packages_size="3G" thumbnails_size="512M" elif [[ $SYSTEM_RAM_GB -ge 8 ]]; then browser_size="2G" ide_size="1G" packages_size="2G" thumbnails_size="256M" fi log "Creating tmpfs mounts (${browser_size} browser, ${ide_size} IDE, ${packages_size} packages)..." # Mount tmpfs filesystems (only if not already mounted) for mount_info in \ "browser:$browser_size" \ "ide:$ide_size" \ "packages:$packages_size" \ "thumbnails:$thumbnails_size"; do local mount_name=$(echo "$mount_info" | cut -d: -f1) local mount_size=$(echo "$mount_info" | cut -d: -f2) local mount_path="/tmp/tmpfs-cache/$mount_name" if ! mountpoint -q "$mount_path"; then mount -t tmpfs -o size="$mount_size" tmpfs "$mount_path" log " Created: $mount_path ($mount_size)" else log " Already mounted: $mount_path" fi done # Scan for and setup cache directories that would benefit from tmpfs scan_and_setup_cache_dirs success "tmpfs cache system configured (total: ~$((${browser_size%G} + ${ide_size%G} + ${packages_size%G}))GB)" } scan_and_setup_cache_dirs() { log "Scanning for folders/software that would benefit from tmpfs..." local found_optimizations=false # Browser caches log "Checking browser installations..." # Firefox cache find /home -path "*/.mozilla/firefox/*/storage" -type d 2>/dev/null | while read firefox_dir; do local profile_dir=$(dirname "$firefox_dir") local cache_dir="$profile_dir/storage" if [[ -d "$cache_dir" ]]; then local size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1) log " Found Firefox cache: $cache_dir ($size)" # Create symlink to tmpfs location local tmpfs_target="/tmp/tmpfs-cache/browser/firefox-$(basename "$profile_dir")" mkdir -p "$tmpfs_target" if [[ ! -L "$cache_dir" ]]; then mv "$cache_dir" "${cache_dir}.bak" 2>/dev/null || true ln -sf "$tmpfs_target" "$cache_dir" found_optimizations=true fi fi done # Chrome/Chromium cache find /home -path "*/.config/google-chrome/*/storage" -o -path "*/.config/chromium/*/storage" -type d 2>/dev/null | while read chrome_dir; do if [[ -d "$chrome_dir" ]]; then local size=$(du -sh "$chrome_dir" 2>/dev/null | cut -f1) local browser_type=$(echo "$chrome_dir" | grep -o -E "(google-chrome|chromium)") log " Found $browser_type cache: $chrome_dir ($size)" # Create symlink to tmpfs location local profile_name=$(basename "$(dirname "$chrome_dir")") local tmpfs_target="/tmp/tmpfs-cache/browser/${browser_type}-${profile_name}" mkdir -p "$tmpfs_target" if [[ ! -L "$chrome_dir" ]]; then mv "$chrome_dir" "${chrome_dir}.bak" 2>/dev/null || true ln -sf "$tmpfs_target" "$chrome_dir" found_optimizations=true fi fi done # IDE caches log "Checking IDE installations..." # VS Code cache find /home -path "*/.config/Code/CachedData" -type d 2>/dev/null | while read vscode_cache; do if [[ -d "$vscode_cache" ]]; then local size=$(du -sh "$vscode_cache" 2>/dev/null | cut -f1) log " Found VS Code cache: $vscode_cache ($size)" local tmpfs_target="/tmp/tmpfs-cache/ide/vscode-cache" mkdir -p "$tmpfs_target" if [[ ! -L "$vscode_cache" ]]; then mv "$vscode_cache" "${vscode_cache}.bak" 2>/dev/null || true ln -sf "$tmpfs_target" "$vscode_cache" found_optimizations=true fi fi done # VS Code extensions find /home -path "*/.vscode/extensions" -type d 2>/dev/null | while read vscode_ext; do if [[ -d "$vscode_ext" ]]; then local size=$(du -sh "$vscode_ext" 2>/dev/null | cut -f1) log " Found VS Code extensions: $vscode_ext ($size)" # Note: Extensions are better left on disk, but we can cache their temp files fi done # Package manager caches log "Checking package manager caches..." # APT cache if [[ -d /var/cache/apt ]]; then local size=$(du -sh /var/cache/apt 2>/dev/null | cut -f1) log " Found APT cache: /var/cache/apt ($size)" if ! mountpoint -q /var/cache/apt; then mount --bind /tmp/tmpfs-cache/packages /var/cache/apt found_optimizations=true fi fi # Thumbnail caches find /home -path "*/.cache/thumbnails" -type d 2>/dev/null | while read thumb_dir; do if [[ -d "$thumb_dir" ]]; then local size=$(du -sh "$thumb_dir" 2>/dev/null | cut -f1) log " Found thumbnail cache: $thumb_dir ($size)" local user=$(echo "$thumb_dir" | cut -d'/' -f3) local tmpfs_target="/tmp/tmpfs-cache/thumbnails/${user}" mkdir -p "$tmpfs_target" if [[ ! -L "$thumb_dir" ]]; then mv "$thumb_dir" "${thumb_dir}.bak" 2>/dev/null || true ln -sf "$tmpfs_target" "$thumb_dir" found_optimizations=true fi fi done # Node.js node_modules (for developers) if [[ $SYSTEM_RAM_GB -ge 8 ]]; then find /home -name "node_modules" -type d -path "*/workspace/*" -o -path "*/projects/*" -o -path "*/dev/*" 2>/dev/null | head -5 | while read node_dir; do if [[ -d "$node_dir" ]]; then local size=$(du -sh "$node_dir" 2>/dev/null | cut -f1) log " Found large node_modules: $node_dir ($size)" # Note: These are better optimized with project-specific solutions fi done fi if [[ $found_optimizations == true ]]; then success "Successfully optimized cache directories for tmpfs usage" else log "No additional cache directories found that need optimization" fi } tune_kernel() { if [[ $SETUP_KERNEL != true ]]; then return 0 fi log "Optimizing kernel parameters..." local sysctl_conf="/etc/sysctl.d/99-system-optimization.conf" # Determine optimal values local swappiness=5 local dirty_ratio=5 local profile="desktop" if [[ $SYSTEM_RAM_GB -ge 16 ]]; then swappiness=1 dirty_ratio=3 profile="high-memory" elif [[ $SYSTEM_RAM_GB -le 4 ]]; then swappiness=10 dirty_ratio=10 profile="low-memory" fi cat > "$sysctl_conf" << EOF # 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 # Apply immediately sysctl -p "$sysctl_conf" success "Kernel parameters optimized ($profile profile)" } 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 log() { echo "[$(date '+%H:%M:%S')] $1" | systemd-cat -t system-optimization } log "Starting system optimizations..." # 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 log "Configured zram swap: ${zram_size}G" fi fi # Recreate tmpfs cache directories if [[ ! -d /tmp/tmpfs-cache ]]; then ram_gb=$(free -g | awk '/^Mem:|^Speicher:/{print $2}') # Determine sizes based on RAM if [[ $ram_gb -ge 16 ]]; then browser_size="4G" ide_size="2G" packages_size="3G" thumbnails_size="512M" elif [[ $ram_gb -ge 8 ]]; then browser_size="2G" ide_size="1G" packages_size="2G" thumbnails_size="256M" else browser_size="1G" ide_size="512M" packages_size="1G" thumbnails_size="256M" fi # Create and mount tmpfs directories mkdir -p /tmp/tmpfs-cache/{browser,ide,packages,thumbnails} mount -t tmpfs -o size="$browser_size" tmpfs /tmp/tmpfs-cache/browser mount -t tmpfs -o size="$ide_size" tmpfs /tmp/tmpfs-cache/ide mount -t tmpfs -o size="$packages_size" tmpfs /tmp/tmpfs-cache/packages mount -t tmpfs -o size="$thumbnails_size" tmpfs /tmp/tmpfs-cache/thumbnails # Bind mount package cache if it exists if [[ -d /var/cache/apt ]]; then mount --bind /tmp/tmpfs-cache/packages /var/cache/apt fi log "Recreated tmpfs cache system (${browser_size} browser, ${ide_size} IDE, ${packages_size} packages)" fi log "System optimizations applied successfully" 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 echo "📊 Current Status:" # zram if [[ -e /dev/zram0 ]] && swapon --show | grep -q zram0; then local zram_size=$(swapon --show | grep zram0 | awk '{print $3}') echo " 🗜️ zram: $zram_size" fi # tmpfs local unique_mounts=$(mount | grep "tmpfs.*tmpfs-cache" | awk '{print $3}' | sort -u) local unique_count=$(echo "$unique_mounts" | grep -c "." || echo "0") local total_count=$(mount | grep "tmpfs.*tmpfs-cache" | wc -l) if [[ $unique_count -gt 0 ]]; then if [[ $total_count -gt $unique_count ]]; then echo " 💾 tmpfs: $unique_count unique mounts (⚠️ $total_count total - duplicates detected)" else echo " 💾 tmpfs: $unique_count cache mounts" fi echo "$unique_mounts" | head -3 | while read mount_point; do local size=$(mount | grep "tmpfs.*tmpfs-cache" | grep " $mount_point " | head -1 | grep -o 'size=[^,)]*' | cut -d= -f2 || echo "unknown") echo " └─ $mount_point ($size)" done [[ $unique_count -gt 3 ]] && echo " └─ ... and $((unique_count - 3)) more" else echo " 💾 tmpfs: not configured" fi # kernel if [[ -f /etc/sysctl.d/99-system-optimization.conf ]]; then local swappiness=$(sysctl -n vm.swappiness 2>/dev/null) echo " ⚙️ kernel: swappiness=$swappiness" fi # service if systemctl is-enabled system-optimization.service &>/dev/null; then echo " 🔄 service: enabled" fi echo "" echo "🔧 Changes applied successfully!" echo "🔄 Reboot recommended for optimal performance" } main() { echo "🚀 Interactive System Optimizer" echo "===============================" echo "" check_root # 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 setup_zram setup_tmpfs tune_kernel create_service # Show results show_final_status log "Optimization completed successfully" } main "$@"