diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 3748ca687768..ca447b068df7 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -99,12 +99,20 @@ pub const ChildProcess = struct { return null; } }, + .windows => { + if (rus.rusage) |ru| { + return ru.PeakWorkingSetSize; + } else { + return null; + } + }, else => return null, } } const rusage_init = switch (builtin.os.tag) { .linux => @as(?std.os.rusage, null), + .windows => @as(?windows.VM_COUNTERS, null), else => {}, }; }; @@ -129,6 +137,7 @@ pub const ChildProcess = struct { os.SetIdError || os.ChangeCurDirError || windows.CreateProcessError || + windows.GetProcessMemoryInfoError || windows.WaitForSingleObjectError; pub const Term = union(enum) { @@ -364,6 +373,10 @@ pub const ChildProcess = struct { } }); + if (self.request_resource_usage_statistics) { + self.resource_usage_statistics.rusage = try windows.GetProcessMemoryInfo(self.id); + } + os.close(self.id); os.close(self.thread_handle); self.cleanupStreams(); diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index b385f681949d..fe0a68a13a06 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -3947,6 +3947,20 @@ pub const PSAPI_WS_WATCH_INFORMATION = extern struct { FaultingVa: LPVOID, }; +pub const VM_COUNTERS = extern struct { + PeakVirtualSize: SIZE_T, + VirtualSize: SIZE_T, + PageFaultCount: ULONG, + PeakWorkingSetSize: SIZE_T, + WorkingSetSize: SIZE_T, + QuotaPeakPagedPoolUsage: SIZE_T, + QuotaPagedPoolUsage: SIZE_T, + QuotaPeakNonPagedPoolUsage: SIZE_T, + QuotaNonPagedPoolUsage: SIZE_T, + PagefileUsage: SIZE_T, + PeakPagefileUsage: SIZE_T, +}; + pub const PROCESS_MEMORY_COUNTERS = extern struct { cb: DWORD, PageFaultCount: DWORD, @@ -3974,6 +3988,24 @@ pub const PROCESS_MEMORY_COUNTERS_EX = extern struct { PrivateUsage: SIZE_T, }; +pub const GetProcessMemoryInfoError = error{ + AccessDenied, + InvalidHandle, + Unexpected, +}; + +pub fn GetProcessMemoryInfo(hProcess: HANDLE) GetProcessMemoryInfoError!VM_COUNTERS { + var vmc: VM_COUNTERS = undefined; + const rc = ntdll.NtQueryInformationProcess(hProcess, .ProcessVmCounters, &vmc, @sizeOf(VM_COUNTERS), null); + switch (rc) { + .SUCCESS => return vmc, + .ACCESS_DENIED => return error.AccessDenied, + .INVALID_HANDLE => return error.InvalidHandle, + .INVALID_PARAMETER => unreachable, + else => return unexpectedStatus(rc), + } +} + pub const PERFORMANCE_INFORMATION = extern struct { cb: DWORD, CommitTotal: SIZE_T, diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index 58cba356a23a..429b36039e5d 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -32,6 +32,69 @@ const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION; const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS; const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE; +pub const PROCESSINFOCLASS = enum(c_int) { + ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + ProcessIoPriority, + ProcessExecuteFlags, + ProcessTlsInformation, + ProcessCookie, + ProcessImageInformation, + ProcessCycleTime, + ProcessPagePriority, + ProcessInstrumentationCallback, + ProcessThreadStackAllocation, + ProcessWorkingSetWatchEx, + ProcessImageFileNameWin32, + ProcessImageFileMapping, + ProcessAffinityUpdateMode, + ProcessMemoryAllocationMode, + ProcessGroupInformation, + ProcessTokenVirtualizationEnabled, + ProcessConsoleHostProcess, + ProcessWindowInformation, + MaxProcessInfoClass, +}; + +pub extern "ntdll" fn NtQueryInformationProcess( + ProcessHandle: HANDLE, + ProcessInformationClass: PROCESSINFOCLASS, + ProcessInformation: *anyopaque, + ProcessInformationLength: ULONG, + ReturnLength: ?*ULONG, +) callconv(WINAPI) NTSTATUS; + pub const THREADINFOCLASS = enum(c_int) { ThreadBasicInformation, ThreadTimes,