# CPU Frequency Control (org.enne2.cpufreq) Plasmoide KDE Plasma 6 per pilotare il profilo energetico della CPU: governor, limiti di frequenza (min/max), `energy_performance_preference` (EPP), boost/turbo, quattro profili pronti e **task con profilo dedicato** che ripristina lo stato precedente quando il comando finisce. Verificato su **frigate** (Fedora 44, Plasma 6.7.5 Wayland, kernel 7.2, AMD Ryzen 7 H 255, driver `amd-pstate-epp` in modalità `active`, 16 policy). ![widget](docs/widget.png) ## Cosa fa | Area | Azione | |---|---| | Profili | **Silenzioso** (EPP power, boost off, tetto 35%), **Risparmio** (balance_power, boost off, tetto 60%), **Bilanciato** (balance_performance, boost on, nessun tetto), **Performance** (governor performance, EPP performance, boost on) | | Governor | pillole con i valori realmente disponibili in `scaling_available_governors` | | EPP | pillole con i valori di `energy_performance_available_preferences` | | Limiti | due slider min/max in kHz con validazione e rilettura; il valore applicato è arrotondato a 10 MHz | | Boost | pillole `on`/`off` (per-policy su kernel recenti, altrimenti globale, altrimenti `intel_pstate/no_turbo`) | | Task | elenco configurabile: ogni task applica un profilo, esegue il comando **come utente** e ripristina la baseline all'uscita | | Footer | messaggio dell'ultima azione e pulsante **Reset** (default hardware: boost on, nessun tetto) | La vista compatta (pannello) mostra frequenza corrente e un badge `no boost`. La frequenza è la massima fra le policy (core più attivo), con la media sotto. ## Architettura e modello di sicurezza ``` org.enne2.cpufreq (QML, non privilegiato) ├─ contents/scripts/cpufreq-state.sh lettura sysfs, /proc, hwmon (nessun privilegio) ├─ contents/scripts/enne2-cpufreq-task launcher task (utente) └─ pkexec /usr/local/libexec/enne2-cpufreq/cpufreq-helper (root) ├─ comandi a elenco chiuso, argomenti validati contro sysfs ├─ ogni scrittura riletta per verifica └─ /var/lib/enne2-cpufreq/{baseline,refcount} (root:root 0755/0644) polkit ├─ /usr/share/polkit-1/actions/org.enne2.cpufreq.set.policy azione dedicata └─ /etc/polkit-1/rules.d/50-org.enne2.cpufreq.rules allow senza prompt ``` - Il widget non è mai root: l'unica operazione privilegiata è l'helper, con sottocomandi fissi (`set-governor`, `set-epp`, `set-limits`, `set-boost`, `apply`, `reset`, `task-begin`, `task-end`, `save-state`, `restore-state`). - L'annotazione `org.freedesktop.policykit.exec.path` lega l'azione polkit a quel solo binario: nessun altro programma eredita il permesso. - La regola in `/etc/polkit-1/rules.d/` concede `polkit.Result.YES` solo a utenti **locali**, con sessione **attiva**, nel gruppo **wheel**. Senza quel file la `.policy` chiede la password a ogni modifica (`auth_admin_keep`). - I comandi dei task girano come utente (`setsid sh -c`), mai come root. ## Installazione ```sh cd ~/Dev/kde-cpufreq-dashboard ./install.sh # widget (utente) + backend (sudo) ./install.sh --widget # solo il plasmoide ./install.sh --backend # solo helper + polkit (root) ./install.sh --no-polkit-rule # backend senza la regola "nessun prompt" ./install.sh --dry-run # mostra le operazioni ``` Il widget si aggiunge da *Aggiungi widget → «CPU Frequency Control»* oppure via scripting Plasma: ```js desktops()[0].addWidget("org.enne2.cpufreq") ``` Disinstallazione: `./uninstall.sh` (ripristina la baseline prima di rimuovere l'helper). I task configurati restano in `~/.config/enne2-cpufreq/tasks.json`. ## Task con profilo dedicato Dall'interfaccia: **Nuovo** → nome, comando, profilo. Da terminale: ```sh enne2-cpufreq-task list enne2-cpufreq-task add "Render Blender" performance "blender -b scena.blend -f 1" enne2-cpufreq-task run render-blender enne2-cpufreq-task stop render-blender enne2-cpufreq-task active ``` Sequenza di `run`: 1. `helper task-begin `: salva la baseline (solo al primo task) e applica il profilo 2. il comando parte staccato (`setsid`) e scrive il proprio pid in `$XDG_RUNTIME_DIR/enne2-cpufreq/.pid` 3. un watcher attende l'uscita del pid e chiama `helper task-end`, che decrementa un contatore e ripristina la baseline a zero (con `notify-send` di conferma) Più task in parallelo sono contati: il ripristino avviene solo quando l'ultimo termina. `enne2-cpufreq-task remove` rifiuta di rimuovere un task in esecuzione. ## Comportamento sui driver - **amd-pstate-epp (active)**: `powersave`/`performance` sono policy del driver; `powersave` *non* blocca la frequenza al minimo, EPP è il vero bias. Con `boost=0` il kernel abbassa `cpuinfo_max_freq` alla frequenza nominale (3.80 GHz invece di 4.97 GHz): il tetto reale viene letto da `amd_pstate_max_freq`, e per questo `apply` imposta **prima** il boost e poi i limiti. - **intel_pstate**: boost tramite `intel_pstate/no_turbo` (invertito). - **Altri driver cpufreq**: governor e limiti restano validi; EPP e boost compaiono solo se le interfacce esistono. ## Servizi concorrenti Se `tuned`, `power-profiles-daemon` o `tlp` sono attivi il widget lo segnala: il profilo `balanced` di tuned scrive esattamente `governor`, `energy_performance_preference` e `boost`, quindi un `tuned-adm profile` o il boot possono sovrascrivere le impostazioni. Su frigate `tuned` è attivo: le modifiche valgono fino al prossimo apply di tuned. ## Diagnosi ```sh /usr/local/libexec/enne2-cpufreq/cpufreq-helper status # stato, baseline, refcount ~/.local/share/plasma/plasmoids/org.enne2.cpufreq/contents/scripts/cpufreq-state.sh pkexec /usr/local/libexec/enne2-cpufreq/cpufreq-helper apply balanced journalctl --user -u plasma-plasmashell.service -f | grep cpufreq ``` | Sintomo | Causa | |---|---| | banner rosso «Backend non installato» | manca `/usr/local/libexec/enne2-cpufreq/` → `./install.sh --backend` | | dialog password a ogni modifica | manca la regola polkit (o utente fuori da `wheel`) | | «autorizzazione negata da polkit» | regola non caricata: `systemctl try-reload-or-restart polkit` | | valori che tornano indietro | servizio concorrente (tuned/power-profiles-daemon/tlp) | | il widget resta 68×68 | `implicitWidth/Height` del plasmoide non validi: verificare `main.qml` | ## Note di implementazione Plasma 6 - `metadata.json` con `X-Plasma-API-Minimum-Version: "6.0"`, senza chiavi Plasma 5. - Comandi via `org.kde.plasma.plasma5support` (`engine: "executable"`); ogni azione usa un source univoco (contatore in coda) perché il motore non riesegue un source già noto. - `syncControls()` è protetto: `applyState()` gira ogni 2 s e la rappresentazione piena può non esistere (popup chiuso) → senza guardia il `ReferenceError` su un id interrompeva la sincronizzazione dei controlli. - `implicitWidth/implicitHeight` del `Flickable` sono costanti: se dipendono dal layout il containment riduce il widget alla dimensione minima (68×68). - Nessun `Switch` per il boost: `toggled` scatta anche quando il valore viene riallineato dallo stato. Le pillole sono prive di stato interno. ## File ``` metadata.json contents/ui/main.qml interfaccia (compact + full, Flickable) contents/ui/ChoicePill.qml pillola selezionabile contents/scripts/profiles.sh tabella profili condivisa (unica fonte) contents/scripts/cpufreq-state.sh lettura stato non privilegiata contents/scripts/enne2-cpufreq-task launcher task (utente) bin/cpufreq-helper helper privilegiato (root) polkit/*.policy, polkit/*.rules azione e regola polkit install.sh, uninstall.sh ``` Licenza MIT.