ITADN

Container with process isolation is ~2.5x slower compared to host on CPU-bound loads

#636Openathierry-oct 创建于 2026-04-15
bugtriage
A
athierry-octcommented
**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 条评论