SYSTEM_CPU_SET_INFORMATION中SchedulingClass的含义

Ale*_*tov 4 cpu winapi

https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_cpu_set_information

MSDN 对此只字未提,但我想知道 SchedulingClass 是什么意思?

我正在查看 AMD Threadripper PRO 5975WX(32 核/64 逻辑处理器),它具有相同的内核(从 Windows 角度来看),除了 SchedulingClass 外,EfficiencyClass=0。前 32 个逻辑核心的 SchedulingClass 不同,但后 32 个核心的 SchedulingClass=0。有什么不同?这是否会以某种方式影响核心的性能?

我还比较了每个核心的频率和PROCESSOR_POWER_INFORMATION,它们都是相同的。

Nei*_*tsa 7

(注意:汇编和内核的东西有点重)。

\n

由于该结构有点难以解析(即使是视觉上),因此其偏移量SchedulingClass为 20 (0x14):

\n
    size_t offScheduling = offsetof(SYSTEM_CPU_SET_INFORMATION, CpuSet.SchedulingClass);\n    printf("off: %llu", offScheduling);  // prints 20\n
Run Code Online (Sandbox Code Playgroud)\n

GetSystemCpuSetInformation该结构本身由(由 导出)使用kernel32.dll

\n

事实上它位于kernelbase.dll通过出口转发。该函数是一个包装器nt!NtQuerySystemInformationEx(因此是一个内核函数),大小写为 0xAF:

\n
00007FFC8C22C5D0 <kernelbase.GetSystemCpuSetInformation>\n; ...\n00007FFC8C22C60E  mov ecx,AF\n00007FFC8C22C613  call qword ptr ds:[<&NtQuerySystemInformationEx>]\n
Run Code Online (Sandbox Code Playgroud)\n

对于案例 0xAF,nt!NtQuerySystemInformationEx调用nt!ExpQuerySystemInformation(使用相同的案例编号),然后我们到达这里:

\n
PAGE:000000014069215C loc_14069215C:\nPAGE:000000014069215C    mov     rcx, [rsp+338h+Handle] ; jumptable 000000014068F773 case 175\nPAGE:0000000140692164    test    rcx, rcx\nPAGE:0000000140692167    jz      short loc_1406921A9\nPAGE:0000000140692169    mov     r8, cs:PsProcessType ; ObjectType\nPAGE:0000000140692170    mov     [rsp+338h+var_238], r14\nPAGE:0000000140692178    mov     [rsp+338h+HandleInformation], r14 ; HandleInformation\nPAGE:000000014069217D    lea     rax, [rsp+338h+var_238]\nPAGE:0000000140692185    mov     [rsp+338h+Object], rax ; Object\nPAGE:000000014069218A    movzx   r9d, r12b       ; AccessMode\nPAGE:000000014069218E    mov     edx, 1000h      ; DesiredAccess\nPAGE:0000000140692193    call    ObReferenceObjectByHandle\nPAGE:0000000140692198    mov     r14, [rsp+338h+var_238]\nPAGE:00000001406921A0    test    eax, eax\nPAGE:00000001406921A2    jns     short loc_1406921B1\nPAGE:00000001406921A4    jmp     loc_1406925ED\nPAGE:00000001406921A9 ; ---------------------------------------------------------------------------\nPAGE:00000001406921A9\nPAGE:00000001406921A9 loc_1406921A9:                          ; CODE XREF: ExpQuerySystemInformation+2D87\xe2\x86\x91j\nPAGE:00000001406921A9    mov     r14, [rsp+338h+Process]\nPAGE:00000001406921B1\nPAGE:00000001406921B1 loc_1406921B1:                          ; CODE XREF: ExpQuerySystemInformation+2DC2\xe2\x86\x91j\nPAGE:00000001406921B1    mov     r9, r14\nPAGE:00000001406921B4    lea     r8, [rsp+338h+Size]\nPAGE:00000001406921B9    mov     edx, edi\nPAGE:00000001406921BB    mov     rcx, rbx        ; void *\nPAGE:00000001406921BE    call    KeQueryCpuSetInformation\n
Run Code Online (Sandbox Code Playgroud)\n

上面发生了什么:如果您将进程句柄传递给GetSystemCpuSetInformation,则该句柄首先被取消引用(即,handle -> _EPROCESS),然后nt!KeQueryCpuSetInformation被调用。

\n

我们nt!KeQueryCpuSetInformation有这样的代码:

