Util shows N/A on online cores when taskset is combined with offlined CPUs
- Lenguaje dominante
- Python
- Estrellas
- 5.1k
- Forks
- 181
- Merge medio
- 30 min
- PR fusionados (30 d)
- 2
Descripción
Follow-up to #303. The fix for #303 handles `taskset` (all CPUs online) and pure `chcpu -d` (no taskset) correctly, but the combination of the two still misreports online cores as N/A.
## Repro
On an 8-core machine:
```
sudo chcpu -d 4
taskset -c 3-6 s-tui
```
Cores actually online: 0, 1, 2, 3, 5, 6, 7. Only core 4 is offline.
s-tui displays: cores 3, 5, 6 with values; cores 0, 1, 2, 4, 7 as N/A.
Expected: only core 4 as N/A.
## Root cause
In `s_tui/sources/util_source.py::update()`, when `len(per_cpu) < total_cores` we fall back to `_get_online_cpu_ids()`, which calls `psutil.Process().cpu_affinity()`. Under taskset that returns the intersection of the taskset mask and the online set (here `[3, 5, 6]`), not the full online set (`[0, 1, 2, 3, 5, 6, 7]`).
`psutil.cpu_percent(percpu=True)` returns 7 values (one per online CPU) but we only know the real IDs of 3 of them, so `zip(online_ids, per_cpu)` truncates and every non-affinity core is marked N/A.
## Why psutil can't answer this
psutil has no API that returns "online CPU IDs" independent of process affinity. `cpu_affinity()` always intersects with the caller's mask; `cpu_count()` gives a number, not IDs; `cpu_percent(percpu=True)` gives values indexed 0..N-1 that don't map to real CPU IDs when there are gaps.
## Proposed fix
Read `/sys/devices/system/cpu/online` (Linux-only, but so is chcpu). Parse the cpulist format (`0-3,5,7`) into the online-ID list. Cadence stays the same as today — we only refresh `_cached_online_ids` when `len(per_cpu)` changes, so this is one file read at startup plus one on each hotplug event, not per update cycle.
Sketch:
```python
def _get_online_cpu_ids() -> list[int] | None:
try:
with open("/sys/devices/system/cpu/online") as f:
raw = f.read().strip()
except OSError:
return None
ids = []
for chunk in raw.split(","):
if "-" in chunk:
a, b = chunk.split("-")
ids.extend(range(int(a), int(b) + 1))
else:
ids.append(int(chunk))
return ids
```
## Scope note
This is a rare combination and was equally broken before 1.4.0 (offline detection didn't exist), so it's not a regression — just a limitation of the offline-detection feature added in #262.
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.