Container with process isolation is ~2.5x slower compared to host on CPU-bound loads
bugtriage
**Describe the bug**
I ran a simple CPU benchmark (`cpu_benchmark.ps1`, attached at the end) and the results surprised me a bit:
| Target | Average run time |
| -------- | -------- |
| Host | 1,812.615 ms |
| Container (process isolation) | 4,252.186 ms |
| Container (hyperv isolation) | 1,804.605 ms |
Hyper-V isolation yields about the same performance as the host, but process isolation is much slower.
**To Reproduce**
Run the following:
```
docker run -it --rm --isolation=process -v [folder containing the benchmark script]:C:\benchmark mcr.microsoft.com/windows/servercore:ltsc2025
C:\>powershell
PS C:\> C:\benchmark\cpu_benchmark.ps1
```
The output will look like this:
```
PS C:\> C:\benchmark\cpu_benchmark.ps1
CPU benchmark starting...
Iterations : 20000000
Runs : 6 (first run discarded as warm-up)
Run 1: 4,386.772 ms (warm-up, discarded)
Run 2: 4,297.680 ms
Run 3: 4,427.794 ms
Run 4: 4,435.934 ms
Run 5: 4,387.221 ms
Run 6: 4,458.746 ms
```
**Expected behavior**
I would have expected similar performance on process isolation, compared to the host and hyperv isolation.
**Configuration:**
- Edition: Windows 11 (version 25H2 build 26200.8246)
- Base Image being used: Windows servercore ltsc2025
- Container engine: Docker Desktop 4.68.0
- Container Engine version: 29.3.1
**Additional context**
I investigated the issue with ETW (see attached traces at the end), and noticed a big difference regarding context switches.
- This is the **ETW trace on the host**, showing the CPU usage and context switches (The high CPU activity in the CPU usage (sampled) view corresponds to the time the benchmark runs):
<img width="1920" height="1040" alt="Image" src="https://github.com/user-attachments/assets/fca11e48-a54e-4fd9-b964-0edf585f857e" />
- And this is the **ETW trace on the container with process isolation**:
<img width="1920" height="1040" alt="Image" src="https://github.com/user-attachments/assets/d5510cfa-ecad-457c-bb61-dbc0672c9c96" />
On the container, there seem to be much more frequent and regular context switches for the `powershell` process. In addition, it spends much more time in the WAIT and READY states.
I'm not a ETW expert, but this suggests that on the container, the benchmark is preempted much more frequently than on the host, which could explain the drop in performance.
Is this a known issue?
Is there a workaround?
Thanks in advance!
--------------------------------
ETW traces:
[2026-04-15_16-50-18 Container performance investigation (host).zip](https://github.com/user-attachments/files/26764519/2026-04-15_16-50-18.Container.performance.investigation.host.zip)
[2026-04-15_16-56-15 Container performance investigation (container with process isolation).zip](https://github.com/user-attachments/files/26764523/2026-04-15_16-56-15.Container.performance.investigation.container.with.process.isolation.zip)
cpu_benchmark.ps1
```powershell
param (
[long]$Iterations = 20000000,
[int]$Runs = 6
)
if ($Runs -lt 2) {
throw "Runs must be at least 2 so the first run can be discarded as warm-up."
}
function Invoke-BenchmarkRun {
param (
[long]$RunIterations
)
$sw = [System.Diagnostics.Stopwatch]::StartNew()
[long]$x = 0
for ([long]$i = 0; $i -lt $RunIterations; $i++) {
$x += $i
}
$sw.Stop()
return $sw.Elapsed.TotalMilliseconds
}
Write-Host "CPU benchmark starting..."
Write-Host "Iterations : $Iterations"
Write-Host "Runs : $Runs (first run discarded as warm-up)"
Write-Host ""
$measurements = New-Object System.Collections.Generic.List[double]
for ($run = 1; $run -le $Runs; $run++) {
$elapsedMs = Invoke-BenchmarkRun -RunIterations $Iterations
if ($run -eq 1) {
Write-Host ("Run {0}: {1:N3} ms (warm-up, discarded)" -f $run, $elapsedMs)
}
else {
$measurements.Add($elapsedMs)
Write-Host ("Run {0}: {1:N3} ms" -f $run, $elapsedMs)
}
}
$averageMs = ($measurements | Measure-Object -Average).Average
$averageTime = [TimeSpan]::FromMilliseconds($averageMs)
Write-Host ""
Write-Host ("Average time: {0} ({1:N3} ms)" -f $averageTime, $averageMs)
```
6 条评论