Path: blob/master/src/hotspot/share/services/nmtPreInit.cpp
64441 views
/*1* Copyright (c) 2021 SAP SE. All rights reserved.2* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "runtime/os.hpp"27#include "services/nmtPreInit.hpp"28#include "utilities/align.hpp"29#include "utilities/debug.hpp"30#include "utilities/ostream.hpp"31#include "utilities/globalDefinitions.hpp"3233#if INCLUDE_NMT3435// Obviously we cannot use os::malloc for any dynamic allocation during pre-NMT-init, so we must use36// raw malloc; to make this very clear, wrap them.37static void* raw_malloc(size_t s) { return ::malloc(s); }38static void* raw_realloc(void* old, size_t s) { return ::realloc(old, s); }39static void raw_free(void* p) { ::free(p); }4041// We must ensure that the start of the payload area of the nmt lookup table nodes is malloc-aligned42static const size_t malloc_alignment = 2 * sizeof(void*); // could we use max_align_t?43STATIC_ASSERT(is_aligned(sizeof(NMTPreInitAllocation), malloc_alignment));4445// --------- NMTPreInitAllocation --------------4647NMTPreInitAllocation* NMTPreInitAllocation::do_alloc(size_t payload_size) {48const size_t outer_size = sizeof(NMTPreInitAllocation) + payload_size;49void* p = raw_malloc(outer_size);50NMTPreInitAllocation* a = new(p) NMTPreInitAllocation(payload_size);51return a;52}5354NMTPreInitAllocation* NMTPreInitAllocation::do_reallocate(NMTPreInitAllocation* old, size_t new_payload_size) {55assert(old->next == NULL, "unhang from map first");56// We just reallocate the old block, header and all.57const size_t new_outer_size = sizeof(NMTPreInitAllocation) + new_payload_size;58void* p = raw_realloc(old, new_outer_size);59// re-stamp header with new size60NMTPreInitAllocation* a = new(p) NMTPreInitAllocation(new_payload_size);61return a;62}6364void NMTPreInitAllocation::do_free(NMTPreInitAllocation* p) {65assert(p->next == NULL, "unhang from map first");66raw_free(p);67}6869// --------- NMTPreInitAllocationTable --------------7071NMTPreInitAllocationTable::NMTPreInitAllocationTable() {72::memset(_entries, 0, sizeof(_entries));73}7475// print a string describing the current state76void NMTPreInitAllocationTable::print_state(outputStream* st) const {77// Collect some statistics and print them78int num_entries = 0;79int num_primary_entries = 0;80int longest_chain = 0;81size_t sum_bytes = 0;82for (int i = 0; i < table_size; i++) {83int chain_len = 0;84for (NMTPreInitAllocation* a = _entries[i]; a != NULL; a = a->next) {85chain_len++;86sum_bytes += a->size;87}88if (chain_len > 0) {89num_primary_entries++;90}91num_entries += chain_len;92longest_chain = MAX2(chain_len, longest_chain);93}94st->print("entries: %d (primary: %d, empties: %d), sum bytes: " SIZE_FORMAT95", longest chain length: %d",96num_entries, num_primary_entries, table_size - num_primary_entries,97sum_bytes, longest_chain);98}99100#ifdef ASSERT101void NMTPreInitAllocationTable::print_map(outputStream* st) const {102for (int i = 0; i < table_size; i++) {103st->print("[%d]: ", i);104for (NMTPreInitAllocation* a = _entries[i]; a != NULL; a = a->next) {105st->print( PTR_FORMAT "(" SIZE_FORMAT ") ", p2i(a->payload()), a->size);106}107st->cr();108}109}110111void NMTPreInitAllocationTable::verify() const {112// This verifies the buildup of the lookup table, including the load and the chain lengths.113// We should see chain lens of 0-1 under normal conditions. Under artificial conditions114// (20000 VM args) we should see maybe 6-7. From a certain length on we can be sure something115// is broken.116const int longest_acceptable_chain_len = 30;117int num_chains_too_long = 0;118for (index_t i = 0; i < table_size; i++) {119int len = 0;120for (const NMTPreInitAllocation* a = _entries[i]; a != NULL; a = a->next) {121index_t i2 = index_for_key(a->payload());122assert(i2 == i, "wrong hash");123assert(a->size > 0, "wrong size");124len++;125// very paranoid: search for dups126bool found = false;127for (const NMTPreInitAllocation* a2 = _entries[i]; a2 != NULL; a2 = a2->next) {128if (a == a2) {129assert(!found, "dup!");130found = true;131}132}133}134if (len > longest_acceptable_chain_len) {135num_chains_too_long++;136}137}138if (num_chains_too_long > 0) {139assert(false, "NMT preinit lookup table degenerated (%d/%d chains longer than %d)",140num_chains_too_long, table_size, longest_acceptable_chain_len);141}142}143#endif // ASSERT144145// --------- NMTPreinit --------------146147NMTPreInitAllocationTable* NMTPreInit::_table = NULL;148bool NMTPreInit::_nmt_was_initialized = false;149150// Some statistics151unsigned NMTPreInit::_num_mallocs_pre = 0;152unsigned NMTPreInit::_num_reallocs_pre = 0;153unsigned NMTPreInit::_num_frees_pre = 0;154155void NMTPreInit::create_table() {156assert(_table == NULL, "just once");157void* p = raw_malloc(sizeof(NMTPreInitAllocationTable));158_table = new(p) NMTPreInitAllocationTable();159}160161// Allocate with os::malloc (hidden to prevent having to include os.hpp)162void* NMTPreInit::do_os_malloc(size_t size) {163return os::malloc(size, mtNMT);164}165166// Switches from NMT pre-init state to NMT post-init state;167// in post-init, no modifications to the lookup table are possible.168void NMTPreInit::pre_to_post() {169assert(_nmt_was_initialized == false, "just once");170_nmt_was_initialized = true;171DEBUG_ONLY(verify();)172}173174#ifdef ASSERT175void NMTPreInit::verify() {176if (_table != NULL) {177_table->verify();178}179assert(_num_reallocs_pre <= _num_mallocs_pre &&180_num_frees_pre <= _num_mallocs_pre, "stats are off");181}182#endif // ASSERT183184void NMTPreInit::print_state(outputStream* st) {185if (_table != NULL) {186_table->print_state(st);187st->cr();188}189st->print_cr("pre-init mallocs: %u, pre-init reallocs: %u, pre-init frees: %u",190_num_mallocs_pre, _num_reallocs_pre, _num_frees_pre);191}192193#endif // INCLUDE_NMT194195196