code wiki / _hdl_build / nx_ctxtop_lib.nx
nx_ctxtop_lib.nx
buildroot/runtime/_hdl_build/nx_ctxtop_lib.nx
about
nx_ctxtop_lib.nx -- PURE core of nx_ctxtop: per-process context-switch ATTRIBUTION.
WHY: nx_procchurn proved the box takes 81k-93k context switches/sec in EVERY sample across 45 minutes
(1.6-1.9x the RED line) -- the one CONSTANT in the perf lane. But a box-level rate names no culprit,
and the fork-rate hypothesis was DISPROVEN as the driver (seq1340: forks swing 15->179->10 while ctxsw
stays flat, so the switches are NOT mostly fork/exec). /proc/<pid>/status carries
voluntary_ctxt_switches and nonvoluntary_ctxt_switches PER PROCESS, so the producer is directly
measurable instead of guessed. LAW (rising-debt-means-find-the-producer): a rate with no owner is a
symptom, not a diagnosis.
★THE VOLUNTARY/NONVOLUNTARY SPLIT IS THE DIAGNOSIS, not a detail:
voluntary = the process BLOCKED on its own (read/poll/sleep) -- an I/O or poll-loop design,
fixable by batching, longer polls, or event-driven waits.
nonvoluntary = the SCHEDULER preempted it -- CPU contention / too many runnable threads,
fixed by reducing concurrency, not by batching.
The same total means opposite remedies, so a tool reporting only the sum would send the fix the wrong
way. This lib keeps them separate all the way to the output.
Rule 15: rate arithmetic is REUSED from nx_procchurn_lib (pc_rate), generic IO/print from
nx_resmon_lib -- no new copies of the emit family (D001/seq389: 9495 duplicate bodies).
license_tier: ORIGINAL Read-only. No hw writes (Rule 26).
dependencies 1 imports · 4 importers
imports: nx_procchurn_lib.nx
imported by: nx_ctxtop.nxnx_ctxtop_gate.nxnx_memvel.nxnx_poolwidth_lib.nx
structs
| none |
consts
| 24 | const CT_NOTFOUND: i64 = 0 - 1 |
| 86 | const CT_LOADAVG_SCALE: i64 = 100 |
| 87 | const CT_ASCII_DOT: i64 = 46 |
functions
| 29 | func ct_find(pids: *i64, n: i64, pid: i64) -> i64 |
| 43 | func ct_topk_insert(pids: *i64, rates: *i64, k: i64, used: i64, pid: i64, rate: i64) -> i64 |
| 72 | func ct_share_permil(part: i64, total: i64) -> i64 |
| 91 | func ct_load_centi(buf: *u8, n: i64) -> i64 |
| 130 | func ct_admit(load_centi: i64, max_centi: i64) -> i64 |