std/os/processor

std/os/src/processor.trb

Processor - how many processors the machine has, what they are and how busy they are - with ProcessorTimes, the cumulative time each state has taken, ProcessorUsage, the fractions of an interval, ProcessorDescription, what a processor says about itself, and Frequency, a processor clock.

Each question is a match OperatingSystem.current whose arm hands it to the directory of that system; only the arm of the build's target is compiled. The sums and the fractions here are pure, so their tests run on every machine.

type Frequency

type Frequency with Show, Compare

A processor clock: a count of hertz.

Examples

print Frequency.ofMegahertz(3_600)
print Frequency.ofMegahertz(800).gigahertz()

Related

fn ofHertz

static fn ofHertz(hertz: Int64): Frequency

A clock of exactly this many hertz.

fn ofMegahertz

static fn ofMegahertz(megahertz: Int64): Frequency

A clock of this many megahertz.

fn hertz

fn hertz(): Int64

As a whole number of hertz, which is exactly what it holds.

fn megahertz

fn megahertz(): Float64

In megahertz of a million hertz.

fn gigahertz

fn gigahertz(): Float64

In gigahertz of a thousand megahertz.

fn compare

fn compare(other: Self): Ordering

Which of the two clocks is the slower one.

fn show

fn show(): String

The unit that fits: whole megahertz below 1000 of them (800 MHz), gigahertz to one decimal from there on (3.6 GHz), both rounded half up, and hertz below one megahertz (500 Hz).

type Processor

type Processor

The processors of this machine. logicalCount is the machine; what this process may use is CurrentProcess.processors(), which honours the affinity mask and a container's CPU quota.

Examples

print "{Processor.logicalCount()?} threads on {Processor.physicalCount()?} cores"
const usage = Processor.usage(500.milliseconds()).await()?
print "{usage.busy * 100.0}% busy"

Related

fn logicalCount

static fn logicalCount(): Result<Int, OsError>

How many logical processors the system runs threads on, hyper-threads included; at least one.

Errors

  • OsError.Unsupported on FreeBSD, whose slice has not come yet, and in a browser, which cannot tell.
  • OsError.Failed where the system's call fails, with its words.

fn physicalCount

static fn physicalCount(): Result<Int, OsError>

How many physical cores: never more than Processor.logicalCount. Where the system does not say - Arm Linux writes no core identifiers - every logical processor counts as a core.

Errors

fn describe

static fn describe(): Result<ProcessorDescription, OsError>

Vendor, model, packages, cores, caches and features of the processor, read once. On x86-64 it is assembled from what cpuid says - the vendor, the brand string, the caches and the features the system lets a program use - and the system's own counts of packages, cores and logical processors, because on a processor with cores of different kinds cpuid answers for the core it happens to run on. The frequencies are None until they have a source.

Examples

const processor = Processor.describe().expect("the processor")
print "{processor.model}: {processor.physicalCores} cores, {processor.logicalProcessors} threads"
print processor.features.contains(ProcessorFeature.Avx2)

Errors

  • OsError.Unsupported on FreeBSD and in a browser, and on an architecture other than x86-64, whose description has not come yet.
  • The errors of Processor.logicalCount and Processor.physicalCount.
  • OsError.Failed where the system's call for the packages fails, with its words.

fn times

static fn times(): Result<ProcessorTimes, OsError>

The time every processor together has spent in each state since the system started. Two readings are monotonic, and their difference is what Processor.usage reports.

Errors

  • OsError.Malformed where /proc/stat is not in the form Linux writes it.
  • OsError.Unsupported on FreeBSD and in a browser.
  • OsError.Failed where the system's call fails, with its words.

fn timesOfEach

static fn timesOfEach(): Result<List<ProcessorTimes>, OsError>

The same, for each logical processor, in the system's order: as many as Processor.logicalCount says.

Errors

fn usage

static fn usage(interval: Duration = 1.seconds()): Task<Result<ProcessorUsage, OsError>>

How busy the processors were over interval: two readings of Processor.times and Processor.timesOfEach, and a sleep between them.

Errors

type ProcessorTimes

type ProcessorTimes with Show, Equals, Subtract

Cumulative time in each state. The difference of two readings is what Processor.usage reports.

Pitfalls

  • What a system counts differently stays in other: Linux folds nice, interrupts and stolen time into it, and Windows counts the interrupt and deferred-procedure time inside system, so its waiting and other are zero.

field user

user: Duration

Running programs of users.

field system

system: Duration

Running the system for them.

field idle

idle: Duration

With nothing to run.

field waiting

waiting: Duration

Waiting for input or output with nothing else to run: Linux iowait. Zero where the system does not count it.

field other

other: Duration

Everything else the system counts: nice, interrupts, stolen time.

