os: Processor.describe and ProcessorDescription on x86-64 (OS slice 3, step 2b of #127) #543

Closed
opened 2026-10-28 13:19:15 +00:00 by orion · 3 comments
Collaborator

Goal

Step 2b of #127 (OS slice 3): Processor.describe() and ProcessorDescription on x86-64 Windows, Linux and macOS, assembled from the decoders step 2a landed (#538) and the system's own counts.

Why the cut: the rest of step 2 (vendor, model, caches and features of an Arm64 processor from getauxval(AT_HWCAP), hw.optional.* and IsProcessorFeaturePresent, three new natives or sysctl names, three per-system halves) is a second PR of its own. Only this first part is filed, per the definition of ready; the Arm64 part stays in the epic checklist as step 2c and is filed when this one lands.

Design record

docs/design/OS.md section 5.2 (Processor.describe, ProcessorDescription), the "As built (step 2a)" note of section 7 ("ProcessorDescription (step 2b) takes that count from the system"), slice 3 of section 10.

Scope

  • ProcessorDescription in std/os/src/processor.trb as in section 5.2 (vendor, model, packages, physicalCores, logicalProcessors, baseFrequency, maximumFrequency, caches, features; with Show, Equals). baseFrequency and maximumFrequency are None here; step 3 fills them.
  • Processor.describe(): Result<ProcessorDescription, OsError>: a match OperatingSystem.current like its siblings, Unsupported arms for FreeBSD and the browser; on Windows, Linux and macOS an Architecture.current match whose .X64 arm reads CpuidDump.read() and whose other arms answer OsError.Unsupported("the processor description", ...) until step 2c replaces them.
  • The composition is one pure function in x86/processor.trb (a CpuidDump method or a static function over a dump and three integers): vendor, brand and features from the dump, caches from the dump, logicalProcessors and physicalCores from the system's counts (Processor.logicalCount, physicalCount), because on a hybrid processor cpuid answers for the core it happens to run on (OS.md 7, as built). Brand string trimmed; an empty brand falls back to the vendor string.
  • packages from the system, one small function per half, each with a pure parser where there is text: Windows processorCounts (already returns packages), macOS sysctl hw.packages, Linux the distinct physical id values of /proc/cpuinfo (parsePackageCount, 0 where none is named, then 1). Where the system gives none, CpuidTopology.packagesOf(logical).
  • std/os/tests/processor.test.trb and x86.test.trb: the composition fed with the captured dumps of #538 (one Intel, one AMD, one with and one without AVX-512) plus the three counts, including a hybrid case where the system's core count differs from the dump's topology; parsePackageCount on a one-socket, a two-socket and an Arm /proc/cpuinfo.
  • docs/standard-library/os.md documents describe and ProcessorDescription; the skills/ copy is regenerated; the "As built" note of OS.md section 7 and the slice 3 row of section 10 say what 2b did.
  • Out of scope: Arm64 features, vendor, model and caches (2c), frequencies (step 3), the planned Windows.processorTopology native (cache data comes from cpuid on every x86 system, so it is not needed here; step 2c decides whether Arm Windows needs it).

Acceptance criteria

  • On an x86-64 machine Processor.describe() answers Ok with a non-empty vendor and model, logicalProcessors == Processor.logicalCount(), physicalCores == Processor.physicalCount(), 1 <= packages and physicalCores <= logicalProcessors, baseFrequency and maximumFrequency None, features containing Sse2, and at least one cache (checked by a test that runs on the CI machines, tolerant of the machine's values).
  • On FreeBSD and in a browser describe answers OsError.Unsupported, as the siblings do; on a non-x86 architecture it answers Unsupported until 2c (a test or the check --every-target run shows no compile error on any target).
  • The composition is a pure function of a dump and three integers: with the captured Intel, AMD and AVX-512 dumps it returns the expected vendor, trimmed model, caches and features, and with a hybrid dump the system's physicalCores, not the dump's, wins.
  • parsePackageCount counts the distinct physical id values, answers 1 for a file that names none (a one-socket or Arm file) and never traps on an empty text.
  • torb format --check clean on touched files; sh tools/gates.sh a green in forge CI; docs check and skills/ regeneration clean.

Seed impact

None expected: new std names and one new function per half; no native, no syntax change, no std name the compiler looks up by string. If CI shows otherwise, fall back to the two-commit rule.

Size

One PR, two Conventional Commits: feat(os): processor package counts per system (the three packages functions, parsePackageCount and their tests) and feat(os): Processor.describe and ProcessorDescription on x86-64 (type, composition, tests, docs).

Dependencies

Step 2a (#538) landed (acf8510), step 1 (#488) landed. Part of #127; 2c (Arm64) and step 3 (frequencies) are not filed yet.

## Goal Step 2b of #127 (OS slice 3): `Processor.describe()` and `ProcessorDescription` on x86-64 Windows, Linux and macOS, assembled from the decoders step 2a landed (#538) and the system's own counts. Why the cut: the rest of step 2 (vendor, model, caches and features of an Arm64 processor from `getauxval(AT_HWCAP)`, `hw.optional.*` and `IsProcessorFeaturePresent`, three new natives or sysctl names, three per-system halves) is a second PR of its own. Only this first part is filed, per the definition of ready; the Arm64 part stays in the epic checklist as step 2c and is filed when this one lands. ## Design record `docs/design/OS.md` section 5.2 (`Processor.describe`, `ProcessorDescription`), the "As built (step 2a)" note of section 7 ("`ProcessorDescription` (step 2b) takes that count from the system"), slice 3 of section 10. ## Scope - `ProcessorDescription` in `std/os/src/processor.trb` as in section 5.2 (`vendor`, `model`, `packages`, `physicalCores`, `logicalProcessors`, `baseFrequency`, `maximumFrequency`, `caches`, `features`; `with Show, Equals`). `baseFrequency` and `maximumFrequency` are `None` here; step 3 fills them. - `Processor.describe(): Result<ProcessorDescription, OsError>`: a `match OperatingSystem.current` like its siblings, `Unsupported` arms for FreeBSD and the browser; on Windows, Linux and macOS an `Architecture.current` match whose `.X64` arm reads `CpuidDump.read()` and whose other arms answer `OsError.Unsupported("the processor description", ...)` until step 2c replaces them. - The composition is one pure function in `x86/processor.trb` (a `CpuidDump` method or a static function over a dump and three integers): vendor, brand and features from the dump, caches from the dump, `logicalProcessors` and `physicalCores` from the system's counts (`Processor.logicalCount`, `physicalCount`), because on a hybrid processor `cpuid` answers for the core it happens to run on (OS.md 7, as built). Brand string trimmed; an empty brand falls back to the vendor string. - `packages` from the system, one small function per half, each with a pure parser where there is text: Windows `processorCounts` (already returns packages), macOS `sysctl hw.packages`, Linux the distinct `physical id` values of `/proc/cpuinfo` (`parsePackageCount`, 0 where none is named, then 1). Where the system gives none, `CpuidTopology.packagesOf(logical)`. - `std/os/tests/processor.test.trb` and `x86.test.trb`: the composition fed with the captured dumps of #538 (one Intel, one AMD, one with and one without AVX-512) plus the three counts, including a hybrid case where the system's core count differs from the dump's topology; `parsePackageCount` on a one-socket, a two-socket and an Arm `/proc/cpuinfo`. - `docs/standard-library/os.md` documents `describe` and `ProcessorDescription`; the `skills/` copy is regenerated; the "As built" note of OS.md section 7 and the slice 3 row of section 10 say what 2b did. - Out of scope: Arm64 features, vendor, model and caches (2c), frequencies (step 3), the planned `Windows.processorTopology` native (cache data comes from `cpuid` on every x86 system, so it is not needed here; step 2c decides whether Arm Windows needs it). ## Acceptance criteria - [ ] On an x86-64 machine `Processor.describe()` answers `Ok` with a non-empty `vendor` and `model`, `logicalProcessors == Processor.logicalCount()`, `physicalCores == Processor.physicalCount()`, `1 <= packages` and `physicalCores <= logicalProcessors`, `baseFrequency` and `maximumFrequency` `None`, `features` containing `Sse2`, and at least one cache (checked by a test that runs on the CI machines, tolerant of the machine's values). - [ ] On FreeBSD and in a browser `describe` answers `OsError.Unsupported`, as the siblings do; on a non-x86 architecture it answers `Unsupported` until 2c (a test or the `check --every-target` run shows no compile error on any target). - [ ] The composition is a pure function of a dump and three integers: with the captured Intel, AMD and AVX-512 dumps it returns the expected vendor, trimmed model, caches and features, and with a hybrid dump the system's `physicalCores`, not the dump's, wins. - [ ] `parsePackageCount` counts the distinct `physical id` values, answers 1 for a file that names none (a one-socket or Arm file) and never traps on an empty text. - [ ] `torb format --check` clean on touched files; `sh tools/gates.sh a` green in forge CI; docs check and `skills/` regeneration clean. ## Seed impact None expected: new std names and one new function per half; no native, no syntax change, no std name the compiler looks up by string. If CI shows otherwise, fall back to the two-commit rule. ## Size One PR, two Conventional Commits: `feat(os): processor package counts per system` (the three `packages` functions, `parsePackageCount` and their tests) and `feat(os): Processor.describe and ProcessorDescription on x86-64` (type, composition, tests, docs). ## Dependencies Step 2a (#538) landed (`acf8510`), step 1 (#488) landed. Part of #127; 2c (Arm64) and step 3 (frequencies) are not filed yet.
Author
Collaborator

[loop:torbscript] decided by the loop: step 2b is only describe on x86-64 (all three systems) with the packages per system; Arm64 vendor, model, caches and features become step 2c. Why: Arm64 needs three new system sources (getauxval(AT_HWCAP), hw.optional.arm.*, IsProcessorFeaturePresent), a native or sysctl names and three per-system halves, which together with describe would exceed one PR of two commits (numbers: 2b touches processor.trb, x86/processor.trb, three small per-system functions and their tests, about 1 h; 2c would add 3 halves and 1 to 2 natives). Also decided: caches on x86 come from cpuid on every system, so the design's Windows.processorTopology native is not needed for 2b; the core count comes from the system, not from cpuid, because a hybrid processor answers for the core it runs on (OS.md section 7, as built); non-x86 architectures answer Unsupported until 2c rather than a half-filled description. Technical choices within the design record, no owner question.

[loop:torbscript] decided by the loop: step 2b is only `describe` on x86-64 (all three systems) with the packages per system; Arm64 vendor, model, caches and features become step 2c. Why: Arm64 needs three new system sources (`getauxval(AT_HWCAP)`, `hw.optional.arm.*`, `IsProcessorFeaturePresent`), a native or sysctl names and three per-system halves, which together with `describe` would exceed one PR of two commits (numbers: 2b touches `processor.trb`, `x86/processor.trb`, three small per-system functions and their tests, about 1 h; 2c would add 3 halves and 1 to 2 natives). Also decided: caches on x86 come from `cpuid` on every system, so the design's `Windows.processorTopology` native is not needed for 2b; the core count comes from the system, not from `cpuid`, because a hybrid processor answers for the core it runs on (OS.md section 7, as built); non-x86 architectures answer `Unsupported` until 2c rather than a half-filled description. Technical choices within the design record, no owner question.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261028 until 2026-10-28T20:08:15Z

[loop:torbscript] claim implement by session:loop-torbscript-20261028 until 2026-10-28T20:08:15Z
Author
Collaborator

[loop:torbscript] implement: PR #545 opened (#545, Closes #543), two commits: package counts per system, then Processor.describe and ProcessorDescription on x86-64 (+401/-16, 12 files). Worker hit its 30 min run limit while waiting on CI; parent verified branch pushed and clean, worktree removed. CI at handoff: commit messages, scope, pdisc, bootstrap (linux-x64) green, gates/tier A/archives/same-C/playground still pending. Worker usage: 1 run, 30 min, tokens not reported. next: waiting (CI on PR and merge gate)

[loop:torbscript] implement: PR #545 opened (https://git.torb.dev/torbscript/language/pulls/545, `Closes #543`), two commits: package counts per system, then `Processor.describe` and `ProcessorDescription` on x86-64 (+401/-16, 12 files). Worker hit its 30 min run limit while waiting on CI; parent verified branch pushed and clean, worktree removed. CI at handoff: commit messages, scope, pdisc, bootstrap (linux-x64) green, gates/tier A/archives/same-C/playground still pending. Worker usage: 1 run, 30 min, tokens not reported. next: waiting (CI on PR and merge gate)
argus closed this issue 2026-10-28 20:25:39 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#543
No description provided.