Skip to content

Developer Documentation

Le Khanh Binh edited this page Sep 13, 2026 · 3 revisions

Developer Documentation

Technical reference for ZenTune v2.1: architecture, daemon IPC protocols, privilege elevation, power profile backends, SMU mailbox execution, and preset serialization.

Third-party dependencies:

  • pyzmq: ZeroMQ messaging for IPC between client and daemon.
  • textual: Terminal user interface framework.
  • textual-plotext: Terminal graphing engine for live sensors.
  • zenmaster (>=1.0.0): Hardware detection, SMU mailbox messaging, and platform kernel interface abstraction.

Low-level SMU opcode tables and register mailboxes reside in the standalone zenmaster library. ZenTune encapsulates the terminal interface, privileged daemon service, safety validation, preset serialization, and Linux/macOS platform controllers.


File Structure

All core application modules reside under ZenTune/Assets/. Package imports are resolved absolutely against the Assets namespace.

ZenTune/
├── zentune.py                  Client entry point: single-instance flock, dependency validation, TUI mount
├── requirements.txt            pyzmq, textual, textual-plotext, zenmaster>=1.0.0
└── Assets/
    ├── config.ini              Application configuration file (generated on initial setup)
    ├── custom.json             Serialized custom presets storage
    ├── adaptive.json           Serialized Adaptive Mode presets storage
    ├── core/
    │   ├── config.py           ConfigParser singleton, interval clamping, REQUIRED schema definition
    │   ├── platform.py         IS_LINUX, IS_MACOS, RUNTIME_DIR (/run on Linux, /var/run on macOS)
    │   ├── powerstate.py       AC power detection (power_supply sysfs on Linux, pmset on macOS)
    │   ├── hardware.py         Hardware identification via zenmaster, ryzen_smu and macOS backend checks
    │   └── ipc.py              DaemonClient ZeroMQ REQ wrapper and singleton getter
    ├── daemon/
    │   ├── daemon.py           PowerDaemon assembly, ZeroMQ REP server loop, signal handlers
    │   ├── util.py             Daemon utility functions: SMU execution, preset resolution, single-instance lock
    │   ├── loops.py            LoopsMixin: reapply timer loop, power state monitor, suspend/resume monitor
    │   ├── commands.py         CommandsMixin: IPC command handlers (_cmd_*)
    │   ├── adaptive.py         AdaptiveMixin: dynamic tuning state machine and sensor loop (Linux only)
    │   ├── service.py          Privilege abstraction (sudo and run0), venv bootstrap, backend dispatch
    │   ├── systemd.py          systemd unit generation, installation, and journalctl inspection (Linux)
    │   └── launchd.py          launchd plist generation, bootstrap, and log inspection (macOS)
    ├── engine/
    │   ├── presets.py          Built-in preset definitions (Preset dataclass), family dispatch tables
    │   ├── adaptive.py         Adaptive Mode control math (power ramp, Curve Optimizer, iGPU clock)
    │   └── runner.py           Argument partitioning: routes sys-* to platformctl, nvidia-* to NVML, SMU to zenmaster
    ├── flows/
    │   ├── setup.py            First-run configuration initialization, integrity validation, reset routines
    │   └── updater.py          Version parsing, GitHub release downloads, atomic update workflows
    ├── system/
    │   ├── sensors.py          Hardware sensor abstraction (hwmon, PM table, sysfs)
    │   ├── nvcheck.py          NVIDIA discrete GPU presence detection
    │   ├── nvml.py             NVML ctypes bindings for clock offsets and power limit management
    │   └── platformctl.py      Power profile daemon cascade, ASUS WMI sysfs, CCD affinity, EPP, CPU boost
    ├── tuning/
    │   ├── power.py            Built-in preset enumeration and daemon apply dispatch
    │   ├── custom.py           Custom preset field definitions, validation ranges, arg builders
    │   ├── adaptivepreset.py   Adaptive preset structure and JSON serialization
    │   ├── automations.py      Power automation slot state helpers (OnAC, OnBattery, OnResume)
    │   └── backup.py           JSON preset backup and restore (BACKUP_VERSION = 1)
    └── tui/
        ├── app.py              ZenTuneApp: TabbedContent coordinator, key bindings, status polling
        ├── tabs/               Individual tab screen implementations (homeView, premadeView, etc.)
        ├── modals.py           Modal dialogues: SudoModal, Run0Modal, UpdaterModal, HardwareInfoModal
        ├── wizard.py           First-run SetupWizard modal screen
        ├── helpers.py          Status line formatters, banner art, privilege verification helpers
        └── app.tcss            Textual CSS styling