fn total

fn total(): Duration

The five states together: the time the processors have existed.

fn subtract

fn subtract(other: Self): Self

These times less other, state by state.

type ProcessorUsage

type ProcessorUsage with Show, Equals

Fractions of an interval, each between 0 and 1.

Examples

const usage = Processor.usage().await()?
for fraction in usage.each {
  print fraction
}

Related

field busy

busy: Float64

user + system of all processors together, as a fraction of their total time.

field user

user: Float64

The share of the total time that ran programs of users.

field system

system: Float64

The share that ran the system.

field each

each: List<Float64>

busy of each processor, in the order of Processor.timesOfEach.

fn between

static fn between(total: ProcessorTimes, each: List<ProcessorTimes>): ProcessorUsage

The fractions of two differences of ProcessorTimes: all processors together, and each one. A difference that covers no time at all - or a negative one, where a counter went backwards - answers 0, never NaN.

type ProcessorDescription

type ProcessorDescription with Show, Equals

What a processor says about itself, as Processor.describe reads it.

Examples

const processor = Processor.describe().expect("the processor")
print processor.vendor
print processor.model
for cache in processor.caches {
  print "L{cache.level} {cache.kind}: {cache.size}"
}

Pitfalls

  • physicalCores and logicalProcessors are the machine's, as the system counts them, and not what cpuid says of the one core it ran on: they differ on a processor with cores of different kinds.
  • caches and features are those of the core that answered, which on such a processor is one of several kinds.

Related

field vendor

vendor: String

The vendor string: GenuineIntel, AuthenticAMD.

field model

model: String

The brand string, AMD Ryzen 9 7950X 16-Core Processor; the vendor string where the processor has none.

field packages

packages: Int

How many processors (sockets) the machine has; at least one.

field physicalCores

physicalCores: Int

The cores of all packages together, as the system counts them.

field logicalProcessors

logicalProcessors: Int

The logical processors of all packages together, hyper-threads included.

field baseFrequency

baseFrequency: Frequency?

The clock the processor is rated at; None until a source for it exists.

field maximumFrequency

maximumFrequency: Frequency?

The highest clock the processor reaches; None until a source for it exists.

field caches

caches: List<ProcessorCache>

The caches the processor lists, level by level; empty where it lists none.

field features

features: Set<ProcessorFeature>

The extensions a program may use.

type ProcessorCache

type ProcessorCache with Show, Equals

One cache of a processor, as the processor describes it: the level, what it holds, how large it is and how long its lines are. A cache that several cores share is one entry, with its full size.

Examples

fn describe(caches: List<ProcessorCache>) {
  for cache in caches {
    print "L{cache.level} {cache.kind}: {cache.size}"
  }
}

Related

field level

level: Int

1, 2 or 3.

field kind

kind: "data" | "instruction" | "unified"

What it holds: only data, only instructions, or both.

field size

size: ByteSize

Its total size.

field lineSize

lineSize: ByteSize

The bytes that move between this cache and the next level at once.

type ProcessorFeature

type ProcessorFeature with Show, Equals, Hash

An instruction-set extension a program may dispatch on, named after the extension as its vendor spells it. The list is closed and grows with its users: a case is added when something reads it.

On x86-64 a feature is reported only when the processor has it and the operating system can use it: the AVX family needs the system to save the wider registers on a task switch, which a processor's own bit does not say.

Examples

fn wideKernelsAreSafe(features: Set<ProcessorFeature>): Bool {
  features.contains ProcessorFeature.Avx2
}

Related

case Sse2

case Sse2

SSE2, which every x86-64 processor has.

case Sse3

case Sse3

SSE3.

case Ssse3

case Ssse3

Supplemental SSE3.

case Sse41

case Sse41

SSE4.1.

case Sse42

case Sse42

SSE4.2.

case Avx

case Avx

AVX, with the system saving the 256-bit registers.

case Avx2

case Avx2

AVX2, with the system saving the 256-bit registers.

case Fma

case Fma

Fused multiply-add on the AVX registers.

case Bmi1

case Bmi1

The first bit-manipulation set.

case Bmi2

case Bmi2

The second bit-manipulation set.

case Avx512Foundation

case Avx512Foundation

AVX-512 Foundation, with the system saving the 512-bit registers and the mask registers.

case Aes

case Aes

The AES instructions.

case Sha

case Sha

The SHA-1 and SHA-256 instructions.

case Neon

case Neon

Arm Advanced SIMD.

case Crc32

case Crc32

The Arm CRC32 instructions.

case DotProduct

case DotProduct

The Arm dot-product instructions.

case Sve

case Sve

The Arm Scalable Vector Extension.

case Sve2

case Sve2

The second version of the Arm Scalable Vector Extension.