\n
PAGE:00000001407B4D02    call    KiGetCpuSetData\nPAGE:00000001407B4D07    mov     r13, rax\n; ...\nPAGE:00000001407B4D56    mov     al, [r13+6]\nPAGE:00000001407B4D5A    mov     [r11+14h], al  ; set SchedulingClass!\n
Run Code Online (Sandbox Code Playgroud)\n

所以,nt!KiGetCpuSetData返回一个结构体;从该结构中,偏移量 +6 处的值用于设置该SchedulingClass字段。

\n

(注意这r11是输出结构)。

\n

现在让我们看看nt!KeQueryCpuSetInformation

\n
.text:0000000140360D94 KiGetCpuSetData proc near\n.text:0000000140360D94\n.text:0000000140360D94                 shl     ecx, 6\n.text:0000000140360D97                 lea     eax, [rdx+rcx]\n.text:0000000140360D9A                 shl     rax, 4\n.text:0000000140360D9E                 add     rax, cs:KiCpuSetData\n.text:0000000140360DA5                 retn\n.text:0000000140360DA5 KiGetCpuSetData endp\n
Run Code Online (Sandbox Code Playgroud)\n

所以一切都来自一个名为 的全局变量nt!KiCpuSetData。看看对该结构的引用,我们只得到了一些结果。

\n

其中一个有趣之处在于nt!KiConfigureCpuSetSchedulingInformation

\n
.text:00000001403B284C KiConfigureCpuSetSchedulingInformation proc near\n; ...\n.text:00000001403B2865                 mov     rsi, rcx\n...\n.text:00000001403B28C3                 add     r8, cs:KiCpuSetData\n; ...\n.text:00000001403B293B                 mov     al, [rsi+81B9h]\n.text:00000001403B2941                 mov     [r8+6], al  ; set offset +6.\n
Run Code Online (Sandbox Code Playgroud)\n

所以,RSI是一个结构体,代码使用偏移量0x81B9来设置当前结构体中的偏移量+6 KiCpuSetData

\n

rsi实际上指向_KPRCB(内核处理器控制块)结构,该结构(基本上)代表内核的 CPU(与其主机结构一起,即_KPCR内核处理器控制区域)。

\n
PAGE:00000001408B7295                 lea     rax, KiProcessorBlock  ; global system KPRCB\nPAGE:00000001408B729C                 mov     ecx, edi\nPAGE:00000001408B729E                 mov     rcx, [rax+rcx*8]  ; pick the one for the current processor.\nPAGE:00000001408B72A2                 call    KiConfigureCpuSetSchedulingInformation\n
Run Code Online (Sandbox Code Playgroud)\n

让我们看看偏移量 0x81B9:

\n
typedef struct _KPRCB                                                     // 351 elements, 0xAF00 bytes (sizeof)\n{\n    // ...\n\n    /*0x7FF8*/     VOID*        MmInternal;\n    /*0x8000*/     struct _PROCESSOR_POWER_STATE PowerState;                             // 46 elements, 0x200 bytes (sizeof)\n    /*0x8200*/     VOID*        HyperPte;\n\n    // ...\n}KPRCB, *PKPRCB;\n
Run Code Online (Sandbox Code Playgroud)\n

我们在 0x8000 处有一个结构,因此它位于该结构内偏移量 0x1B9 (0x8000 + 0x1B9 = 0x81B9) 处:

\n
typedef struct _PROCESSOR_POWER_STATE                         // 46 elements, 0x200 bytes (sizeof)\n{\n\n// ...\n\n/*0x1B8*/     UINT8        ArchitecturalEfficiencyClass;\n/*0x1B9*/     UINT8        PerformanceSchedulingClass;\n/*0x1BA*/     UINT8        EfficiencySchedulingClass;\n\n// ...\n}PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE;\n
Run Code Online (Sandbox Code Playgroud)\n

所以该字段的名称是PerformanceSchedulingClass. 我没有进一步推进我的调查(该字段实际上是在其中设置的)\n但是AMD第 19 页的幻灯片中有一个很好的解释:

\n
\n

某些 AMD 产品的内核比其他内核更快。\n系统 BIOS 描述每个逻辑处理器的 CPPC 最高性能排名。\nWindows 内核根据此信息创建 PerformanceSchedulingClass 排名,并在调度期间使用它。\n逻辑处理器 0 和CCD0 可能不是最快的。

\n
\n

据我了解上述内容以及我们在内核中看到的代码,内核SchedulingClass使用它来根据处理器在地面上的执行情况对处理器进行分组?(我不是 CPU 专家)。

\n