Client-Daemon Two-Process Architecture

ZenTune enforces strict separation between an unprivileged client interface and a privileged root daemon.

+-------------------------------------------------------------+
|                     Unprivileged Client                     |
|          ZenTune TUI (textual)  -  Runs as standard user     |
|          Lock: /tmp/zentune_tui.lock                        |
+-------------------------------------------------------------+
                               |
                               | ZeroMQ REQ/REP over IPC
                               | Address: ipc://{RUNTIME_DIR}/zentune.sock
                               | Socket Permissions: 0o666 (world-writable)
                               v
+-------------------------------------------------------------+
|                      Privileged Daemon                      |
|          PowerDaemon (daemon.py)  -  Runs as root           |
|          Lock: {RUNTIME_DIR}/zentune_daemon.lock            |
+-------------------------------------------------------------+
         |                        |                       |
         v                        v                       v
+------------------+    +-------------------+   +--------------------+
| zenmaster (SMU)  |    |  platformctl.py   |   |   NVML (libnvidia) |
| HSMP / MP1 / RSMU|    | ppd > tuned > sys |   | Clock Offsets / PL |
+------------------+    +-------------------+   +--------------------+

IPC Channel Characteristics

  • Socket Address: ipc://{RUNTIME_DIR}/zentune.sock where RUNTIME_DIR evaluates to /run on Linux and /var/run on macOS.
  • Permissions: The daemon explicitly sets 0o666 world-writable permissions on zentune.sock immediately after binding (daemon.py:102). This allows client processes executed by unprivileged local users to establish IPC connections without root access.
  • Timeout & Resilience: DaemonClient (core/ipc.py) enforces a 2,000 ms timeout (TIMEOUT_MS = 2_000). If a request times out, receives malformed JSON, or encounters an OS socket error, the client closes the socket handle and resets state. The next call instantiates a clean connection.
  • Single-Instance Locks: The client acquires /tmp/zentune_tui.lock using fcntl.flock with LOCK_EX | LOCK_NB. The daemon locks {RUNTIME_DIR}/zentune_daemon.lock.

IPC Command Surface

Command Payload Response Description
ping None {"ok": True, "version": "..."} Daemon liveness verification and version check.
apply args, mode {"ok": True, "output": "...", "rejected": bool} Executes an immediate hardware profile apply.
apply_loop args, mode, interval, automation {"ok": True} Starts the periodic background reapply loop.
stop_loop None {"ok": True} Halts the active reapply loop.
status None Dict of runtime state Reports active mode, arguments, loop state, AC status, and SMU output.
apply_saved None Dict of applied state Re-evaluates config.ini and transitions daemon state accordingly.
reload_config None {"ok": True} Re-reads configuration parameters from disk.
reset_state None {"ok": True} Cancels execution loops and clears cached preset state.
adaptive_start preset, values {"ok": True, "caps": [...]} Starts the dynamic Adaptive Mode loop (Linux only).
adaptive_stop None {"ok": True, "reverted": bool} Halts Adaptive Mode and restores saved preset.

Privilege Elevation Subsystem (Assets/daemon/service.py)

ZenTune supports both systemd run0 and traditional sudo for operations requiring elevated access, such as installing system services, configuring virtual environments, and writing protected files.

