| /* |
| * Copyright (c) 2023 Red Hat Inc. All rights reserved. |
| * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "runtime/os.hpp" |
| #include "runtime/trimNativeHeap.hpp" |
| #include "utilities/globalDefinitions.hpp" |
| #include "utilities/ostream.hpp" |
| #include "testutils.hpp" |
| #include "unittest.hpp" |
| |
| using ::testing::HasSubstr; |
| |
| // Check the state of the trimmer via print_state; returns the suspend count |
| static int check_trim_state() { |
| char buf [1024]; |
| stringStream ss(buf, sizeof(buf)); |
| NativeHeapTrimmer::print_state(&ss); |
| if (NativeHeapTrimmer::enabled()) { |
| assert(TrimNativeHeapInterval > 0, "Sanity"); |
| EXPECT_THAT(buf, HasSubstr("Periodic native trim enabled")); |
| |
| const char* s = ::strstr(buf, "Trims performed"); |
| EXPECT_NOT_NULL(s); |
| |
| uint64_t num_trims = 0; |
| int suspend_count = 0; |
| int stopped = 0; |
| EXPECT_EQ(::sscanf(s, "Trims performed: " UINT64_FORMAT ", current suspend count: %d, stopped: %d", |
| &num_trims, &suspend_count, &stopped), 3); |
| |
| // Number of trims we can reasonably expect should be limited |
| const double fudge_factor = 1.5; |
| const uint64_t elapsed_ms = (uint64_t)(os::elapsedTime() * fudge_factor * 1000.0); |
| const uint64_t max_num_trims = (elapsed_ms / TrimNativeHeapInterval) + 1; |
| EXPECT_LE(num_trims, max_num_trims); |
| |
| // We should not be stopped |
| EXPECT_EQ(stopped, 0); |
| |
| // Suspend count must not underflow |
| EXPECT_GE(suspend_count, 0); |
| return suspend_count; |
| |
| } else { |
| EXPECT_THAT(buf, HasSubstr("Periodic native trim disabled")); |
| EXPECT_THAT(buf, Not(HasSubstr("Trims performed"))); |
| return 0; |
| } |
| } |
| |
| TEST_VM(os, TrimNative) { |
| |
| if (!NativeHeapTrimmer::enabled()) { |
| return; |
| } |
| |
| // Try recursive pausing. This tests that we are able to pause, that pauses stack, |
| // and that stacking works within the same thread. |
| int c1 = 0, c2 = 0, c3 = 0; |
| { |
| NativeHeapTrimmer::SuspendMark sm1("Test1"); |
| c1 = check_trim_state(); |
| { |
| NativeHeapTrimmer::SuspendMark sm2("Test2"); |
| c2 = check_trim_state(); |
| { |
| NativeHeapTrimmer::SuspendMark sm3("Test3"); |
| c3 = check_trim_state(); |
| } |
| } |
| } |
| // We also check the state: the suspend count should go up. But since we don't know |
| // whether concurrent code will have increased the suspend count too, this is fuzzy and |
| // we must avoid intermittent false positives. |
| EXPECT_GT(c2, c1); |
| EXPECT_GT(c3, c2); |
| } |