# Shared Pi CPU layout for EtherGold + DyzineFrame (source this file; do not exec).
#
# Raspberry Pi 5 (4× A76) default lanes:
#   CPU0  OS / housekeeping leftovers (+ shared with DF)
#   CPU1  Network plane (eth / gretap / WG softirq preference) (+ DF)
#   CPU2  DyzineFrame prefer / shared render pool
#   CPU3  EtherGold exclusive (uartd + bridge Python)
#
# Fireworks/render needs multiple cores — DF is NOT limited to a single core.
# Default DF set is all cores except EG (0-2). Override OHD_CPU_DF_SET if needed.
# Override any OHD_CPU_* or set OHD_CPU_ENABLE=0 to disable pinning.
# Requires nproc >= 4 and `taskset` for process pinning.

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  echo "FATAL: source cpu_layout.sh (do not execute)" >&2
  exit 1
fi

OHD_CPU_ENABLE="${OHD_CPU_ENABLE:-1}"
OHD_CPU_OS="${OHD_CPU_OS:-0}"
OHD_CPU_NET="${OHD_CPU_NET:-1}"
# Prefer core (docs/RPS labels) — not exclusive for DF since EG 3.0.2.14.
OHD_CPU_DF="${OHD_CPU_DF:-2}"
OHD_CPU_EG="${OHD_CPU_EG:-3}"
# taskset -c list for DyzineFrame (must keep EG core free for hard-RT copper).
OHD_CPU_DF_SET="${OHD_CPU_DF_SET:-0-2}"

ohd_cpu_count() {
  nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1
}

# True when default 4-lane policy is safe to apply.
ohd_cpu_lanes_ok() {
  [[ "${OHD_CPU_ENABLE}" == "1" ]] || return 1
  local n
  n="$(ohd_cpu_count)"
  [[ "${n}" -ge 4 ]] || return 1
  return 0
}

ohd_have_taskset() {
  command -v taskset >/dev/null 2>&1
}

# Run a command pinned to the EG lane (background: ends with & outside).
ohd_eg_run() {
  if ohd_cpu_lanes_ok && ohd_have_taskset; then
    taskset -c "${OHD_CPU_EG}" "$@"
  else
    "$@"
  fi
}

# exec replacement pinned to EG lane.
ohd_eg_exec() {
  if ohd_cpu_lanes_ok && ohd_have_taskset; then
    exec taskset -c "${OHD_CPU_EG}" "$@"
  else
    exec "$@"
  fi
}

# DyzineFrame: multi-core set excluding EG (default 0-2).
ohd_df_exec() {
  if ohd_cpu_lanes_ok && ohd_have_taskset; then
    exec taskset -c "${OHD_CPU_DF_SET}" "$@"
  else
    exec "$@"
  fi
}

ohd_df_run() {
  if ohd_cpu_lanes_ok && ohd_have_taskset; then
    taskset -c "${OHD_CPU_DF_SET}" "$@"
  else
    "$@"
  fi
}

# Bitmask hex string for a single CPU id (for rps_cpus / smp_affinity files).
ohd_cpu_bitmask_hex() {
  local core="$1"
  # shellcheck disable=SC2003
  printf '%x' "$((1 << core))"
}