Tool Selection & Polkit Integration

  • get_privilege_tool(): On macOS, returns "sudo". On Linux, reads [Settings] PrivilegeTool from config.ini (auto, sudo, or run0). When set to auto, the engine checks whether sudo exists, falling back to run0, then returning "none".
  • Command Construction:
    • For run0: Base command is ["run0", "--background=", "--pipe"]. If executing in non-interactive mode, --no-ask-password is appended. This construction ensures standard streams pass cleanly without terminal escape pollution while delegating authentication to the system Polkit agent.
    • For sudo: Base command is ["sudo"]. Appends -n for non-interactive calls, or -S -p "" when feeding passwords via stdin.
  • Interactive Authentication:
    • prime_privilege(password): For run0, executes run0 --background= --pipe true. run0 relies entirely on system Polkit agents (desktop graphical dialogs or TTY agents); it does not accept passwords on stdin. If authorization is dismissed or denied, the method inspects stdout and stderr for cancellation keywords ("cancel", "denied", "not authorized", "dismiss", "closed") and sets _last_auth_cancelled = True.
    • For sudo, prime_sudo(password) validates credentials via sudo -S -p "" -v.
  • File Installation: privilege_write_file(path, content, suffix, owner, mode) writes payload to a tempfile.NamedTemporaryFile and moves it via install -m <mode> -o <owner> <tmp> <path> executed under the privileged tool.
  • systemd Bypass: In Assets/daemon/systemd.py, privilege pre-checks via privilege_available() are intentionally bypassed when get_privilege_tool() == "run0". Because Polkit invokes authentication interactively at execution time, a non-interactive pre-flight check would fail on unprimed sessions.

Power Profile & Platform Management (Assets/system/platformctl.py)

The platform management subsystem controls operating system power daemons, kernel ACPI interfaces, ASUS notebook WMI switches, CPU Energy Performance Preference (EPP), and CPU Turbo Boost.

Backend Prioritization Cascade

When resolving platform power profiles, ZenTune queries backends in strict order:

                  +----------------------------------+
                  |  get_power_profile_backend()     |
                  +----------------------------------+
                                   |
                [1] Is power-profiles-daemon active?
                               /        \
                            Yes          No
                            /              \
            Backend: "ppd"        [2] Is TuneD active?
            (powerprofilesctl /          /          \
             busctl D-Bus)             Yes           No
                                       /               \
                       Backend: "tuned"         [3] Does ACPI sysfs exist?
                       (tuned-adm active)      /sys/firmware/acpi/platform_profile
                                                        /              \
                                                     Yes                No
                                                     /                    \
                                      Backend: "sysfs"            Backend: "none"
  1. ppd (power-profiles-daemon or tuned-ppd): Tested via is_ppd_active(). Runs powerprofilesctl get, checks systemctl is-active power-profiles-daemon, and queries D-Bus property net.hadess.PowerProfiles via busctl.
  2. tuned (TuneD): Tested via is_tuned_active(). Executes tuned-adm active and verifies active profile output.
  3. sysfs (Direct Kernel ACPI Fallback): Used only when no system daemon is active. Directly targets /sys/firmware/acpi/platform_profile.
  4. none: Returned when no platform profile interface is exposed by hardware or kernel.

Prioritization rationale: Writing directly to /sys/firmware/acpi/platform_profile while power-profiles-daemon or tuned is active creates race conditions where the system daemon immediately overrides the manual sysfs write. ZenTune interacts with the active service first and reserves direct sysfs manipulation for systems without a running power daemon.

Settling Delays and Anti-Flap Timers

Hardware and platform controllers require discrete settling intervals to transition power states safely:

  • Power Profile Settling Delay: set_power_profile() introduces an explicit 0.5-second settling delay (time.sleep(0.5)) after applying profiles across all backends (ppd, tuned, and sysfs). This allows embedded controllers and firmware thermal tables to stabilize before subsequent commands execute.
  • ASUS dGPU Bus Rescan Delay: In set_asus_eco(), re-enabling discrete graphics requires a 50 ms delay (time.sleep(0.05)) prior to writing "1" to /sys/bus/pci/rescan.
  • Post-Suspend Resume Delay: In Assets/daemon/loops.py, _POST_SUSPEND_WAIT_S = 5.0 enforces a 5.0s post-suspend wait delay following wake events before reapplying presets. This prevents commands from executing before device drivers, PCIe bridges, and power delivery ICs finish resume staging.
  • Anti-Flap Cooldown: A 3.0-second delay (time.monotonic() - last_smu_apply < 3.0) in the power state monitor prevents rapid cycling caused by unstable AC adapters or intermittent charging connections.

