GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Guest CPU time includes host load: expose steal time (or a PMU) to the Linux VM · Issue #2788 · orbstack/orbstack

Guest CPU time includes host load: expose steal time (or a PMU) to the Linux VM #2788

New issue
Copy link
New issue
Copy link
Open
Open
Guest CPU time includes host load: expose steal time (or a PMU) to the Linux VM#2788
Copy link

Description

@spankyed
spankyed
opened on Nov 7, 2026
Issue body actions

Is your feature request related to a problem? Please describe.

Inside OrbStack's Linux VM, a process's CPU time grows with the host's load, because the guest is never told when its vCPU was descheduled. The steal column in /proc/stat stays at 0 however busy the Mac is, so a guest can't tell CPU it used from time the host took.

That makes CPU time useless inside the VM as a measure of how much work a process did. That's the usual way a build or test runner tells a process that is slow from one that is spinning, so the runner gets killed for host load it can't see.

Measured on an M1 Pro, macOS 26.3.1, OrbStack 2.0.5, with the same fixed loop (2e9 iterations in Node, CPU read through process.cpuUsage()):

host at load ~10 host saturated (16 busy loops on 10 cores)
on macOS 10.1s CPU 10.3s CPU
in an OrbStack container (--cpus 2) 11.4s CPU 35.6s CPU (35.6s wall)

On macOS the work's CPU time doesn't move with load. In the guest it tripled, and it matched the wall time exactly: the whole time the vCPU was waiting for the host was counted as the process's own CPU.

To reproduce:

# steal stays 0 in the guest, idle or under host load
docker run --rm alpine sh -c 'head -1 /proc/stat'

# fixed work, CPU time as the guest accounts it; run once with the Mac idle and once with it saturated
docker run --rm --cpus 2 node:24-bookworm node -e 'const c=process.cpuUsage();let x=0;for(let i=0;i<2e9;i++)x+=i%7;const u=process.cpuUsage(c);console.log((u.user+u.system)/1e6)'

The other load-independent measure of work, retired-instruction counts, isn't available either: the guest has no CPU PMU (/sys/bus/event_source/devices lists only breakpoint kprobe software tracepoint uprobe).

Describe the solution you'd like

Either of:

  1. Steal-time accounting for the guest (paravirtual steal time, as KVM guests get through CONFIG_PARAVIRT_TIME_ACCOUNTING), so the kernel stops counting descheduled time as a task's CPU and reports it as steal.
  2. A virtualised PMU, so perf_event_open can count instructions retired in the guest.

Describe alternatives you've considered

  • Measuring the VM from the macOS side: honest, but a single VM runs every container, so a reading can't be attributed to one container.
  • Wall-clock limits: these are what host load already breaks.
  • Inside the VM we now stop limiting by CPU at all and rely on a no-progress watchdog, plus one generous wall-clock limit around the whole run. That works, but it loses the ability to catch a loop that spins.

Additional context

Cloud CI on KVM hypervisors has steal accounting, so the same runner code does get accurate CPU time there. OrbStack is where it doesn't.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.