microsoft/Windows-Dev-Performance

Windows incorrectly schedules utility QoS threads exclusively to E-cores when running on AC power

Opened this issue · 0 comments

Windows Build Number

22631

Processor Architecture

AMD64

Memory

64GB

Storage Type, free / capacity

SSD 4TB

Relevant apps installed

WinDbg, LiveKD

Traces collected via Feedback Hub

https://aka.ms/AAojvh6

Isssue description

Windows incorrectly schedules utility QoS threads exclusively to E-cores when running on AC power.

Steps to reproduce

[C:\]
> cd C:\Windows\Temp\
[C:\Windows\Temp]
> $sieve_URI = "https://github.com/kimwalisch/primesieve/releases/download/v11.2/primesieve-11.2-win-x64.zip"
[C:\Windows\Temp]
> Invoke-WebRequest -Uri $sieve_URI -OutFile "sieve.zip"
[C:\Windows\Temp]
> Expand-Archive -Path ".\sieve.zip" -DestinationPath ".\sieve\"
[C:\Windows\Temp]
> schtasks.exe /Create /SC ONLOGON /TN "PrimeSieve" /TR "C:\Windows\Temp\sieve\primesieve.exe 1e12" /NP
SUCCESS: The scheduled task "PrimeSieve" has successfully been created.
[C:\Windows\Temp]
> schtasks.exe /Run /TN "PrimeSieve"
SUCCESS: Attempted to run the scheduled task "PrimeSieve".
[C:\Windows\Temp]
>

Expected Behavior

Windows should schedule utility QoS processes/threads exclusively to E-core only when running on battery power. When running on AC power the default behavior should be kept.

According to the documentation of a company called Microsoft (archive):

QoS level
Utility
Description
Background services
Performance and power
On battery, selects most efficient CPU frequency and schedules to efficient cores.
Release
Windows 11 22H2

image

Actual Behavior

Windows schedules the process's threads to run only on the E-cores:

image

Taking a dump using livekd.exe while primesieve.exe is running allows us to verify the thread QoS:

0: kd> dx Debugger.Sessions[0].Processes.Where( p => p.Name == "primesieve.exe" ).First().Threads.Select( t => t.KernelObject.Tcb.BamQosLevel )
Debugger.Sessions[0].Processes.Where( p => p.Name == "primesieve.exe" ).First().Threads.Select( t => t.KernelObject.Tcb.BamQosLevel )                
    [0x9bac]         : 0x6 [Type: unsigned long]
    [0x215c]         : 0x6 [Type: unsigned long]
    [0x9978]         : 0x6 [Type: unsigned long]
    [0x7e84]         : 0x6 [Type: unsigned long]
    [0x5fc8]         : 0x6 [Type: unsigned long]
    [0x5f20]         : 0x6 [Type: unsigned long]
    [0xf6c]          : 0x6 [Type: unsigned long]
    [0x5a38]         : 0x6 [Type: unsigned long]
    [0x5aa8]         : 0x6 [Type: unsigned long]
    [0xa2b4]         : 0x6 [Type: unsigned long]
    [0x574c]         : 0x6 [Type: unsigned long]
    [0x67c4]         : 0x6 [Type: unsigned long]
    [0x5af4]         : 0x6 [Type: unsigned long]
    [0xa6d8]         : 0x6 [Type: unsigned long]
    [0x301c]         : 0x6 [Type: unsigned long]
    [0xa270]         : 0x6 [Type: unsigned long]
    [0x42d8]         : 0x6 [Type: unsigned long]
    [0x378]          : 0x6 [Type: unsigned long]
    [0xed4]          : 0x6 [Type: unsigned long]
    [0x84d0]         : 0x6 [Type: unsigned long]
    [0x2968]         : 0x6 [Type: unsigned long]

And as we all know 6 means KHeteroCpuQosUtility.