Top: each CPU's threads are counted from 0 under it on a two-socket machine

The kernel numbers the whole machine's threads in one run and deals them out a
socket at a time, twice: nexus's first CPU listed C0–C9 and C20–C29, its second
C10–C19 and C30–C39. Each CPU now lists its own twenty as C0–C19; the kernel's
number is in the row's tooltip.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-11-10 12:19:49 -08:00
co-authored by Claude
parent 0e57419d8b
commit c40de5067b
4 changed files with 63 additions and 8 deletions
+34
View File
@@ -0,0 +1,34 @@
// node scripts/test-sockets.mjs — src/sockets.ts: each CPU's threads, counted under it.
import { buildSync } from 'esbuild'
import { pathToFileURL } from 'node:url'
import { mkdtempSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
const out = join(mkdtempSync(join(tmpdir(), 'sockets-')), 'sockets.mjs')
buildSync({ entryPoints: [new URL('../src/sockets.ts', import.meta.url).pathname], outfile: out, format: 'esm', logLevel: 'error' })
const { socketThreads } = await import(pathToFileURL(out).href)
const fails = []
const eq = (got, want, what) => { if (JSON.stringify(got) !== JSON.stringify(want)) fails.push(`${what} — got ${JSON.stringify(got)}, want ${JSON.stringify(want)}`) }
const range = (a, b) => Array.from({ length: b - a }, (_, i) => a + i)
// nexus: 2 × E5-2680 v2, as /sys/devices/system/cpu/cpu*/topology/physical_package_id reads
const nexus = [...Array(10).fill(0), ...Array(10).fill(1), ...Array(10).fill(0), ...Array(10).fill(1)]
const got = socketThreads(nexus)
eq(got.map((s) => s.pkg), [0, 1], 'two sockets, in order')
eq(got[0].cpus, [...range(0, 10), ...range(20, 30)], "CPU 1's threads")
eq(got[1].cpus, [...range(10, 20), ...range(30, 40)], "CPU 2's threads")
eq(got.map((s) => s.cpus.length), [20, 20], 'twenty threads each')
// every thread is under exactly one CPU
eq(got.flatMap((s) => s.cpus).sort((a, b) => a - b), range(0, 40), 'every thread once')
// a thread's number under its CPU runs 0…19 on both
for (const s of got) eq(s.cpus.map((_, n) => n), range(0, 20), `CPU ${s.pkg + 1} counts from 0`)
// a board that numbers each socket's threads together, and one whose socket ids are not 0 and 1
eq(socketThreads([0, 0, 0, 0, 1, 1, 1, 1]), [{ pkg: 0, cpus: [0, 1, 2, 3] }, { pkg: 1, cpus: [4, 5, 6, 7] }], 'contiguous numbering')
eq(socketThreads([3, 1, 3, 1]), [{ pkg: 1, cpus: [1, 3] }, { pkg: 3, cpus: [0, 2] }], 'socket ids sorted')
eq(socketThreads([]), [], 'nothing')
if (fails.length) { console.error('sockets: FAIL\n ' + fails.join('\n ')); process.exit(1) }
console.log('sockets: ok')