@samitouri / QOSAMI-WSL / commits / 2cfdd582

Set page_reporting_order via kernel command line (#40374)

* Set page_reporting_order via kernel command line Move page reporting configuration from post-boot process launches and init messages to the kernel command line parameter (page_reporting.page_reporting_order=N). This ensures the correct order is set at boot time for both WSLC and WSL2. Remove PageReportingOrder from the early config message struct. Simplify the memory reduction thread in init to always perform compaction when idle, removing the PageReportingOrder gate which was effectively dead code (the value was always non-zero in practice). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR feedback: simplify lambda capture and align page reporting logic - Simplify [Mode = Mode] to [Mode] in ConfigureMemoryReduction lambda - Use coldDiscardShiftSize variable in HcsVirtualMachine to match WslCoreVm pattern Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Ben Hillis committed May 1, 2026 at 12:46 UTC 2cfdd58286cc41ef6f31280dd13bca8d8e574034
6 files changed +29 -59
src/linux/init/main.cpp
+10 -36
@@ -122,7 +122,7 @@ std::optional<bool> g_EnableSocketLogging;
122
123 int Chroot(const char* Target);
124
125 -void ConfigureMemoryReduction(int PageReportingOrder, LX_MINI_INIT_MEMORY_RECLAIM_MODE Mode);
125 +void ConfigureMemoryReduction(LX_MINI_INIT_MEMORY_RECLAIM_MODE Mode);
126
127 void CreateSwap(unsigned int Lun);
128
@@ -265,20 +265,16 @@ Return Value:
265 return 0;
266 }
267
268 -void ConfigureMemoryReduction(int PageReportingOrder, LX_MINI_INIT_MEMORY_RECLAIM_MODE Mode)
268 +void ConfigureMemoryReduction(LX_MINI_INIT_MEMORY_RECLAIM_MODE Mode)
269
270 /*++
271
272 Routine Description:
273
274 - This routine sets the page reporting order.
274 + This routine configures memory reduction behavior including memory reclaim and compaction.
275
276 Arguments:
277
278 - PageReportingOrder - Supplies the page reporting order. This value determines the size of cold discard hints
279 - by using the equation: 2^PageReportingOrder * PAGE_SIZE
280 - Example: 2^9 * 4096 = 2MB
281 -
278 Mode - Supplies the memory reclaim mode.
279
280 Return Value:
@@ -290,32 +286,11 @@ Return Value:
286 try
287 {
288 //
293 - // Ensure the value falls within a reasonable range (single page to 2MB).
294 - //
295 -
296 - if (PageReportingOrder < 0 || PageReportingOrder > 9)
297 - {
298 - LOG_WARNING("Invalid page_reporting_order {}", PageReportingOrder);
299 - PageReportingOrder = 0;
300 - }
301 - else
302 - {
303 - WriteToFile("/sys/module/page_reporting/parameters/page_reporting_order", std::to_string(PageReportingOrder).c_str());
304 - }
305 -
306 - //
307 - // Create a worker thread to periodically check if the VM is idle and performs memory compaction.
308 - // This ensures that the maximum number of pages can be discarded to the host.
289 + // Create a worker thread to periodically check if the VM is idle and performs memory compaction
290 + // and memory reclaim. This ensures that the maximum number of pages can be discarded to the host.
291 //
310 - // N.B. Compaction is not needed if page reporting order is set to single page mode.
311 - //
312 -
313 - if (PageReportingOrder == 0 && Mode == LxMiniInitMemoryReclaimModeDisabled)
314 - {
315 - return;
316 - }
292
318 - std::thread([PageReportingOrder = PageReportingOrder, Mode = Mode]() mutable {
293 + std::thread([Mode]() mutable {
294 try
295 {
296 //
@@ -422,11 +397,10 @@ try
397
398 //
399 // Perform memory compaction if the VM is idle.
425 - //
426 - // N.B. Memory compaction is not needed if the page reporting order is set to single page (0).
400 + // This coalesces free pages into larger blocks for more efficient page reporting.
401 //
402
429 - if (PageReportingOrder != 0 && (Start - Stop) > IdleThreshold)
403 + if ((Start - Stop) > IdleThreshold)
404 {
405 std::this_thread::sleep_for(std::chrono::seconds(1));
406 Stop = GetUserCpuTime();
@@ -3294,10 +3268,10 @@ try
3268 }
3269
3270 //
3297 - // Configure page reporting and memory reclamation.
3271 + // Configure memory reclamation.
3272 //
3273
3300 - ConfigureMemoryReduction(EarlyConfig->PageReportingOrder, EarlyConfig->MemoryReclaimMode);
3274 + ConfigureMemoryReduction(EarlyConfig->MemoryReclaimMode);
3275
3276 //
3277 // Initialize system distro if supported.
src/shared/inc/lxinitshared.h
-2
@@ -1251,7 +1251,6 @@ typedef struct _LX_MINI_INIT_EARLY_CONFIG_MESSAGE
1251 unsigned int SwapLun;
1252 LX_MINI_INIT_MOUNT_DEVICE_TYPE SystemDistroDeviceType;
1253 unsigned int SystemDistroDeviceId;
1254 - int PageReportingOrder;
1254 LX_MINI_INIT_MEMORY_RECLAIM_MODE MemoryReclaimMode;
1255 // IPv4 address stored in network byte order
1256 uint32_t DnsTunnelingIpAddress = 0;
@@ -1269,7 +1268,6 @@ typedef struct _LX_MINI_INIT_EARLY_CONFIG_MESSAGE
1268 FIELD(SwapLun),
1269 FIELD(SystemDistroDeviceType),
1270 FIELD(SystemDistroDeviceId),
1272 - FIELD(PageReportingOrder),
1271 FIELD(MemoryReclaimMode),
1272 FIELD(DnsTunnelingIpAddress),
1273 FIELD(EnableDebugShell),
src/windows/service/exe/HcsVirtualMachine.cpp
+11 -2
@@ -76,15 +76,21 @@ HcsVirtualMachine::HcsVirtualMachine(_In_ const WSLCSessionSettings* Settings)
76 vmSettings.ComputeTopology.Memory.EnableColdDiscardHint = true;
77 vmSettings.ComputeTopology.Processor.Count = Settings->CpuCount;
78
79 - // Configure backing page size, fault cluster shift size, and cold discard hint size to favor density (lower vmmem usage).
79 + // Configure backing page size, fault cluster shift size, and page reporting order to favor density (lower vmmem usage).
80 //
81 - // N.B. Cold discard hint size should be a multiple of the fault cluster shift size.
81 + // N.B. Page reporting order must be >= fault cluster size shift.
82 const auto windowsVersion = wsl::windows::common::helpers::GetWindowsVersion();
83 + int pageReportingOrder;
84 if (windowsVersion.BuildNumber >= WindowsBuildNumbers::Germanium)
85 {
86 vmSettings.ComputeTopology.Memory.BackingPageSize = hcs::MemoryBackingPageSize::Small;
87 vmSettings.ComputeTopology.Memory.FaultClusterSizeShift = 4;
88 vmSettings.ComputeTopology.Memory.DirectMapFaultClusterSizeShift = 4;
89 + pageReportingOrder = 5; // 128k
90 + }
91 + else
92 + {
93 + pageReportingOrder = 9; // 2MB
94 }
95
96 if (helpers::IsVmemmSuffixSupported() && Settings->DisplayName)
@@ -108,6 +114,9 @@ HcsVirtualMachine::HcsVirtualMachine(_In_ const WSLCSessionSettings* Settings)
114 // Enable timesync workaround to sync on resume from sleep in modern standby.
115 kernelCmdLine += L" hv_utils.timesync_implicit=1";
116
117 + // Configure page reporting order - minimum order of pages reported as free to the hypervisor.
118 + kernelCmdLine += std::format(L" page_reporting.page_reporting_order={}", pageReportingOrder);
119 +
120 // Setup dmesg collector with optional DmesgOutput handle.
121 // TODO: move dmesg collector to user session process.
122 // N.B. 'DmesgOutput' needs to be duplicated since COM will close it when this call completes.
src/windows/service/exe/WslCoreVm.cpp
+7 -5
@@ -509,7 +509,6 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
509 message->SwapLun = swapLun;
510 message->SystemDistroDeviceType = m_systemDistroDeviceType;
511 message->SystemDistroDeviceId = m_systemDistroDeviceId;
512 - message->PageReportingOrder = m_coldDiscardShiftSize;
512 message->MemoryReclaimMode = static_cast<LX_MINI_INIT_MEMORY_RECLAIM_MODE>(m_vmConfig.MemoryReclaim);
513 message->EnableDebugShell = m_vmConfig.EnableDebugShell;
514 message->EnableSafeMode = m_vmConfig.EnableSafeMode;
@@ -1381,9 +1380,9 @@ std::wstring WslCoreVm::GenerateConfigJson()
1380 vmSettings.ComputeTopology.Memory.EnableDeferredCommit = true;
1381 vmSettings.ComputeTopology.Memory.EnableColdDiscardHint = true;
1382
1384 - // Configure backing page size, fault cluster shift size, and cold discard hint size to favor density (lower vmmem usage).
1383 + // Configure backing page size, fault cluster shift size, and page reporting order to favor density (lower vmmem usage).
1384 //
1386 - // N.B. Cold discard hint size should be a multiple of the fault cluster shift size.
1385 + // N.B. Page reporting order must be >= fault cluster size shift.
1386 //
1387 // N.B. This is only done on builds that have the fix for the VID deadlock on partition teardown.
1388 if ((m_windowsVersion.BuildNumber >= WindowsBuildNumbers::Germanium) ||
@@ -1394,11 +1393,11 @@ std::wstring WslCoreVm::GenerateConfigJson()
1393 vmSettings.ComputeTopology.Memory.BackingPageSize = hcs::MemoryBackingPageSize::Small;
1394 vmSettings.ComputeTopology.Memory.FaultClusterSizeShift = 4; // 64k
1395 vmSettings.ComputeTopology.Memory.DirectMapFaultClusterSizeShift = 4; // 64k
1397 - m_coldDiscardShiftSize = 5; // 128k
1396 + m_pageReportingOrder = 5; // 128k
1397 }
1398 else
1399 {
1401 - m_coldDiscardShiftSize = 9; // 2MB
1400 + m_pageReportingOrder = 9; // 2MB
1401 }
1402
1403 // May need more MMIO than the default 16GB. WSL uses a vpci device per Plan9 share, WSLg adds a GPU device,
@@ -1527,6 +1526,9 @@ std::wstring WslCoreVm::GenerateConfigJson()
1526 // Enable timesync workaround to sync on resume from sleep in modern standby.
1527 kernelCmdLine += L" hv_utils.timesync_implicit=1";
1528
1529 + // Configure page reporting order - minimum order of pages reported as free to the hypervisor.
1530 + kernelCmdLine += std::format(L" page_reporting.page_reporting_order={}", m_pageReportingOrder);
1531 +
1532 // If using virtio features, enable SWIOTLB as a perf optimization (will cause VM to consume 64MB more memory).
1533 if (m_vmConfig.EnableVirtio9p || m_vmConfig.EnableVirtioFs || m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy)
1534 {
src/windows/service/exe/WslCoreVm.h
+1 -1
@@ -277,7 +277,7 @@ private:
277 wsl::core::Config m_vmConfig;
278 std::wstring m_comPipe0;
279 std::wstring m_comPipe1;
280 - int m_coldDiscardShiftSize;
280 + int m_pageReportingOrder;
281 WslTraceLoggingClient m_traceClient;
282 std::filesystem::path m_rootFsPath;
283 std::filesystem::path m_tempPath;
src/windows/wslcsession/WSLCVirtualMachine.cpp
-13
@@ -295,19 +295,6 @@ void WSLCVirtualMachine::Initialize()
295 // Configure GPU mounts if enabled
296 MountGpuLibraries(c_gpuLibrariesPath, c_gpuDriversPath);
297
298 - // Configure cold discard hint size for page reporting.
299 - // This sets the minimum order of pages that will be reported as free to the hypervisor.
300 - {
301 - const auto windowsVersion = wsl::windows::common::helpers::GetWindowsVersion();
302 - int pageReportingOrder = (windowsVersion.BuildNumber >= wsl::windows::common::helpers::WindowsBuildNumbers::Germanium) ? 5 : 9; // 128k or 2MB
303 - auto cmdStr = std::format("echo {} > /sys/module/page_reporting/parameters/page_reporting_order", pageReportingOrder);
304 - std::vector<const char*> args{"/bin/sh", "-c", cmdStr.c_str()};
305 -
306 - WSLCProcessOptions options{};
307 - options.CommandLine = {.Values = args.data(), .Count = static_cast<ULONG>(args.size())};
308 - CreateLinuxProcessImpl("/bin/sh", options, {}, nullptr, [](const auto&) {});
309 - }
310 -
298 // Configure networking. This must happen after all filesystems are mounted since /gns needs to access /sys.
299 ConfigureNetworking();
300 }