CPU Energy Performance Preference & Boost

  • Energy Performance Preference (EPP):
    • Detection: Scans /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference, falling back to /sys/devices/system/cpu/cpufreq/policy*/energy_performance_preference.
    • Values: power, balance_power, balance_performance, performance.
    • Execution: Controlled via --sys-epp (indices 0 through 3). set_epp(index) writes the corresponding string to every available CPU core node.
  • CPU Turbo Boost:
    • Detection: Validates existence of /sys/devices/system/cpu/cpufreq/boost.
    • Execution: Controlled via --sys-cpu-boost (index 0 for disabled, 1 for enabled). set_cpu_boost(index) writes "0" or "1" directly to the boost node.

ASUS WMI Integration & Safety Guards

Controls /sys/devices/platform/asus-nb-wmi/throttle_thermal_policy (fallback /sys/class/firmware-attributes/asus-armoury/attributes/):

  • Performance Modes: Silent (2), Balanced (0), Turbo (1).
  • GPU Eco Mode: Refuses to disable dGPU if nvidia_drm has an active reference count (/sys/module/nvidia_drm/refcnt > 0), if AMD dGPU runtime status is not suspended, or if GPU MUX is set to Ultimate mode (which would cause display loss).
  • GPU MUX Mode: Switches between dGPU (Ultimate) and Optimus (Hybrid). Refuses changes if dGPU is disabled in Eco mode, and informs the user that a system reboot is required.

SMU Runner & Mailbox Architecture (Assets/engine/runner.py)

runner.py::apply_args() partitions input arguments into three execution domains:

  1. sys-* tokens: Routed to _apply_system() to invoke platformctl.py setters.
  2. nvidia-clocks=* tokens: Routed to _apply_nvidia() for local NVML execution.
  3. SMU tokens: Passed to zenmaster.apply.apply(args_str, family).

Parameter Sanitization

For non-Curve-Optimizer SMU parameters, any non-positive value (int(val, 0) <= 0) is explicitly forced to --{name}=0. Curve Optimizer tokens (set-coall, set-coper, set-cogfx) permit signed negative offsets and bypass this rule.

ZenMaster Mailbox Routing

The zenmaster package arbitrates communication across three physical SMU mailboxes:

  • MP1: Primary microprocessor mailbox for client APUs and mobile platforms. Handles STAPM, fast/slow power limits, and temperature limits.
  • RSMU: Secondary management unit mailbox used on specific desktop socket architectures and APU sub-blocks.
  • HSMP (Host System Management Port): Used on server, workstation, and select multi-CCD processors. Curve Optimizer margins on HSMP are calculated as signed 16-bit PSM margins rather than standard 20-bit two's complement offsets.

SMU Status Codes

Firmware execution responses return standardized status codes: 0x01 (SMU_OK), 0xFF (SMU_FAILED), 0xFE (SMU_UNKNOWN_CMD), 0xFD (SMU_REJECTED_PREREQ), and 0xFC (SMU_REJECTED_BUSY).

Code Enumeration Description
0x01 SMU_OK Command accepted and executed successfully by SMU firmware.
0xFF SMU_FAILED Firmware rejected command execution or internal failure occurred.
0xFE SMU_UNKNOWN_CMD Opcode is unsupported by target processor family firmware.
0xFD SMU_REJECTED_PREREQ Command prerequisite not satisfied (e.g. overclocking bit not enabled).
0xFC SMU_REJECTED_BUSY SMU mailbox interface timed out or was busy servicing higher-priority telemetry.

NVIDIA NVML Integration (Assets/system/nvml.py & runner.py)

Discrete NVIDIA GPU parameters are applied directly in ZenTune via libnvidia-ml.so.1 ctypes bindings.

Power Limits and Clock Controls

  • Power Limit: Input values in Watts are converted to milliwatts (power_limit * 1000) before calling nvmlDeviceSetPowerManagementLimit(). If the GPU does not support software power limit changes (NVML_ERROR_NOT_SUPPORTED, error code 3), the error is caught and logged.
  • Locked Clocks: Setting clock cap < 4000 MHz locks frequency via nvmlDeviceSetGpuLockedClocks(dev, 0, max_clk). Setting cap to 4000 MHz calls nvmlDeviceResetGpuLockedClocks(dev) to release the lock.
  • Clock Offsets via _ClockOffset:
    • Modern API: ZenTune constructs a _ClockOffset struct defined as:
      class _ClockOffset(ctypes.Structure):
          _fields_ = [
              ("version", ctypes.c_uint),
              ("type", ctypes.c_uint),
              ("pstate", ctypes.c_uint),
              ("clockOffsetMHz", ctypes.c_int),
              ("minClockOffsetMHz", ctypes.c_int),
              ("maxClockOffsetMHz", ctypes.c_int),
          ]
      Version is encoded as OFFSET_V1 = ctypes.sizeof(_ClockOffset) | (1 << 24). Offsets are committed via nvmlDeviceSetClockOffsets().
    • Legacy Fallback: If nvmlDeviceSetClockOffsets() is unavailable or returns unsupported, ZenTune falls back to calling legacy entry points nvmlDeviceSetGpcClkVfOffset() for core clock and nvmlDeviceSetMemClkVfOffset() for memory clock.

