Files
linux_system_tuning/one-button-optimizer.sh
mindesbunister 03153f2380 Add application configuration prompt for already-optimized systems
- Add check for application configuration when system is already optimized
- Prompt user to configure apps even if tmpfs mounts already exist
- Create standalone configure-apps-for-tmpfs.sh script
- Detect if applications are already configured (Firefox prefs check)
- Skip redundant configuration attempts with 'already configured' messages
- Add backup timestamp to avoid overwriting previous backups
- Update README with new configuration script

Benefits:
- Users with existing tmpfs can now configure applications
- Standalone script allows re-configuration without full optimizer run
- Smarter detection prevents duplicate configurations
- Better user experience for incremental optimization
2025-10-06 09:28:59 +02:00

1250 lines
48 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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:"
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
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!"
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 already configured for tmpfs
local current_user=$(logname 2>/dev/null || echo $SUDO_USER)
local user_home=$(eval echo ~$current_user)
local apps_configured=false
# Quick check if browsers are configured
if [[ -f "$user_home/.mozilla/firefox"/*default*/prefs.js ]] && \
grep -q "tmpfs-cache" "$user_home/.mozilla/firefox"/*default*/prefs.js 2>/dev/null; then
apps_configured=true
fi
if [[ ! $apps_configured ]]; then
echo "📱 Application Configuration:"
echo " ⚠️ Your applications are not yet configured to use tmpfs caches"
echo ""
read -p " Would you like to automatically configure your browsers and dev tools? (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..."
# 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++))
fi
fi
done
# Chrome/Chromium
if command -v google-chrome &>/dev/null || command -v chromium &>/dev/null; then
local chrome_dir="$user_home/.config/google-chrome"
local chromium_dir="$user_home/.config/chromium"
for browser_dir in "$chrome_dir" "$chromium_dir"; do
if [[ -d "$browser_dir" ]]; then
local browser_name=$(basename "$browser_dir")
mkdir -p /tmp/tmpfs-cache/browser/$browser_name
# Create wrapper script to launch with cache dir
local desktop_file=""
if [[ "$browser_name" == "google-chrome" ]]; then
desktop_file="$user_home/.local/share/applications/google-chrome.desktop"
cat > "$desktop_file" << '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
else
desktop_file="$user_home/.local/share/applications/chromium.desktop"
cat > "$desktop_file" << '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
fi
chown $current_user:$current_user "$desktop_file" 2>/dev/null || true
chmod +x "$desktop_file" 2>/dev/null || true
success "$browser_name configured to use tmpfs cache"
((configured_count++))
fi
done
fi
# Brave
if [[ -d "$user_home/.config/BraveSoftware" ]]; then
mkdir -p /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 configured to use tmpfs cache"
((configured_count++))
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++))
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++))
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++))
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 [[ $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
# 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
# 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
create_service
# Show results
show_final_status
log "Optimization completed successfully"
}
main "$@"