Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Relax ullAvailPageFile check a bit, it's not always synced.
dlls/kernel32/tests/heap.c | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index c597ff9590b..fc4ece81e00 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1264,6 +1264,67 @@ static void test_GlobalMemoryStatus(void) wine_dbgstr_longlong(mem.dwAvailVirtual), wine_dbgstr_longlong(memex.ullAvailVirtual)); }
+static void test_GlobalMemoryStatusEx(void) +{ + char buffer[sizeof(SYSTEM_PERFORMANCE_INFORMATION) + 16]; /* some Win 7 versions need a larger info */ + SYSTEM_PERFORMANCE_INFORMATION *perf_info = (void *)buffer; + SYSTEM_BASIC_INFORMATION basic_info; + MEMORYSTATUSEX memex = {0}, expect; + VM_COUNTERS_EX vmc; + NTSTATUS status; + BOOL ret; + + SetLastError( 0xdeadbeef ); + ret = GlobalMemoryStatusEx( &memex ); + ok( !ret, "GlobalMemoryStatusEx succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + do + { + status = NtQuerySystemInformation( SystemBasicInformation, &basic_info, sizeof(basic_info), NULL ); + ok( !status, "NtQuerySystemInformation returned %#lx\n", status ); + status = NtQuerySystemInformation( SystemPerformanceInformation, perf_info, sizeof(buffer), NULL ); + ok( !status, "NtQuerySystemInformation returned %#lx\n", status ); + status = NtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), NULL ); + ok( !status, "NtQueryInformationProcess returned %#lx\n", status ); + memex.dwLength = sizeof(MEMORYSTATUSEX); + ret = GlobalMemoryStatusEx( &memex ); + ok( ret, "GlobalMemoryStatusEx succeeded\n" ); + } while (memex.ullAvailPhys != (ULONGLONG)perf_info->AvailablePages * basic_info.PageSize); + + ok( basic_info.PageSize, "got 0 PageSize\n" ); + ok( basic_info.MmNumberOfPhysicalPages, "got 0 MmNumberOfPhysicalPages\n" ); + ok( !!basic_info.HighestUserAddress, "got 0 HighestUserAddress\n" ); + ok( !!basic_info.LowestUserAddress, "got 0 LowestUserAddress\n" ); + ok( perf_info->TotalCommittedPages, "got 0 TotalCommittedPages\n" ); + ok( perf_info->TotalCommitLimit, "got 0 TotalCommitLimit\n" ); + ok( perf_info->AvailablePages, "got 0 AvailablePages\n" ); + + expect.dwMemoryLoad = (memex.ullTotalPhys - memex.ullAvailPhys) / (memex.ullTotalPhys / 100); + expect.ullTotalPhys = (ULONGLONG)basic_info.MmNumberOfPhysicalPages * basic_info.PageSize; + expect.ullAvailPhys = (ULONGLONG)perf_info->AvailablePages * basic_info.PageSize; + expect.ullTotalPageFile = (ULONGLONG)perf_info->TotalCommitLimit * basic_info.PageSize; + expect.ullAvailPageFile = (ULONGLONG)(perf_info->TotalCommitLimit - perf_info->TotalCommittedPages) * basic_info.PageSize; + expect.ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress + 1; + expect.ullAvailVirtual = expect.ullTotalVirtual - (ULONGLONG)vmc.WorkingSetSize /* approximate */; + expect.ullAvailExtendedVirtual = 0; + + ok( memex.dwMemoryLoad == expect.dwMemoryLoad, "got dwMemoryLoad %lu\n", memex.dwMemoryLoad ); + todo_wine + ok( memex.ullTotalPhys == expect.ullTotalPhys, "got ullTotalPhys %#I64x\n", memex.ullTotalPhys ); + ok( memex.ullAvailPhys == expect.ullAvailPhys, "got ullAvailPhys %#I64x\n", memex.ullAvailPhys ); + todo_wine + ok( memex.ullTotalPageFile == expect.ullTotalPageFile, "got ullTotalPageFile %#I64x\n", memex.ullTotalPageFile ); + /* allow some variability, page file is not always in sync on Windows */ + ok( memex.ullAvailPageFile - expect.ullAvailPageFile + 32 * basic_info.PageSize <= 64 * basic_info.PageSize, + "got ullAvailPageFile %#I64x\n", memex.ullAvailPageFile ); + todo_wine + ok( memex.ullTotalVirtual == expect.ullTotalVirtual, "got ullTotalVirtual %#I64x\n", memex.ullTotalVirtual ); + todo_wine + ok( memex.ullAvailVirtual <= expect.ullAvailVirtual, "got ullAvailVirtual %#I64x\n", memex.ullAvailVirtual ); + ok( memex.ullAvailExtendedVirtual == 0, "got ullAvailExtendedVirtual %#I64x\n", memex.ullAvailExtendedVirtual ); +} + START_TEST(heap) { int argc; @@ -1298,6 +1359,7 @@ START_TEST(heap) test_HeapQueryInformation(); test_GetPhysicallyInstalledSystemMemory(); test_GlobalMemoryStatus(); + test_GlobalMemoryStatusEx();
if (pRtlGetNtGlobalFlags) {
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/tests/heap.c | 72 ++++++++++---------------------------- 1 file changed, 19 insertions(+), 53 deletions(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index fc4ece81e00..c36d9331bef 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1213,63 +1213,13 @@ static void test_GetPhysicallyInstalledSystemMemory(void) "expected total_memory >= memstatus.ullTotalPhys / 1024\n"); }
-static BOOL compare_ulong64(ULONG64 v1, ULONG64 v2, ULONG64 max_diff) -{ - ULONG64 diff = v1 > v2 ? v1 - v2 : v2 - v1; - - return diff <= max_diff; -} - static void test_GlobalMemoryStatus(void) -{ - static const ULONG64 max_diff = 0x200000; - SIZE_T size, size_broken; - MEMORYSTATUSEX memex; - MEMORYSTATUS mem; - - mem.dwLength = sizeof(mem); - GlobalMemoryStatus(&mem); - memex.dwLength = sizeof(memex); - GlobalMemoryStatusEx(&memex); - - /* Compare values approximately as the available memory may change between - * GlobalMemoryStatus() and GlobalMemoryStatusEx() calls. */ - - size = min(memex.ullTotalPhys, ~(SIZE_T)0 >> 1); - size_broken = min(memex.ullTotalPhys, ~(SIZE_T)0); - ok(compare_ulong64(mem.dwTotalPhys, size, max_diff) - || broken(compare_ulong64(mem.dwTotalPhys, size_broken, max_diff)) /* Win <= 8.1 with RAM size > 4GB */, - "Got unexpected dwTotalPhys %s, size %s.\n", - wine_dbgstr_longlong(mem.dwTotalPhys), wine_dbgstr_longlong(size)); - size = min(memex.ullAvailPhys, ~(SIZE_T)0 >> 1); - size_broken = min(memex.ullAvailPhys, ~(SIZE_T)0); - ok(compare_ulong64(mem.dwAvailPhys, size, max_diff) - || broken(compare_ulong64(mem.dwAvailPhys, size_broken, max_diff)) /* Win <= 8.1 with RAM size > 4GB */, - "Got unexpected dwAvailPhys %s, size %s.\n", - wine_dbgstr_longlong(mem.dwAvailPhys), wine_dbgstr_longlong(size)); - - size = min(memex.ullTotalPageFile, ~(SIZE_T)0); - ok(compare_ulong64(mem.dwTotalPageFile, size, max_diff), - "Got unexpected dwTotalPageFile %s, size %s.\n", - wine_dbgstr_longlong(mem.dwTotalPageFile), wine_dbgstr_longlong(size)); - size = min(memex.ullAvailPageFile, ~(SIZE_T)0); - ok(compare_ulong64(mem.dwAvailPageFile, size, max_diff), "Got unexpected dwAvailPageFile %s, size %s.\n", - wine_dbgstr_longlong(mem.dwAvailPageFile), wine_dbgstr_longlong(size)); - - ok(compare_ulong64(mem.dwTotalVirtual, memex.ullTotalVirtual, max_diff), - "Got unexpected dwTotalVirtual %s, ullTotalVirtual %s.\n", - wine_dbgstr_longlong(mem.dwTotalVirtual), wine_dbgstr_longlong(memex.ullTotalVirtual)); - ok(compare_ulong64(mem.dwAvailVirtual, memex.ullAvailVirtual, max_diff), - "Got unexpected dwAvailVirtual %s, ullAvailVirtual %s.\n", - wine_dbgstr_longlong(mem.dwAvailVirtual), wine_dbgstr_longlong(memex.ullAvailVirtual)); -} - -static void test_GlobalMemoryStatusEx(void) { char buffer[sizeof(SYSTEM_PERFORMANCE_INFORMATION) + 16]; /* some Win 7 versions need a larger info */ SYSTEM_PERFORMANCE_INFORMATION *perf_info = (void *)buffer; SYSTEM_BASIC_INFORMATION basic_info; MEMORYSTATUSEX memex = {0}, expect; + MEMORYSTATUS mem = {0}; VM_COUNTERS_EX vmc; NTSTATUS status; BOOL ret; @@ -1278,6 +1228,9 @@ static void test_GlobalMemoryStatusEx(void) ret = GlobalMemoryStatusEx( &memex ); ok( !ret, "GlobalMemoryStatusEx succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + GlobalMemoryStatus( &mem ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() );
do { @@ -1287,10 +1240,13 @@ static void test_GlobalMemoryStatusEx(void) ok( !status, "NtQuerySystemInformation returned %#lx\n", status ); status = NtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), NULL ); ok( !status, "NtQueryInformationProcess returned %#lx\n", status ); + mem.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus( &mem ); memex.dwLength = sizeof(MEMORYSTATUSEX); ret = GlobalMemoryStatusEx( &memex ); ok( ret, "GlobalMemoryStatusEx succeeded\n" ); - } while (memex.ullAvailPhys != (ULONGLONG)perf_info->AvailablePages * basic_info.PageSize); + } while (memex.ullAvailPhys != (ULONGLONG)perf_info->AvailablePages * basic_info.PageSize || + mem.dwAvailPhys != min( ~(SIZE_T)0 >> 1, memex.ullAvailPhys ));
ok( basic_info.PageSize, "got 0 PageSize\n" ); ok( basic_info.MmNumberOfPhysicalPages, "got 0 MmNumberOfPhysicalPages\n" ); @@ -1323,6 +1279,17 @@ static void test_GlobalMemoryStatusEx(void) todo_wine ok( memex.ullAvailVirtual <= expect.ullAvailVirtual, "got ullAvailVirtual %#I64x\n", memex.ullAvailVirtual ); ok( memex.ullAvailExtendedVirtual == 0, "got ullAvailExtendedVirtual %#I64x\n", memex.ullAvailExtendedVirtual ); + + ok( mem.dwMemoryLoad == memex.dwMemoryLoad, "got dwMemoryLoad %lu\n", mem.dwMemoryLoad ); + ok( mem.dwTotalPhys == min( ~(SIZE_T)0 >> 1, memex.ullTotalPhys ), "got dwTotalPhys %#Ix\n", mem.dwTotalPhys ); + ok( mem.dwAvailPhys == min( ~(SIZE_T)0 >> 1, memex.ullAvailPhys ), "got dwAvailPhys %#Ix\n", mem.dwAvailPhys ); +#ifndef _WIN64 + todo_wine_if(memex.ullTotalPageFile > 0xfff7ffff) +#endif + ok( mem.dwTotalPageFile == min( ~(SIZE_T)0, memex.ullTotalPageFile ), "got dwTotalPageFile %#Ix\n", mem.dwTotalPageFile ); + ok( mem.dwAvailPageFile == min( ~(SIZE_T)0, memex.ullAvailPageFile ), "got dwAvailPageFile %#Ix\n", mem.dwAvailPageFile ); + ok( mem.dwTotalVirtual == memex.ullTotalVirtual, "got dwTotalVirtual %#Ix\n", mem.dwTotalVirtual ); + ok( mem.dwAvailVirtual == memex.ullAvailVirtual, "got dwAvailVirtual %#Ix\n", mem.dwAvailVirtual ); }
START_TEST(heap) @@ -1359,7 +1326,6 @@ START_TEST(heap) test_HeapQueryInformation(); test_GetPhysicallyInstalledSystemMemory(); test_GlobalMemoryStatus(); - test_GlobalMemoryStatusEx();
if (pRtlGetNtGlobalFlags) {
On Fri, 25 Mar 2022, Rémi Bernon wrote: [...]
- size = min(memex.ullTotalPhys, ~(SIZE_T)0 >> 1);
- size_broken = min(memex.ullTotalPhys, ~(SIZE_T)0);
- ok(compare_ulong64(mem.dwTotalPhys, size, max_diff)
|| broken(compare_ulong64(mem.dwTotalPhys, size_broken, max_diff)) /* Win <= 8.1 with RAM size > 4GB */,
You've lost this broken() case in a couple of places which causes the tests to fail on the cw-gtx560 and cw-rx460 machines. That's because they have 16 GB of memory (> 4 GB) and in that case Windows 8.1 (<= Win <= 8.1) returns -1 (~(SIZE_T)0).
https://test.winehq.org/data/patterns.html#kernel32:heap
On 4/5/22 00:01, Francois Gouget wrote:
On Fri, 25 Mar 2022, Rémi Bernon wrote: [...]
- size = min(memex.ullTotalPhys, ~(SIZE_T)0 >> 1);
- size_broken = min(memex.ullTotalPhys, ~(SIZE_T)0);
- ok(compare_ulong64(mem.dwTotalPhys, size, max_diff)
|| broken(compare_ulong64(mem.dwTotalPhys, size_broken, max_diff)) /* Win <= 8.1 with RAM size > 4GB */,
You've lost this broken() case in a couple of places which causes the tests to fail on the cw-gtx560 and cw-rx460 machines. That's because they have 16 GB of memory (> 4 GB) and in that case Windows 8.1 (<= Win <= 8.1) returns -1 (~(SIZE_T)0).
Thanks! I believe I actually tried a local Win8.1 VM with > 4GB and didn't get the same results, so I thought it was an old broken result. I'll add it back.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/tests/heap.c | 4 ---- dlls/kernelbase/memory.c | 13 ++++++++----- dlls/ntdll/unix/system.c | 4 ++++ 3 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index c36d9331bef..6efe4da4634 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1266,17 +1266,13 @@ static void test_GlobalMemoryStatus(void) expect.ullAvailExtendedVirtual = 0;
ok( memex.dwMemoryLoad == expect.dwMemoryLoad, "got dwMemoryLoad %lu\n", memex.dwMemoryLoad ); - todo_wine ok( memex.ullTotalPhys == expect.ullTotalPhys, "got ullTotalPhys %#I64x\n", memex.ullTotalPhys ); ok( memex.ullAvailPhys == expect.ullAvailPhys, "got ullAvailPhys %#I64x\n", memex.ullAvailPhys ); - todo_wine ok( memex.ullTotalPageFile == expect.ullTotalPageFile, "got ullTotalPageFile %#I64x\n", memex.ullTotalPageFile ); /* allow some variability, page file is not always in sync on Windows */ ok( memex.ullAvailPageFile - expect.ullAvailPageFile + 32 * basic_info.PageSize <= 64 * basic_info.PageSize, "got ullAvailPageFile %#I64x\n", memex.ullAvailPageFile ); - todo_wine ok( memex.ullTotalVirtual == expect.ullTotalVirtual, "got ullTotalVirtual %#I64x\n", memex.ullTotalVirtual ); - todo_wine ok( memex.ullAvailVirtual <= expect.ullAvailVirtual, "got ullAvailVirtual %#I64x\n", memex.ullAvailVirtual ); ok( memex.ullAvailExtendedVirtual == 0, "got ullAvailExtendedVirtual %#I64x\n", memex.ullAvailExtendedVirtual );
diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 29e1999fe6b..42ffd1bcdd9 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -1043,6 +1043,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GlobalMemoryStatusEx( MEMORYSTATUSEX *status ) static DWORD last_check; SYSTEM_BASIC_INFORMATION basic_info; SYSTEM_PERFORMANCE_INFORMATION perf_info; + VM_COUNTERS_EX vmc;
if (status->dwLength != sizeof(*status)) { @@ -1059,16 +1060,18 @@ BOOL WINAPI DECLSPEC_HOTPATCH GlobalMemoryStatusEx( MEMORYSTATUSEX *status ) if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation, &basic_info, sizeof(basic_info), NULL )) || !set_ntstatus( NtQuerySystemInformation( SystemPerformanceInformation, - &perf_info, sizeof(perf_info), NULL))) + &perf_info, sizeof(perf_info), NULL)) || + !set_ntstatus( NtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, + &vmc, sizeof(vmc), NULL ))) return FALSE;
status->dwMemoryLoad = 0; - status->ullTotalPhys = perf_info.TotalCommitLimit; + status->ullTotalPhys = basic_info.MmNumberOfPhysicalPages; status->ullAvailPhys = perf_info.AvailablePages; - status->ullTotalPageFile = perf_info.TotalCommitLimit + 1; /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */ + status->ullTotalPageFile = perf_info.TotalCommitLimit; status->ullAvailPageFile = status->ullTotalPageFile - perf_info.TotalCommittedPages; - status->ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress; - status->ullAvailVirtual = status->ullTotalVirtual - 64 * 1024; /* FIXME */ + status->ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress + 1; + status->ullAvailVirtual = status->ullTotalVirtual - (ULONGLONG)vmc.WorkingSetSize /* approximate */; status->ullAvailExtendedVirtual = 0;
status->ullTotalPhys *= basic_info.PageSize; diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 4052d28f644..65c49b6ccd1 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -2008,6 +2008,10 @@ static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info ) #endif } #endif + + /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */ + if (!totalswap) totalswap = page_size; + info->AvailablePages = freeram / page_size; info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size; info->TotalCommitLimit = (totalram + totalswap) / page_size;