Initial release: z13Profiler GUI for unified memory on GZ302.
Adds zenity profile picker (gaming / LLM / reset) with safe RAM guardrails, pkexec-based apply, and install.sh for Nobara/Fedora. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
*.tar.gz
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# z13Profiler
|
||||||
|
|
||||||
|
GUI profile switcher for **ROG Flow Z13 (GZ302)** unified memory on **Nobara / Fedora**.
|
||||||
|
|
||||||
|
Repository: [git.hisora.dev/Dawnsorrow/z13Profiler](https://git.hisora.dev/Dawnsorrow/z13Profiler)
|
||||||
|
|
||||||
|
Switches between:
|
||||||
|
|
||||||
|
| Profile | Fixed VRAM (carveout) | Dynamic GPU pool (TTM) |
|
||||||
|
|---------|----------------------|-------------------------|
|
||||||
|
| **Gaming** | 8 GB | Kernel default (removes custom TTM) |
|
||||||
|
| **LLM / AI** | 512 MB (minimum available) | 48 GB |
|
||||||
|
| **Reset** | 4 GB (ASUS default) | Kernel default |
|
||||||
|
|
||||||
|
All changes require a **reboot**. The GUI warns and confirms before applying.
|
||||||
|
|
||||||
|
## Quick install (Z13 / Nobara)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.hisora.dev/Dawnsorrow/z13Profiler.git
|
||||||
|
cd z13Profiler
|
||||||
|
./install.sh
|
||||||
|
z13-memory-profiles
|
||||||
|
```
|
||||||
|
|
||||||
|
One-liner (clone + install):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.hisora.dev/Dawnsorrow/z13Profiler.git /tmp/z13Profiler && /tmp/z13Profiler/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependencies (install first if missing):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y git zenity python3 polkit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update from git
|
||||||
|
|
||||||
|
If installed from this repo, pull and re-run the installer:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/z13Profiler # or wherever you cloned
|
||||||
|
git pull
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or update the installed copy directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/.local/share/z13-memory-profiles
|
||||||
|
git pull
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- ROG Flow Z13 2025 (GZ302), 64 GB RAM (defaults in `config/profiles.conf`)
|
||||||
|
- Nobara / Fedora with `zenity`, `python3`, `polkit` (`pkexec`)
|
||||||
|
- Root via `pkexec` when applying profiles
|
||||||
|
|
||||||
|
Optional: `pipx install amd-debug-tools` for standalone `amd-ttm` CLI.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
**GUI (Application menu → “Z13 Memory Profiles”, or terminal):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
z13-memory-profiles
|
||||||
|
# alias after install:
|
||||||
|
z13profiler
|
||||||
|
```
|
||||||
|
|
||||||
|
**Check current settings:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
z13-memory-profiles --status
|
||||||
|
```
|
||||||
|
|
||||||
|
**Apply from terminal (reboot manually after):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo z13-memory-profiles --apply gaming
|
||||||
|
sudo z13-memory-profiles --apply llm
|
||||||
|
sudo z13-memory-profiles --apply reset
|
||||||
|
```
|
||||||
|
|
||||||
|
## Safeguards
|
||||||
|
|
||||||
|
- Refuses profiles that would leave less than **8 GB** for the OS (configurable).
|
||||||
|
- Warns if TTM exceeds **90%** of installed RAM.
|
||||||
|
- Only writes `/etc/modprobe.d/ttm.conf` and UMA sysfs index (no random kernel hacks).
|
||||||
|
- Uses `pkexec` for privileged operations from the GUI.
|
||||||
|
|
||||||
|
## If fixed VRAM (carveout) does not change
|
||||||
|
|
||||||
|
Some setups do not expose `/sys/class/drm/card0/device/uma/` yet. The tool still adjusts TTM for LLM mode. For gaming VRAM:
|
||||||
|
|
||||||
|
1. Boot **Windows** once → **Armoury Crate → System Settings → Free up memory** → set **8 GB** → reboot.
|
||||||
|
2. Or update Nobara/kernel and re-check `z13-memory-profiles --status`.
|
||||||
|
|
||||||
|
## Customizing for your RAM size
|
||||||
|
|
||||||
|
Edit `~/.local/share/z13-memory-profiles/config/profiles.conf` after install:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[llm]
|
||||||
|
ttm_gb=48 # lower on 32 GB systems (e.g. 24)
|
||||||
|
min_os_reserve_gb=8
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -f ~/.local/bin/z13-memory-profiles ~/.local/bin/z13profiler
|
||||||
|
rm -rf ~/.local/share/z13-memory-profiles
|
||||||
|
rm -f ~/.local/share/applications/z13-memory-profiles.desktop
|
||||||
|
sudo rm -f /etc/modprobe.d/ttm.conf
|
||||||
|
sudo dracut --force --regenerate-all 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reboot.
|
||||||
|
|
||||||
|
## Build tarball (optional)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./package.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates `z13Profiler-1.0.0.tar.gz` in the parent directory for USB transfer.
|
||||||
Executable
+163
@@ -0,0 +1,163 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Z13 Memory Profiles — GUI picker for unified RAM (GZ302 / Nobara)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
INSTALL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
export INSTALL_ROOT CONFIG_FILE="${INSTALL_ROOT}/config/profiles.conf"
|
||||||
|
|
||||||
|
# shellcheck source=../lib/memory-profiles.sh
|
||||||
|
source "${INSTALL_ROOT}/lib/memory-profiles.sh"
|
||||||
|
|
||||||
|
SELF="${INSTALL_ROOT}/bin/$(basename "$0")"
|
||||||
|
|
||||||
|
die_gui() {
|
||||||
|
zenity --error --width=420 --title="Z13 Memory Profiles" --text="$1" 2>/dev/null || {
|
||||||
|
echo "ERROR: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
need_zenity() {
|
||||||
|
command -v zenity >/dev/null 2>&1 || die_gui "zenity is required.\n\nInstall: sudo dnf install zenity"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_privileged() {
|
||||||
|
if [[ "${EUID}" -eq 0 ]]; then
|
||||||
|
"$@"
|
||||||
|
elif command -v pkexec >/dev/null 2>&1; then
|
||||||
|
pkexec "$@"
|
||||||
|
else
|
||||||
|
die_gui "pkexec not found.\n\nInstall: sudo dnf install polkit\nOr run: sudo ${SELF} --apply <profile>"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_summary() {
|
||||||
|
local profile="$1"
|
||||||
|
local label desc carveout ttm_action ttm_gb
|
||||||
|
label="$(read_profile_value "${profile}" label)"
|
||||||
|
desc="$(read_profile_value "${profile}" description)"
|
||||||
|
carveout="$(read_profile_value "${profile}" carveout_target_mb)"
|
||||||
|
ttm_action="$(read_profile_value "${profile}" ttm_action)"
|
||||||
|
ttm_gb="$(read_profile_value "${profile}" ttm_gb)"
|
||||||
|
|
||||||
|
local ttm_text
|
||||||
|
if [[ "${ttm_action}" == "clear" ]]; then
|
||||||
|
ttm_text="default (clear custom TTM)"
|
||||||
|
else
|
||||||
|
ttm_text="${ttm_gb} GB dynamic"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n\n%s\n\nFixed VRAM target: %s MB\nDynamic GPU pool: %s\n\nRequires reboot.' \
|
||||||
|
"${label}" "${desc}" "${carveout}" "${ttm_text}"
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_main() {
|
||||||
|
need_zenity
|
||||||
|
|
||||||
|
local total_gb uma_note
|
||||||
|
total_gb="$(total_ram_gb)"
|
||||||
|
if find_uma_base >/dev/null 2>&1; then
|
||||||
|
uma_note="UMA sysfs: available"
|
||||||
|
else
|
||||||
|
uma_note="UMA sysfs: not found — fixed VRAM may need Windows Armoury Crate"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local choice
|
||||||
|
choice="$(zenity --list --title="Z13 Memory Profiles" --width=520 --height=360 \
|
||||||
|
--text="ROG Flow Z13 unified memory (~${total_gb} GB RAM)\n${uma_note}\n\nPick a profile (reboot required):" \
|
||||||
|
--column="Profile" --column="Use case" \
|
||||||
|
"gaming" "Gaming — 8 GB fixed VRAM, default dynamic pool" \
|
||||||
|
"llm" "LLM / AI — min fixed VRAM, 48 GB dynamic pool" \
|
||||||
|
"reset" "Reset — 4 GB fixed VRAM, default dynamic pool" \
|
||||||
|
"status" "Show current settings (no changes)" \
|
||||||
|
"discover" "Print full status to terminal" \
|
||||||
|
2>/dev/null)" || exit 0
|
||||||
|
|
||||||
|
case "${choice}" in
|
||||||
|
status)
|
||||||
|
local info
|
||||||
|
info="$(show_status 2>&1)"
|
||||||
|
zenity --text-info --title="Z13 Memory Status" --width=620 --height=480 --font=monospace <<<"${info}"
|
||||||
|
gui_main
|
||||||
|
;;
|
||||||
|
discover)
|
||||||
|
xterm -e "bash -lc '${SELF} --status; echo; read -p \"Press Enter...\"'" 2>/dev/null \
|
||||||
|
|| konsole -e bash -lc "${SELF} --status; read -p 'Press Enter...'" 2>/dev/null \
|
||||||
|
|| {
|
||||||
|
show_status
|
||||||
|
read -r -p "Press Enter..."
|
||||||
|
}
|
||||||
|
gui_main
|
||||||
|
;;
|
||||||
|
gaming|llm|reset)
|
||||||
|
local summary confirm
|
||||||
|
summary="$(profile_summary "${choice}")"
|
||||||
|
if ! validate_msg="$(validate_profile "${choice}" 2>&1)"; then
|
||||||
|
die_gui "${validate_msg}\n\nEdit ${CONFIG_FILE} if your RAM size differs."
|
||||||
|
fi
|
||||||
|
confirm="$(zenity --question --title="Confirm reboot" --width=480 \
|
||||||
|
--text="${summary}\n\nApply this profile and reboot now?" \
|
||||||
|
--ok-label="Apply & Reboot" --cancel-label="Cancel" 2>/dev/null && echo yes || echo no)"
|
||||||
|
[[ "${confirm}" == "yes" ]] || exit 0
|
||||||
|
|
||||||
|
local tmpout
|
||||||
|
tmpout="$(mktemp)"
|
||||||
|
if ! run_privileged "${SELF}" --apply "${choice}" >"${tmpout}" 2>&1; then
|
||||||
|
die_gui "Failed to apply profile:\n\n$(cat "${tmpout}")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
zenity --info --title="Rebooting" --width=420 \
|
||||||
|
--text="Profile applied.\n\n$(cat "${tmpout}")\n\nRebooting in 5 seconds..." 2>/dev/null || true
|
||||||
|
sleep 5
|
||||||
|
run_privileged systemctl reboot
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $(basename "$0") [OPTIONS]
|
||||||
|
|
||||||
|
(no args) Open zenity profile picker
|
||||||
|
--gui Same as no args
|
||||||
|
--status Print current memory settings
|
||||||
|
--discover Alias for --status
|
||||||
|
--apply PROFILE Apply gaming|llm|reset (root/pkexec)
|
||||||
|
--validate PROFILE Check profile fits this machine
|
||||||
|
-h, --help Show help
|
||||||
|
|
||||||
|
Install: ${INSTALL_ROOT}/install.sh
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
case "${1:-}" in
|
||||||
|
""|--gui)
|
||||||
|
gui_main
|
||||||
|
;;
|
||||||
|
--status|--discover)
|
||||||
|
show_status
|
||||||
|
;;
|
||||||
|
--apply)
|
||||||
|
[[ -n "${2:-}" ]] || { echo "Missing profile name" >&2; exit 1; }
|
||||||
|
apply_profile "$2"
|
||||||
|
;;
|
||||||
|
--validate)
|
||||||
|
[[ -n "${2:-}" ]] || { echo "Missing profile name" >&2; exit 1; }
|
||||||
|
validate_profile "$2"
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Z13 Memory Profiles — defaults for 64 GB ROG Flow Z13 (GZ302)
|
||||||
|
# Edit after running: z13-memory-profiles --discover
|
||||||
|
#
|
||||||
|
# carveout_target_mb: fixed GPU reservation (what many games read as "VRAM")
|
||||||
|
# ttm_gb: dynamic GPU pool (LLM / compute). Empty or "clear" removes custom TTM.
|
||||||
|
# min_os_reserve_gb: refuse settings that leave less than this for the OS
|
||||||
|
|
||||||
|
[gaming]
|
||||||
|
label=Gaming
|
||||||
|
description=8 GB fixed VRAM for game compatibility. Clears custom TTM (kernel default ~half RAM).
|
||||||
|
carveout_target_mb=8192
|
||||||
|
ttm_action=clear
|
||||||
|
min_os_reserve_gb=8
|
||||||
|
|
||||||
|
[llm]
|
||||||
|
label=LLM / AI
|
||||||
|
description=Minimum fixed VRAM + 48 GB dynamic GPU pool for local models.
|
||||||
|
carveout_target_mb=512
|
||||||
|
ttm_gb=48
|
||||||
|
min_os_reserve_gb=8
|
||||||
|
|
||||||
|
[reset]
|
||||||
|
label=Reset to defaults
|
||||||
|
description=4 GB fixed VRAM (ASUS default) and default TTM settings.
|
||||||
|
carveout_target_mb=4096
|
||||||
|
ttm_action=clear
|
||||||
|
min_os_reserve_gb=8
|
||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Install Z13 Memory Profiles for the current user
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PREFIX="${PREFIX:-${HOME}/.local}"
|
||||||
|
INSTALL_DIR="${PREFIX}/share/z13-memory-profiles"
|
||||||
|
BIN_DIR="${PREFIX}/bin"
|
||||||
|
APP_DIR="${PREFIX}/share/applications"
|
||||||
|
|
||||||
|
echo "==> z13Profiler installer"
|
||||||
|
echo " Source: ${SRC_DIR}"
|
||||||
|
echo " Target: ${INSTALL_DIR}"
|
||||||
|
|
||||||
|
missing=()
|
||||||
|
for cmd in zenity python3; do
|
||||||
|
command -v "${cmd}" >/dev/null 2>&1 || missing+=("${cmd}")
|
||||||
|
done
|
||||||
|
|
||||||
|
if ((${#missing[@]})); then
|
||||||
|
echo "Missing dependencies: ${missing[*]}"
|
||||||
|
echo "Install with: sudo dnf install ${missing[*]} polkit"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v pkexec >/dev/null 2>&1; then
|
||||||
|
echo "Note: pkexec not found — GUI apply will fall back to sudo."
|
||||||
|
echo " Recommended: sudo dnf install polkit"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${INSTALL_DIR}" "${BIN_DIR}" "${APP_DIR}"
|
||||||
|
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude='.git' \
|
||||||
|
--exclude='*.tar.gz' \
|
||||||
|
--exclude='package.sh' \
|
||||||
|
"${SRC_DIR}/" "${INSTALL_DIR}/"
|
||||||
|
|
||||||
|
chmod +x "${INSTALL_DIR}/bin/z13-memory-profiles"
|
||||||
|
chmod +x "${INSTALL_DIR}/install.sh" 2>/dev/null || true
|
||||||
|
|
||||||
|
ln -sf "${INSTALL_DIR}/bin/z13-memory-profiles" "${BIN_DIR}/z13-memory-profiles"
|
||||||
|
ln -sf "${INSTALL_DIR}/bin/z13-memory-profiles" "${BIN_DIR}/z13profiler"
|
||||||
|
|
||||||
|
cat > "${APP_DIR}/z13-memory-profiles.desktop" <<EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Type=Application
|
||||||
|
Name=Z13 Memory Profiles
|
||||||
|
GenericName=Unified Memory Settings
|
||||||
|
Comment=Switch gaming and LLM RAM profiles on ROG Flow Z13 (GZ302)
|
||||||
|
Exec=${BIN_DIR}/z13-memory-profiles
|
||||||
|
Icon=preferences-system-memory
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;Settings;
|
||||||
|
Keywords=VRAM;UMA;TTM;memory;Strix;Halo;GZ302;
|
||||||
|
StartupNotify=true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Installed."
|
||||||
|
echo " Command: z13-memory-profiles (alias: z13profiler)"
|
||||||
|
echo " Menu: Z13 Memory Profiles"
|
||||||
|
echo ""
|
||||||
|
echo "Optional (recommended for LLM): pipx install amd-debug-tools"
|
||||||
|
echo ""
|
||||||
|
echo "First run:"
|
||||||
|
echo " z13-memory-profiles --status"
|
||||||
|
echo " z13-memory-profiles"
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
# shellcheck shell=bash
|
||||||
|
# Z13 unified memory profile helpers (GZ302 / Strix Halo)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
INSTALL_ROOT="${INSTALL_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
||||||
|
CONFIG_FILE="${CONFIG_FILE:-${INSTALL_ROOT}/config/profiles.conf}"
|
||||||
|
TTM_CONF="/etc/modprobe.d/ttm.conf"
|
||||||
|
TTM_PARAM="/sys/module/ttm/parameters/pages_limit"
|
||||||
|
MAX_TTM_PERCENT=90
|
||||||
|
|
||||||
|
log() { printf '[z13-mem] %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
require_root() {
|
||||||
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
|
echo "Root required. Re-run with pkexec or sudo." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
total_ram_mb() {
|
||||||
|
awk '/^MemTotal:/ { printf "%d\n", $2 / 1024 }' /proc/meminfo
|
||||||
|
}
|
||||||
|
|
||||||
|
total_ram_gb() {
|
||||||
|
awk '/^MemTotal:/ { printf "%.1f\n", $2 / 1024 / 1024 }' /proc/meminfo
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_to_pages() {
|
||||||
|
python3 -c "print(int(float('${1}') * (1024 ** 3) / 4096))"
|
||||||
|
}
|
||||||
|
|
||||||
|
pages_to_gb() {
|
||||||
|
python3 -c "print(f'{int(${1}) * 4096 / (1024 ** 3):.2f}')"
|
||||||
|
}
|
||||||
|
|
||||||
|
find_uma_base() {
|
||||||
|
local card
|
||||||
|
for card in /sys/class/drm/card*/device; do
|
||||||
|
[[ -d "${card}/uma" ]] || continue
|
||||||
|
if [[ -r "${card}/uma/carveout_options" ]]; then
|
||||||
|
echo "${card}/uma"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_carveout_options() {
|
||||||
|
local uma_base="$1"
|
||||||
|
cat "${uma_base}/carveout_options"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pick carveout index closest to target_mb without exceeding max_mb (when set).
|
||||||
|
find_carveout_index() {
|
||||||
|
local uma_base="$1" target_mb="$2" max_mb="${3:-}"
|
||||||
|
python3 - "${uma_base}/carveout_options" "${target_mb}" "${max_mb}" <<'PY'
|
||||||
|
import re, sys
|
||||||
|
path, target_s, max_s = sys.argv[1:4]
|
||||||
|
target = float(target_s)
|
||||||
|
max_mb = float(max_s) if max_s else None
|
||||||
|
options = []
|
||||||
|
with open(path, encoding="utf-8", errors="replace") as f:
|
||||||
|
for line in f:
|
||||||
|
m = re.match(r"\s*(\d+):\s*(.*)$", line.strip())
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
idx, rest = int(m.group(1)), m.group(2).lower()
|
||||||
|
mb = None
|
||||||
|
g = re.search(r"(\d+(?:\.\d+)?)\s*gb", rest)
|
||||||
|
if g:
|
||||||
|
mb = float(g.group(1)) * 1024
|
||||||
|
else:
|
||||||
|
m2 = re.search(r"(\d+(?:\.\d+)?)\s*mb", rest)
|
||||||
|
if m2:
|
||||||
|
mb = float(m2.group(1))
|
||||||
|
if mb is None:
|
||||||
|
continue
|
||||||
|
if max_mb is not None and mb > max_mb:
|
||||||
|
continue
|
||||||
|
options.append((idx, mb, line.strip()))
|
||||||
|
if not options:
|
||||||
|
sys.exit(1)
|
||||||
|
# Prefer smallest option >= target; else largest below target.
|
||||||
|
at_or_above = [o for o in options if o[1] >= target - 0.5]
|
||||||
|
if at_or_above:
|
||||||
|
best = min(at_or_above, key=lambda o: o[1])
|
||||||
|
else:
|
||||||
|
best = max(options, key=lambda o: o[1])
|
||||||
|
print(best[0])
|
||||||
|
print(best[2])
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
read_profile_value() {
|
||||||
|
local section="$1" key="$2"
|
||||||
|
awk -v section="[$section]" -v key="$key" '
|
||||||
|
$0 == section { found=1; next }
|
||||||
|
/^\[/ { found=0 }
|
||||||
|
found && $0 ~ "^[[:space:]]*" key "=" {
|
||||||
|
sub(/^[^=]*=/, "")
|
||||||
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "")
|
||||||
|
print
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
' "${CONFIG_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
current_ttm_gb() {
|
||||||
|
if [[ ! -r "${TTM_PARAM}" ]]; then
|
||||||
|
echo "unknown"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
pages_to_gb "$(cat "${TTM_PARAM}")"
|
||||||
|
}
|
||||||
|
|
||||||
|
current_carveout_info() {
|
||||||
|
local uma_base
|
||||||
|
if ! uma_base="$(find_uma_base)"; then
|
||||||
|
echo "UMA sysfs: not available"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "Current index: $(cat "${uma_base}/carveout")"
|
||||||
|
echo "Options:"
|
||||||
|
parse_carveout_options "${uma_base}"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_profile() {
|
||||||
|
local profile="$1"
|
||||||
|
local carveout_mb ttm_action ttm_gb min_reserve total_mb total_gb max_ttm_gb
|
||||||
|
|
||||||
|
carveout_mb="$(read_profile_value "${profile}" carveout_target_mb)"
|
||||||
|
ttm_action="$(read_profile_value "${profile}" ttm_action)"
|
||||||
|
ttm_gb="$(read_profile_value "${profile}" ttm_gb)"
|
||||||
|
min_reserve="$(read_profile_value "${profile}" min_os_reserve_gb)"
|
||||||
|
|
||||||
|
[[ -n "${carveout_mb}" ]] || { echo "Missing carveout_target_mb for ${profile}"; return 1; }
|
||||||
|
|
||||||
|
total_mb="$(total_ram_mb)"
|
||||||
|
total_gb="$(total_ram_gb)"
|
||||||
|
max_ttm_gb="$(python3 -c "print(${total_gb} * ${MAX_TTM_PERCENT} / 100)")"
|
||||||
|
|
||||||
|
if [[ "${ttm_action}" == "clear" ]]; then
|
||||||
|
ttm_gb="0"
|
||||||
|
elif [[ -n "${ttm_gb}" ]]; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
ttm_gb="0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local needed_mb
|
||||||
|
needed_mb="$(python3 -c "
|
||||||
|
c = ${carveout_mb}
|
||||||
|
t = float('${ttm_gb}') * 1024 if ${ttm_gb} else 0
|
||||||
|
r = float('${min_reserve}') * 1024
|
||||||
|
print(int(c + t + r))
|
||||||
|
")"
|
||||||
|
|
||||||
|
if (( needed_mb > total_mb )); then
|
||||||
|
echo "Refusing: profile needs ~$(( needed_mb / 1024 )) GB but only ~${total_gb} GB RAM installed."
|
||||||
|
echo " carveout ${carveout_mb} MB + TTM ${ttm_gb} GB + OS reserve ${min_reserve} GB"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ttm_gb}" != "0" ]] && python3 -c "exit(0 if float('${ttm_gb}') > float('${max_ttm_gb}') else 1)"; then
|
||||||
|
echo "Warning: TTM ${ttm_gb} GB exceeds ${MAX_TTM_PERCENT}% of RAM (~${max_ttm_gb} GB)."
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
write_ttm_config() {
|
||||||
|
local gb="$1"
|
||||||
|
local pages
|
||||||
|
pages="$(gb_to_pages "${gb}")"
|
||||||
|
cat > "${TTM_CONF}" <<EOF
|
||||||
|
# Written by z13-memory-profiles on $(date -Iseconds)
|
||||||
|
options ttm pages_limit=${pages}
|
||||||
|
options ttm page_pool_size=${pages}
|
||||||
|
EOF
|
||||||
|
log "Wrote ${TTM_CONF} (${gb} GB -> ${pages} pages)"
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_ttm_config() {
|
||||||
|
if [[ -f "${TTM_CONF}" ]]; then
|
||||||
|
rm -f "${TTM_CONF}"
|
||||||
|
log "Removed ${TTM_CONF}"
|
||||||
|
else
|
||||||
|
log "No ${TTM_CONF} to remove (already default)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
regenerate_initramfs() {
|
||||||
|
if command -v dracut >/dev/null 2>&1; then
|
||||||
|
log "Regenerating initramfs (dracut)..."
|
||||||
|
dracut --force --regenerate-all 2>/dev/null || dracut --force
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if command -v update-initramfs >/dev/null 2>&1; then
|
||||||
|
update-initramfs -u -k all
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if command -v mkinitcpio >/dev/null 2>&1; then
|
||||||
|
mkinitcpio -P
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log "No initramfs tool found; reboot may still apply modprobe.d on next boot."
|
||||||
|
}
|
||||||
|
|
||||||
|
set_carveout_index() {
|
||||||
|
local index="$1"
|
||||||
|
local uma_base
|
||||||
|
uma_base="$(find_uma_base)"
|
||||||
|
echo "${index}" > "${uma_base}/carveout"
|
||||||
|
log "Set ${uma_base}/carveout -> ${index} (applies next boot)"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_profile() {
|
||||||
|
local profile="$1"
|
||||||
|
require_root
|
||||||
|
|
||||||
|
local carveout_mb ttm_action ttm_gb label desc
|
||||||
|
|
||||||
|
label="$(read_profile_value "${profile}" label)"
|
||||||
|
desc="$(read_profile_value "${profile}" description)"
|
||||||
|
carveout_mb="$(read_profile_value "${profile}" carveout_target_mb)"
|
||||||
|
ttm_action="$(read_profile_value "${profile}" ttm_action)"
|
||||||
|
ttm_gb="$(read_profile_value "${profile}" ttm_gb)"
|
||||||
|
|
||||||
|
validate_profile "${profile}" || return 1
|
||||||
|
|
||||||
|
log "Applying profile: ${label} (${profile})"
|
||||||
|
log "${desc}"
|
||||||
|
|
||||||
|
local uma_base carveout_line carveout_index
|
||||||
|
if uma_base="$(find_uma_base)"; then
|
||||||
|
mapfile -t carveout_pick < <(find_carveout_index "${uma_base}" "${carveout_mb}")
|
||||||
|
carveout_index="${carveout_pick[0]}"
|
||||||
|
carveout_line="${carveout_pick[1]:-}"
|
||||||
|
set_carveout_index "${carveout_index}"
|
||||||
|
log "Carveout: ${carveout_line}"
|
||||||
|
else
|
||||||
|
log "WARN: UMA sysfs missing — fixed VRAM unchanged."
|
||||||
|
log " Use Armoury Crate in Windows once, or update kernel/firmware."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ttm_action}" == "clear" ]]; then
|
||||||
|
clear_ttm_config
|
||||||
|
elif [[ -n "${ttm_gb}" ]]; then
|
||||||
|
write_ttm_config "${ttm_gb}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
regenerate_initramfs
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
Profile "${label}" staged successfully.
|
||||||
|
|
||||||
|
Changes take effect after reboot:
|
||||||
|
• Fixed VRAM (carveout): target ${carveout_mb} MB
|
||||||
|
• Dynamic GPU pool (TTM): $(
|
||||||
|
if [[ "${ttm_action}" == "clear" ]]; then echo "kernel default (custom config removed)"; else echo "${ttm_gb} GB"; fi
|
||||||
|
)
|
||||||
|
|
||||||
|
Verify after reboot:
|
||||||
|
sudo dmesg | grep -i 'amdgpu.*memory'
|
||||||
|
cat /sys/module/ttm/parameters/pages_limit 2>/dev/null || true
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
show_status() {
|
||||||
|
local total_gb uma_line ttm_gb
|
||||||
|
total_gb="$(total_ram_gb)"
|
||||||
|
echo "=== Z13 Memory Status ==="
|
||||||
|
echo "Total RAM: ~${total_gb} GB"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if uma_base="$(find_uma_base)"; then
|
||||||
|
echo "UMA carveout (fixed VRAM):"
|
||||||
|
echo " Path: ${uma_base}"
|
||||||
|
echo " Active index: $(cat "${uma_base}/carveout" 2>/dev/null || echo '?')"
|
||||||
|
echo " Options:"
|
||||||
|
sed 's/^/ /' "${uma_base}/carveout_options"
|
||||||
|
else
|
||||||
|
echo "UMA carveout: not exposed on this kernel (use Windows Armoury Crate for fixed VRAM)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "TTM dynamic pool:"
|
||||||
|
if [[ -r "${TTM_PARAM}" ]]; then
|
||||||
|
ttm_gb="$(current_ttm_gb)"
|
||||||
|
echo " Active limit: ~${ttm_gb} GB"
|
||||||
|
else
|
||||||
|
echo " ${TTM_PARAM} not readable"
|
||||||
|
fi
|
||||||
|
if [[ -f "${TTM_CONF}" ]]; then
|
||||||
|
echo " Pending config: ${TTM_CONF}"
|
||||||
|
sed 's/^/ /' "${TTM_CONF}"
|
||||||
|
else
|
||||||
|
echo " No custom ${TTM_CONF}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if command -v amd-ttm >/dev/null 2>&1; then
|
||||||
|
echo "amd-ttm:"
|
||||||
|
amd-ttm 2>/dev/null | sed 's/^/ /' || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build a transferable tarball of z13-memory-profiles
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
NAME="z13Profiler"
|
||||||
|
VERSION="1.0.0"
|
||||||
|
OUT="$(cd "${ROOT}/.." && pwd)/${NAME}-${VERSION}.tar.gz"
|
||||||
|
|
||||||
|
cd "${ROOT}/.."
|
||||||
|
tar -czf "${OUT}" \
|
||||||
|
--exclude='*.tar.gz' \
|
||||||
|
--exclude='.git' \
|
||||||
|
"${NAME}/"
|
||||||
|
|
||||||
|
echo "Created: ${OUT}"
|
||||||
|
echo ""
|
||||||
|
echo "Transfer to Z13 (USB, scp, etc.), then on the tablet:"
|
||||||
|
echo " tar -xzf ${NAME}-${VERSION}.tar.gz"
|
||||||
|
echo " cd ${NAME}"
|
||||||
|
echo " ./install.sh"
|
||||||
|
echo " z13-memory-profiles"
|
||||||
Reference in New Issue
Block a user