Preset Serialization & Backup (Assets/tuning/backup.py)

ZenTune manages three distinct JSON data files for storing user tuning configurations:

  1. custom.json: List of custom preset definitions. Stores field enabled flags and display-unit values (W, A, °C, MHz).
  2. adaptive.json: Dictionary of named adaptive tuning configurations specifying thermal targets, baseline power, and load-ramping boundaries.
  3. ~/zentune_backup.json: Unified export archive containing custom and adaptive profiles.

Backup Schema Specification

  • Constant Identifier: BACKUP_FORMAT = "ZenTune Preset Backup"
  • Version Number: BACKUP_VERSION = 1
{
  "format": "ZenTune Preset Backup",
  "version": 1,
  "created_utc": "2026-09-13T14:35:00.000000+00:00",
  "custom_presets": [
    {
      "name": "Performance_Custom",
      "tctl_temp": { "enabled": true, "value": 90 },
      "stapm_limit": { "enabled": true, "value": 35 },
      "fast_limit": { "enabled": true, "value": 45 },
      "stapm_time": { "enabled": false, "value": 64 }
    }
  ],
  "adaptive_presets": {
    "Adaptive_Custom": {
      "max_temp": 95,
      "power": 35,
      "co_max": 30,
      "igpu_min": 400,
      "igpu_max": 1900,
      "min_cpu_clk": 1500,
      "enable_co": true,
      "enable_igpu": false,
      "enable_asus": false,
      "asus_mode": 1,
      "enable_nvidia": false,
      "nv_max_clk": 4000,
      "nv_core_offset": 0,
      "nv_mem_offset": 0,
      "nv_power_limit": 0
    }
  }
}

Import Merge Semantics

import_backup(source_path, merge=True) supports non-destructive restoration:

  • When merge=True: Incoming custom presets overwrite existing profiles with identical names while preserving unique local presets. Adaptive dictionary keys are merged in place.
  • When merge=False: Local custom.json and adaptive.json files are overwritten completely by the backup contents.
  • Writes are committed atomically using cfg.atomic_write().

macOS Hardware SMU Backends

Hardware detection and register access on macOS Hackintosh systems run through Assets/core/hardware.py::check_macos_backend():

  1. DirectHW (zenmaster.directhw) — Priority 1: Requires DirectHW.kext loaded into the kernel (System Integrity Protection configured with csr-active-config = 03080000). Grants physical memory access to inspect raw SMU PM tables via CLI commands (zenmaster --sensors / zenmaster --table) and issue SMU mailbox commands. Home tab sensor plots in the TUI are Linux-only (active = [] on macOS in homeView.py), where the Home tab renders only the quick navigation menu.
  2. IOPCIBridge (zenmaster.iopci) — Priority 2: Kext-free fallback using IOKit's IOPCIBridge service. Requires boot argument debug=0x144 configured in kern.bootargs. Allows configuration space access to issue SMU mailbox commands and configure power limits without kernel extensions. Physical memory mapping is unavailable under this backend.

Premade Presets Definition (Assets/engine/presets.py)

Built-in presets are defined using the Preset dataclass:

@dataclass
class Preset:
    Eco: str
    Balanced: str
    Performance: str
    Extreme: str

The second tier is strictly named Balanced (matching CLI logs, TUI buttons, and configuration keys). Presets resolve in order:

  1. Specific hardware variant matching (_variant_preset()).
  2. APU family matching (_apu_preset()).
  3. Desktop processor matching (_desktop_preset()).
  4. Fallback baseline profile (_desktop_standard()).

Clone this wiki locally