[PATCH 2/4] ntdll: Provide more accurate virtual memory counters.

Akihiro Sagawa sagawa.aki at gmail.com
Sun Jun 4 08:37:36 CDT 2017


Current approach is less accurate because VmSize from /proc/self/status
contains Wine's reserved area by mmap(2). Thus, the counter doesn't reflect
VirtualAlloc()/VirtualFree() simultaneously.

This approach is keeping process own VM counters inside ntdll.dll. So, we can
provide more accurate values for Windows applications. To avoid wineserver
round-trip overheads when allocating, it is implemented as variables in
dlls/ntdll/virtual.c.

Signed-off-by: Akihiro Sagawa <sagawa.aki at gmail.com>
---
 dlls/ntdll/ntdll_misc.h |  1 +
 dlls/ntdll/process.c    | 18 ++++++++++++------
 dlls/ntdll/tests/info.c |  2 +-
 dlls/ntdll/virtual.c    | 41 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 5e4c39e..aa385af 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -162,6 +162,7 @@ extern NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_S
 
 /* virtual memory */
 extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN;
+extern void virtual_get_memory_counters( SIZE_T *current, SIZE_T *peak ) DECLSPEC_HIDDEN;
 extern NTSTATUS virtual_create_builtin_view( void *base ) DECLSPEC_HIDDEN;
 extern NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, SIZE_T commit_size ) DECLSPEC_HIDDEN;
 extern void virtual_clear_thread_stack(void) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index f615ce2..1d0a703 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -123,7 +123,6 @@ static void fill_VM_COUNTERS(VM_COUNTERS* pvmi)
     mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
     if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS)
     {
-        pvmi->VirtualSize = info.resident_size + info.virtual_size;
         pvmi->PagefileUsage = info.virtual_size;
         pvmi->WorkingSetSize = info.resident_size;
         pvmi->PeakWorkingSetSize = info.resident_size_max;
@@ -144,11 +143,7 @@ static void fill_VM_COUNTERS(VM_COUNTERS* pvmi)
 
     while (fgets(line, sizeof(line), f))
     {
-        if (sscanf(line, "VmPeak: %lu", &value))
-            pvmi->PeakVirtualSize = (ULONG64)value * 1024;
-        else if (sscanf(line, "VmSize: %lu", &value))
-            pvmi->VirtualSize = (ULONG64)value * 1024;
-        else if (sscanf(line, "VmHWM: %lu", &value))
+        if (sscanf(line, "VmHWM: %lu", &value))
             pvmi->PeakWorkingSetSize = (ULONG64)value * 1024;
         else if (sscanf(line, "VmRSS: %lu", &value))
             pvmi->WorkingSetSize = (ULONG64)value * 1024;
@@ -301,7 +296,10 @@ NTSTATUS WINAPI NtQueryInformationProcess(
                 {
                     memset(&pvmi, 0 , sizeof(VM_COUNTERS));
                     if (ProcessHandle == GetCurrentProcess())
+                    {
+                        virtual_get_memory_counters(&pvmi.VirtualSize, &pvmi.PeakVirtualSize);
                         fill_VM_COUNTERS(&pvmi);
+                    }
                     else
                     {
                         SERVER_START_REQ(get_process_vm_counters)
@@ -320,6 +318,14 @@ NTSTATUS WINAPI NtQueryInformationProcess(
                         SERVER_END_REQ;
                         if (ret) break;
                     }
+                    if (pvmi.PeakWorkingSetSize > pvmi.PeakVirtualSize)
+                        pvmi.PeakWorkingSetSize = pvmi.PeakVirtualSize;
+                    if (pvmi.WorkingSetSize > pvmi.VirtualSize)
+                        pvmi.WorkingSetSize = pvmi.VirtualSize;
+                    if (pvmi.PagefileUsage > pvmi.VirtualSize)
+                        pvmi.PagefileUsage = pvmi.VirtualSize;
+                    if (pvmi.PeakPagefileUsage > pvmi.PeakVirtualSize)
+                        pvmi.PeakPagefileUsage = pvmi.PeakVirtualSize;
 
                     len = ProcessInformationLength;
                     if (len != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) len = sizeof(VM_COUNTERS);
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 4198d9c..5e42045 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -1135,7 +1135,7 @@ static void test_query_process_vm(void)
     ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
     if (winetest_debug > 1)
         dump_vm_counters("VM counters after VirtualAlloc", &pvi);
-    todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size,
+    ok( pvi.VirtualSize >= prev_size + alloc_size,
         "Expected to be greater than %lu, got %lu\n", prev_size + alloc_size, pvi.VirtualSize);
     VirtualFree( ptr, 0, MEM_RELEASE);
 }
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index e826fa0..d19d31b 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -108,6 +108,10 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
       0, 0, { (DWORD_PTR)(__FILE__ ": csVirtual") }
 };
 static RTL_CRITICAL_SECTION csVirtual = { &critsect_debug, -1, 0, 0, 0, 0 };
+static struct {
+    SIZE_T size;
+    SIZE_T peak;
+} vm_counters;
 
 #ifdef __i386__
 static const UINT page_shift = 12;
@@ -438,7 +442,13 @@ static inline void unmap_area( void *addr, size_t size )
  */
 static void delete_view( struct file_view *view ) /* [in] View */
 {
-    if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size );
+    if (!(view->protect & VPROT_SYSTEM))
+    {
+        unmap_area( view->base, view->size );
+
+        /* Decrement VM counters */
+        vm_counters.size -= view->size;
+    }
     list_remove( &view->entry );
     if (view->mapping) close_handle( view->mapping );
     RtlFreeHeap( virtual_heap, 0, view );
@@ -512,6 +522,15 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz
         }
     }
 
+    /* Increment VM counters */
+
+    if (!(vprot & VPROT_SYSTEM))
+    {
+        vm_counters.size += size;
+        if (vm_counters.peak < vm_counters.size)
+            vm_counters.peak = vm_counters.size;
+    }
+
     *view_ret = view;
     VIRTUAL_DEBUG_DUMP_VIEW( view );
 
@@ -1385,6 +1404,26 @@ void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info )
 
 
 /***********************************************************************
+ *           virtual_get_memory_counters
+ */
+void virtual_get_memory_counters( SIZE_T *current, SIZE_T *peak )
+{
+    sigset_t sigset;
+    server_enter_uninterrupted_section( &csVirtual, &sigset );
+
+    *current = min(vm_counters.size, (SIZE_T)user_space_limit);
+    *peak    = min(vm_counters.peak, (SIZE_T)user_space_limit);
+
+    server_leave_uninterrupted_section( &csVirtual, &sigset );
+
+    TRACE("current=%s, peak=%s\n",
+          wine_dbgstr_longlong((ULONGLONG)*current),
+          wine_dbgstr_longlong((ULONGLONG)*peak));
+
+}
+
+
+/***********************************************************************
  *           virtual_create_builtin_view
  */
 NTSTATUS virtual_create_builtin_view( void *module )
-- 
2.7.4





More information about the wine-patches mailing list