Expand description
Delay accounting via TASKSTATS generic netlink.
The kernel accounts, per task, how long it spent waiting rather than
running: waiting for a CPU while runnable, waiting for synchronous block I/O,
and waiting for a page to be swapped back in. Those three numbers are what
separate “this process is working” from “this process is stuck”, and nothing
in /proc exposes them.
§Why raw netlink
htop reaches the same data through libnl3, which it dlopens and uses
through function pointers. That is a runtime dependency on a library that may
not be installed, loaded lazily so the failure is a dlopen that returns
NULL. The protocol is four messages; speaking it directly removes the
dependency and the failure mode, and is the reason Cargo.toml still lists
nothing but libc.
§The two ways this fails, and why they are not errors
EPERM—TASKSTATS_CMD_GETrequiresCAP_NET_ADMIN. An unprivilegedgandergetsEPERMon every request, which is the normal case, not a fault.probe()records it once and no further requests are sent.ENOENTon the family —CONFIG_TASKSTATSis not compiled in. The generic-netlink family does not exist, and neither does the column.
Both end up as None on every row, which renders -: “not measured”, which
is the truth. A row must never show 0.0% for a figure nobody read.
§Units
Every *_delay_total is nanoseconds, and ac_etime is microseconds.
The percentage htop prints is Δdelay / Δ(ac_etime × 1000), i.e. the share of
the task’s wall-clock life spent waiting. It is a lifetime average, not an
instantaneous rate, because the kernel exposes no interval counter — see
docs/ROADMAP.md.
Structs§
- Delay
Acct - A connected generic-netlink socket bound to the
TASKSTATSfamily. - Delay
Stats - Cumulative delay counters for one task, all in nanoseconds, plus the task’s elapsed wall-clock life in microseconds.
Functions§
- parse_
taskstats - Parse a
struct taskstatsblob into the four fields that are read.