diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1fb2a248bec..1eee76b4667 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -167,11 +167,11 @@ void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool che } } -bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { +bool os::first_resident_in_range(address start, size_t size, address& resident_start, size_t& resident_size) { #ifdef _AIX - committed_start = start; - committed_size = size; + resident_start = start; + resident_size = size; return true; #else @@ -188,10 +188,10 @@ bool os::committed_in_range(address start, size_t size, address& committed_start assert(is_aligned(start, page_sz), "Start address must be page aligned"); assert(is_aligned(size, page_sz), "Size must be page aligned"); - committed_start = nullptr; + resident_start = nullptr; int loops = checked_cast((pages + stripe - 1) / stripe); - int committed_pages = 0; + int resident_pages = 0; address loop_base = start; bool found_range = false; @@ -210,7 +210,7 @@ bool os::committed_in_range(address start, size_t size, address& committed_start // During shutdown, some memory goes away without properly notifying NMT, // E.g. ConcurrentGCThread/WatcherThread can exit without deleting thread object. - // Bailout and return as not committed for now. + // Bailout and return as not resident for now. if (mincore_return_value == -1 && errno == ENOMEM) { return false; } @@ -224,32 +224,32 @@ bool os::committed_in_range(address start, size_t size, address& committed_start assert(mincore_return_value == 0, "Range must be valid"); // Process this stripe for (uintx vecIdx = 0; vecIdx < pages_to_query; vecIdx ++) { - if ((vec[vecIdx] & 0x01) == 0) { // not committed + if ((vec[vecIdx] & 0x01) == 0) { // not resident // End of current contiguous region - if (committed_start != nullptr) { + if (resident_start != nullptr) { found_range = true; break; } - } else { // committed + } else { // resident // Start of region - if (committed_start == nullptr) { - committed_start = loop_base + page_sz * vecIdx; + if (resident_start == nullptr) { + resident_start = loop_base + page_sz * vecIdx; } - committed_pages ++; + resident_pages ++; } } loop_base += pages_to_query * page_sz; } - if (committed_start != nullptr) { - assert(committed_pages > 0, "Must have committed region"); - assert(committed_pages <= int(size / page_sz), "Can not commit more than it has"); - assert(committed_start >= start && committed_start < start + size, "Out of range"); - committed_size = page_sz * committed_pages; + if (resident_start != nullptr) { + assert(resident_pages > 0, "Must have a resident region"); + assert(resident_pages <= int(size / page_sz), "Resident size exceeds region size"); + assert(resident_start >= start && resident_start < start + size, "Out of range"); + resident_size = page_sz * resident_pages; return true; } else { - assert(committed_pages == 0, "Should not have committed region"); + assert(resident_pages == 0, "Should not have a resident region"); return false; } #endif diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 9a987bf3762..9137723fa58 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -465,36 +465,63 @@ void os::current_stack_base_and_size(address* stack_base, size_t* stack_size) { *stack_size = size; } -bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { - MEMORY_BASIC_INFORMATION minfo; - committed_start = nullptr; - committed_size = 0; - address top = start + size; - const address start_addr = start; - while (start < top) { - VirtualQuery(start, &minfo, sizeof(minfo)); - if ((minfo.State & MEM_COMMIT) == 0) { // not committed - if (committed_start != nullptr) { - break; - } - } else { // committed - if (committed_start == nullptr) { - committed_start = start; - } - size_t offset = start - (address)minfo.BaseAddress; - committed_size += minfo.RegionSize - offset; - } - start = (address)minfo.BaseAddress + minfo.RegionSize; - } +bool os::first_resident_in_range(address start, size_t size, address& resident_start, size_t& resident_size) { + constexpr size_t stripe = 1024; // query this many pages each time + PSAPI_WORKING_SET_EX_INFORMATION wsinfo[stripe]; - if (committed_start == nullptr) { - assert(committed_size == 0, "Sanity"); - return false; - } else { - assert(committed_start >= start_addr && committed_start < top, "Out of range"); - // current region may go beyond the limit, trim to the limit - committed_size = MIN2(committed_size, size_t(top - committed_start)); + size_t page_sz = os::vm_page_size(); + uintx pages_left = size / page_sz; + + assert(is_aligned(start, page_sz), "Start address must be page aligned"); + assert(is_aligned(size, page_sz), "Size must be page aligned"); + + resident_start = nullptr; + + uintx loops = (pages_left + stripe - 1) / stripe; + uintx resident_pages = 0; + address pos = start; + bool found_range = false; + + for (uintx index = 0; index < loops && !found_range; index++) { + assert(pages_left > 0, "Nothing to do"); + uintx pages_to_query = MIN2(pages_left, stripe); + pages_left -= pages_to_query; + + for (uintx i = 0; i < pages_to_query; i++) { + wsinfo[i].VirtualAddress = (PVOID)(pos + i * page_sz); + } + + BOOL success = QueryWorkingSetEx(GetCurrentProcess(), wsinfo, pages_to_query * sizeof(PSAPI_WORKING_SET_EX_INFORMATION)); + if (!success) { + return false; + } + + for (uintx i = 0; i < pages_to_query; i++) { + if (wsinfo[i].VirtualAttributes.Valid == 0) { + if (resident_start != nullptr) { + found_range = true; + break; + } + // Still searching for start of resident region + } else { + if (resident_start == nullptr) { + // Found first resident page in region + resident_start = pos + i * page_sz; + } + resident_pages++; + } + } + pos += pages_to_query * page_sz; + } + if (resident_start != nullptr) { + assert(resident_pages > 0, "Must have a resident region"); + assert(resident_pages <= size / page_sz, "Resident size exceeds region size"); + assert(resident_start >= start && resident_start < start + size, "Out of range"); + resident_size = page_sz * resident_pages; return true; + } else { + assert(resident_pages == 0, "Should not have a resident region"); + return false; } } diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index dc68664f34f..e23076a12bf 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -283,7 +283,7 @@ bool RegionIterator::next_committed(address& committed_start, size_t& committed_ const size_t page_sz = os::vm_page_size(); const size_t current_size = end() - _current_start; - if (os::committed_in_range(_current_start, current_size, committed_start, committed_size)) { + if (os::first_resident_in_range(_current_start, current_size, committed_start, committed_size)) { assert(committed_start != nullptr, "Must be"); assert(committed_size > 0 && is_aligned(committed_size, os::vm_page_size()), "Must be"); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index f6c7f03778b..10a8dd6f858 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -440,9 +440,9 @@ class os: AllStatic { public: // get allowed minimum java stack size static jlong get_minimum_java_stack_size(); - // Find committed memory region within specified range (start, start + size), - // return true if found any - static bool committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size); + // Find the first resident memory region within the specified range (start, start + size) beginning at the start address. + // Returns true if successful or false if none are found. + static bool first_resident_in_range(address start, size_t size, address& resident_start, size_t& resident_size); // OS interface to Virtual Memory diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index 8cf62fb9ea5..5d475d2f955 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -169,8 +169,8 @@ public: static void test_partial_region() { bool result; - size_t committed_size; - address committed_start; + size_t resident_size; + address resident_start; size_t index; const size_t page_sz = os::vm_page_size(); @@ -187,36 +187,36 @@ public: } // Test whole range - result = os::committed_in_range((address)base, size, committed_start, committed_size); + result = os::first_resident_in_range((address)base, size, resident_start, resident_size); ASSERT_TRUE(result); - ASSERT_EQ(num_pages * page_sz, committed_size); - ASSERT_EQ(committed_start, (address)base); + ASSERT_EQ(num_pages * page_sz, resident_size); + ASSERT_EQ(resident_start, (address)base); // Test beginning of the range - result = os::committed_in_range((address)base, 2 * page_sz, committed_start, committed_size); + result = os::first_resident_in_range((address)base, 2 * page_sz, resident_start, resident_size); ASSERT_TRUE(result); - ASSERT_EQ(2 * page_sz, committed_size); - ASSERT_EQ(committed_start, (address)base); + ASSERT_EQ(2 * page_sz, resident_size); + ASSERT_EQ(resident_start, (address)base); // Test end of the range - result = os::committed_in_range((address)(base + page_sz), 3 * page_sz, committed_start, committed_size); + result = os::first_resident_in_range((address)(base + page_sz), 3 * page_sz, resident_start, resident_size); ASSERT_TRUE(result); - ASSERT_EQ(3 * page_sz, committed_size); - ASSERT_EQ(committed_start, (address)(base + page_sz)); + ASSERT_EQ(3 * page_sz, resident_size); + ASSERT_EQ(resident_start, (address)(base + page_sz)); // Test middle of the range - result = os::committed_in_range((address)(base + page_sz), 2 * page_sz, committed_start, committed_size); + result = os::first_resident_in_range((address)(base + page_sz), 2 * page_sz, resident_start, resident_size); ASSERT_TRUE(result); - ASSERT_EQ(2 * page_sz, committed_size); - ASSERT_EQ(committed_start, (address)(base + page_sz)); + ASSERT_EQ(2 * page_sz, resident_size); + ASSERT_EQ(resident_start, (address)(base + page_sz)); os::release_memory(base, size); } - static void test_committed_in_range(size_t num_pages, size_t pages_to_touch) { + static void test_first_resident_in_range(size_t num_pages, size_t pages_to_touch) { bool result; - size_t committed_size; - address committed_start; + size_t resident_size; + address resident_start; size_t index; const size_t page_sz = os::vm_page_size(); @@ -228,7 +228,7 @@ public: result = os::commit_memory(base, size, !ExecMem); ASSERT_TRUE(result); - result = os::committed_in_range((address)base, size, committed_start, committed_size); + result = os::first_resident_in_range((address)base, size, resident_start, resident_size); ASSERT_FALSE(result); // Touch pages @@ -236,14 +236,14 @@ public: base[index * page_sz] = 'a'; } - result = os::committed_in_range((address)base, size, committed_start, committed_size); + result = os::first_resident_in_range((address)base, size, resident_start, resident_size); ASSERT_TRUE(result); - ASSERT_EQ(pages_to_touch * page_sz, committed_size); - ASSERT_EQ(committed_start, (address)base); + ASSERT_EQ(pages_to_touch * page_sz, resident_size); + ASSERT_EQ(resident_start, (address)base); os::uncommit_memory(base, size, false); - result = os::committed_in_range((address)base, size, committed_start, committed_size); + result = os::first_resident_in_range((address)base, size, resident_start, resident_size); ASSERT_FALSE(result); os::release_memory(base, size); @@ -266,9 +266,9 @@ TEST_VM(NMTCommittedVirtualMemoryTracker, test_committed_virtualmemory_region) { } -#if !defined(_WINDOWS) && !defined(_AIX) -TEST_VM(NMTCommittedVirtualMemory, test_committed_in_range){ - CommittedVirtualMemoryTest::test_committed_in_range(1024, 1024); - CommittedVirtualMemoryTest::test_committed_in_range(2, 1); +#if !defined(_AIX) +TEST_VM(NMTCommittedVirtualMemory, test_first_resident_in_range){ + CommittedVirtualMemoryTest::test_first_resident_in_range(1024, 1024); + CommittedVirtualMemoryTest::test_first_resident_in_range(2, 1); } #endif