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,它们都是相同的。
(注意:汇编和内核的东西有点重)。
\n由于该结构有点难以解析(即使是视觉上),因此其偏移量SchedulingClass为 20 (0x14):
size_t offScheduling = offsetof(SYSTEM_CPU_SET_INFORMATION, CpuSet.SchedulingClass);\n printf("off: %llu", offScheduling); // prints 20\nRun Code Online (Sandbox Code Playgroud)\nGetSystemCpuSetInformation该结构本身由(由 导出)使用kernel32.dll。
事实上它位于kernelbase.dll通过出口转发。该函数是一个包装器nt!NtQuerySystemInformationEx(因此是一个内核函数),大小写为 0xAF:
00007FFC8C22C5D0 <kernelbase.GetSystemCpuSetInformation>\n; ...\n00007FFC8C22C60E mov ecx,AF\n00007FFC8C22C613 call qword ptr ds:[<&NtQuerySystemInformationEx>]\nRun Code Online (Sandbox Code Playgroud)\n对于案例 0xAF,nt!NtQuerySystemInformationEx调用nt!ExpQuerySystemInformation(使用相同的案例编号),然后我们到达这里:
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\nRun Code Online (Sandbox Code Playgroud)\n上面发生了什么:如果您将进程句柄传递给GetSystemCpuSetInformation,则该句柄首先被取消引用(即,handle -> _EPROCESS),然后nt!KeQueryCpuSetInformation被调用。
我们nt!KeQueryCpuSetInformation有这样的代码:
PAGE:00000001407B4D02 call KiGetCpuSetData\nPAGE:00000001407B4D07 mov r13, rax\n; ...\nPAGE:00000001407B4D56 mov al, [r13+6]\nPAGE:00000001407B4D5A mov [r11+14h], al ; set SchedulingClass!\nRun Code Online (Sandbox Code Playgroud)\n所以,nt!KiGetCpuSetData返回一个结构体;从该结构中,偏移量 +6 处的值用于设置该SchedulingClass字段。
(注意这r11是输出结构)。
现在让我们看看nt!KeQueryCpuSetInformation:
.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\nRun Code Online (Sandbox Code Playgroud)\n所以一切都来自一个名为 的全局变量nt!KiCpuSetData。看看对该结构的引用,我们只得到了一些结果。
其中一个有趣之处在于nt!KiConfigureCpuSetSchedulingInformation:
.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.\nRun Code Online (Sandbox Code Playgroud)\n所以,RSI是一个结构体,代码使用偏移量0x81B9来设置当前结构体中的偏移量+6 KiCpuSetData。
rsi实际上指向_KPRCB(内核处理器控制块)结构,该结构(基本上)代表内核的 CPU(与其主机结构一起,即_KPCR内核处理器控制区域)。
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\nRun Code Online (Sandbox Code Playgroud)\n让我们看看偏移量 0x81B9:
\ntypedef 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;\nRun Code Online (Sandbox Code Playgroud)\n我们在 0x8000 处有一个结构,因此它位于该结构内偏移量 0x1B9 (0x8000 + 0x1B9 = 0x81B9) 处:
\ntypedef 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;\nRun Code Online (Sandbox Code Playgroud)\n所以该字段的名称是PerformanceSchedulingClass. 我没有进一步推进我的调查(该字段实际上是在其中设置的)\n但是AMD第 19 页的幻灯片中有一个很好的解释:
\n\n某些 AMD 产品的内核比其他内核更快。\n系统 BIOS 描述每个逻辑处理器的 CPPC 最高性能排名。\nWindows 内核根据此信息创建 PerformanceSchedulingClass 排名,并在调度期间使用它。\n逻辑处理器 0 和CCD0 可能不是最快的。
\n
据我了解上述内容以及我们在内核中看到的代码,内核SchedulingClass使用它来根据处理器在地面上的执行情况对处理器进行分组?(我不是 CPU 专家)。
| 归档时间: |
|
| 查看次数: |
204 次 |
| 最近记录: |