jdk-24/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp
Gerard Ziemski eabfc6e4d9 8337563: NMT: rename MEMFLAGS to MemTag
Reviewed-by: dholmes, coleenp, jsjolen
2024-09-17 19:59:06 +00:00

159 lines
6.0 KiB
C++

/*
* Copyright (c) 2023 SAP SE. All rights reserved.
* Copyright (c) 2023, 2024, 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 "precompiled.hpp"
#include "memory/allocation.hpp"
#include "nmt/mallocLimit.hpp"
#include "nmt/memTracker.hpp"
#include "nmt/nmtCommon.hpp"
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
#include "testutils.hpp"
#include "unittest.hpp"
// Tests here just test the MallocLimit option parser. They are complemented
// by more extensive jtreg tests (runtime/NMT/TestMallocLimit.java)
static bool compare_limits(const malloclimit* a, const malloclimit* b) {
return a->sz == b->sz && a->mode == b->mode;
}
static bool compare_sets(const MallocLimitSet* a, const MallocLimitSet* b) {
if (compare_limits(a->global_limit(), b->global_limit())) {
for (int i = 0; i < mt_number_of_tags; i++) {
if (!compare_limits(a->category_limit(NMTUtil::index_to_tag(i)),
b->category_limit(NMTUtil::index_to_tag(i)))) {
return false;
}
}
}
return true;
}
static void test(const char* s, const MallocLimitSet& expected) {
MallocLimitSet set;
const char* err;
EXPECT_TRUE(set.parse_malloclimit_option(s, &err)) << err;
EXPECT_TRUE(compare_sets(&set, &expected));
}
TEST(NMT, MallocLimitBasics) {
MallocLimitSet expected;
expected.set_global_limit(1 * G, MallocLimitMode::trigger_fatal);
test("1g", expected);
test("1024m", expected);
test("1048576k", expected);
test("1073741824", expected);
// Fatal is default, but can be specified explicitely
test("1g:fatal", expected);
expected.set_global_limit(2 * M, MallocLimitMode::trigger_oom);
test("2m:oom", expected);
test("2m:OOM", expected);
test("2048k:oom", expected);
}
TEST(NMT, MallocLimitPerCategory) {
MallocLimitSet expected;
expected.set_category_limit(mtMetaspace, 1 * M, MallocLimitMode::trigger_fatal);
test("metaspace:1m", expected);
test("metaspace:1m:fatal", expected);
test("METASPACE:1m", expected);
expected.set_category_limit(mtCompiler, 2 * M, MallocLimitMode::trigger_oom);
expected.set_category_limit(mtThread, 3 * M, MallocLimitMode::trigger_oom);
expected.set_category_limit(mtThreadStack, 4 * M, MallocLimitMode::trigger_oom);
expected.set_category_limit(mtClass, 5 * M, MallocLimitMode::trigger_fatal);
expected.set_category_limit(mtClassShared, 6 * M, MallocLimitMode::trigger_fatal);
test("metaspace:1m,compiler:2m:oom,thread:3m:oom,threadstack:4m:oom,class:5m,classshared:6m", expected);
}
TEST(NMT, MallocLimitCategoryEnumNames) {
MallocLimitSet expected;
stringStream option;
for (int i = 0; i < mt_number_of_tags; i++) {
MemTag mem_tag = NMTUtil::index_to_tag(i);
if (mem_tag != MemTag::mtNone) {
expected.set_category_limit(mem_tag, (i + 1) * M, MallocLimitMode::trigger_fatal);
option.print("%s%s:%dM", (i > 0 ? "," : ""), NMTUtil::tag_to_enum_name(mem_tag), i + 1);
}
}
test(option.base(), expected);
}
TEST(NMT, MallocLimitAllCategoriesHaveHumanReadableNames) {
MallocLimitSet expected;
stringStream option;
for (int i = 0; i < mt_number_of_tags; i++) {
MemTag mem_tag = NMTUtil::index_to_tag(i);
if (mem_tag != MemTag::mtNone) {
expected.set_category_limit(mem_tag, (i + 1) * M, MallocLimitMode::trigger_fatal);
option.print("%s%s:%dM", (i > 0 ? "," : ""), NMTUtil::tag_to_name(mem_tag), i + 1);
}
}
test(option.base(), expected);
}
static void test_failing(const char* s) {
MallocLimitSet set;
const char* err;
ASSERT_FALSE(set.parse_malloclimit_option(s, &err));
}
TEST(NMT, MallocLimitBadOptions) {
test_failing("abcd");
test_failing("compiler:1g:");
test_failing("compiler:1g:oom:mtTest:asas:1m");
}
// Death tests.
// Majority of MallocLimit functional tests are done via jtreg test runtime/NMT/MallocLimitTest. Here, we just
// test that limits are triggered for specific APIs.
TEST_VM_FATAL_ERROR_MSG(NMT, MallocLimitDeathTestOnRealloc, ".*MallocLimit: reached category .mtTest. limit.*") {
// We fake the correct assert if NMT is off to make the test pass (there is no way to execute a death test conditionally)
if (!MemTracker::enabled()) {
fatal("Fake message please ignore: MallocLimit: reached category \"mtTest\" limit");
}
// the real test
MallocLimitHandler::initialize("test:100m:fatal");
char* p = (char*)os::malloc(2, mtTest);
p = (char*)os::realloc(p, 120 * M, mtTest);
}
TEST_VM_FATAL_ERROR_MSG(NMT, MallocLimitDeathTestOnStrDup, ".*MallocLimit: reached category .mtTest. limit.*") {
// We fake the correct assert if NMT is off to make the test pass (there is no way to execute a death test conditionally)
if (!MemTracker::enabled()) {
fatal("Fake message please ignore: MallocLimit: reached category \"mtTest\" limit");
}
// the real test
MallocLimitHandler::initialize("test:10m:fatal");
for (int i = 0; i < 100000; i++) {
char* p = os::strdup("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", mtTest);
}
}