#!/usr/bin/env bash
# php-fpm-autocalculation script — Calculates average memory per process and PM values based on the actual Hardware CPU core count and RAM usage + %10 RAM buffer.
# Make sure your php-fpm service is running in your server before executing this script.

set -euo pipefail

# 1) Detect php-fpm process name via ps
set +e
PF_NAME=$(ps axc | grep -Eo 'php-fpm[0-9]+\.[0-9]+' | head -n1)
PF_STATUS=$?
set -e
if [[ -z $PF_NAME || PF_STATUS -ne 0 ]]; then
  echo "Error: could not find php-fpm process via ps axc" >&2
  exit 1
fi

# 2) Compute average RSS per process (KB → MB)
set +e
AVG_RSS_KB=$(ps --no-headers -o rss -C "$PF_NAME" | awk '{ sum+=$1; count++ } END { print (count>0 ? int(sum/count) : 0) }')
RSS_STATUS=$?
set -e
if (( RSS_STATUS != 0 || AVG_RSS_KB < 1 )); then
  echo "Error: no php-fpm workers found for $PF_NAME" >&2
  exit 1
fi
AVG_PROC_MB=$(( AVG_RSS_KB / 1024 ))

# 3) Gather system resources
RESERVE_MB=1024
TOTAL_RAM_MB=$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo)
CPU_CORES=$(nproc)
BUFFER=$(( TOTAL_RAM_MB / 10 ))
USABLE_MB=$(( TOTAL_RAM_MB - RESERVE_MB - BUFFER ))
(( USABLE_MB < AVG_PROC_MB )) && echo "Warning: usable RAM (${USABLE_MB}MB) < avg proc (${AVG_PROC_MB}MB)" >&2

# 4) Calculate pm.* values
MAX_CHILDREN=$(( USABLE_MB / AVG_PROC_MB ))
(( MAX_CHILDREN < 1 )) && MAX_CHILDREN=1
PM_MIN_SPARE=$CPU_CORES
PM_MAX_SPARE=$(( CPU_CORES * 2 ))
# Initial start_servers: 75% of CPU cores
START_SERVERS=$(( CPU_CORES * 3 / 4 ))
# Clamp start_servers between min_spare and max_spare
if (( START_SERVERS < PM_MIN_SPARE )); then
  START_SERVERS=$PM_MIN_SPARE
elif (( START_SERVERS > PM_MAX_SPARE )); then
  START_SERVERS=$PM_MAX_SPARE
fi

# 5) Print configuration snippets
cat <<EOF
; ------------------- PHP-FPM tuning --------------------
; Detected process       : $PF_NAME
; Avg memory per process : ${AVG_PROC_MB} MB

; ====== Dynamic mode (Balanced, variable traffic) ======
pm = dynamic
pm.max_children         = $MAX_CHILDREN
pm.start_servers        = $START_SERVERS
pm.min_spare_servers    = $PM_MIN_SPARE
pm.max_spare_servers    = $PM_MAX_SPARE

; Offers a balance between resource efficiency
: and responsiveness, adapting to varying traffic
; levels.

; ======= Ondemand mode (Efficient, low traffic) ========
pm = ondemand
pm.max_children         = $MAX_CHILDREN
pm.process_idle_timeout = 10s

; Highly resource-efficient, as processes are
; only active when needed, minimizing memory
; consumption for low-traffic sites.

; ======= Static mode (Performance, high traffic) =======
pm = static
pm.max_children         = $MAX_CHILDREN

; Provides the fastest response times as
; processes are always ready to handle requests,
; but can consume more memory, recommended for 
; high-traffic sites.
EOF
