#!/usr/bin/env bash # KNELPerf day/night resource profile engine. # # Broken out of ultix staged/ukrrs-daynight.sh (2026-09-06, #826) and # redesigned: slice names, devices, and all numeric knobs are CONF-driven # (no host-specific hardcoding); slice targets are a list so any host can # run it. Runtime-only changes (set-property --runtime + sysctl + readahead): # a reboot always lands safely in day mode, because slice unit files carry # the day defaults (unchanged ultix invariant). # # Usage: knelperf-daynight.sh [--conf FILE] day|night set -euo pipefail CONF=${KNELPERF_DAYNIGHT_CONF:-/etc/knelperf/daynight.conf} while [ $# -gt 0 ]; do case "$1" in --conf) CONF=$2; shift 2 ;; day|night) MODE=$1; shift ;; *) echo "usage: $0 [--conf FILE] day|night" >&2; exit 2 ;; esac done [ "${MODE:-}" ] || { echo "usage: $0 [--conf FILE] day|night" >&2; exit 2; } [ -r "$CONF" ] && . "$CONF" # Targets: "slice:CPUWeight:AllowedCPUs:MemoryHigh" per mode, space-separated. # Empty fields mean "skip that property". See knelperf-daynight.conf.example. : "${DAY_SLICES:=}"; : "${NIGHT_SLICES:=}" # Block devices for readahead tuning (space-separated; partitions auto-appended). : "${BLOCK_DEVS:=}" : "${DATA_RA_DAY:=256}"; : "${DATA_RA_NIGHT:=2048}" : "${DIRTY_DAY:=1073741824}"; : "${DIRTY_NIGHT:=2147483648}" : "${DIRTY_BG_DAY:=268435456}"; : "${DIRTY_BG_NIGHT:=536870912}" log() { echo "[knelperf-daynight] $*"; } ra=$DATA_RA_DAY; dirty=$DIRTY_DAY; dirtybg=$DIRTY_BG_DAY; slices=$DAY_SLICES [ "$MODE" = night ] && { ra=$DATA_RA_NIGHT; dirty=$DIRTY_NIGHT; dirtybg=$DIRTY_BG_NIGHT; slices=$NIGHT_SLICES; } apply_slice() { # "slice:weight:cpus:memhigh" local spec=$1 slice weight cpus memhigh IFS=: read -r slice weight cpus memhigh <<< "$spec" [ -n "$slice" ] || return 0 local -a props=() [ -n "$weight" ] && props+=(CPUWeight="$weight") [ -n "$cpus" ] && props+=(AllowedCPUs="$cpus") [ -n "$memhigh" ] && props+=(MemoryHigh="$memhigh") if [ ${#props[@]} -gt 0 ]; then systemctl set-property --runtime "$slice" "${props[@]}" \ || log "WARN: set-property failed for $slice (slice not loaded?)" fi } for spec in $slices; do apply_slice "$spec"; done if [ -n "$BLOCK_DEVS" ]; then for dev in $BLOCK_DEVS; do blockdev --setra "$ra" "$dev" 2>/dev/null || log "readahead skip: $dev" for part in "${dev}"[0-9]*; do if [ -e "$part" ]; then blockdev --setra "$ra" "$part" 2>/dev/null || true; fi done done fi sysctl -q -w vm.dirty_bytes="$dirty" vm.dirty_background_bytes="$dirtybg" log "profile $MODE applied $(date -Is)"