Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/hotspot/share/services/nmtPreInit.cpp
64441 views
1
/*
2
* Copyright (c) 2021 SAP SE. All rights reserved.
3
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*
24
*/
25
26
#include "precompiled.hpp"
27
#include "runtime/os.hpp"
28
#include "services/nmtPreInit.hpp"
29
#include "utilities/align.hpp"
30
#include "utilities/debug.hpp"
31
#include "utilities/ostream.hpp"
32
#include "utilities/globalDefinitions.hpp"
33
34
#if INCLUDE_NMT
35
36
// Obviously we cannot use os::malloc for any dynamic allocation during pre-NMT-init, so we must use
37
// raw malloc; to make this very clear, wrap them.
38
static void* raw_malloc(size_t s) { return ::malloc(s); }
39
static void* raw_realloc(void* old, size_t s) { return ::realloc(old, s); }
40
static void raw_free(void* p) { ::free(p); }
41
42
// We must ensure that the start of the payload area of the nmt lookup table nodes is malloc-aligned
43
static const size_t malloc_alignment = 2 * sizeof(void*); // could we use max_align_t?
44
STATIC_ASSERT(is_aligned(sizeof(NMTPreInitAllocation), malloc_alignment));
45
46
// --------- NMTPreInitAllocation --------------
47
48
NMTPreInitAllocation* NMTPreInitAllocation::do_alloc(size_t payload_size) {
49
const size_t outer_size = sizeof(NMTPreInitAllocation) + payload_size;
50
void* p = raw_malloc(outer_size);
51
NMTPreInitAllocation* a = new(p) NMTPreInitAllocation(payload_size);
52
return a;
53
}
54
55
NMTPreInitAllocation* NMTPreInitAllocation::do_reallocate(NMTPreInitAllocation* old, size_t new_payload_size) {
56
assert(old->next == NULL, "unhang from map first");
57
// We just reallocate the old block, header and all.
58
const size_t new_outer_size = sizeof(NMTPreInitAllocation) + new_payload_size;
59
void* p = raw_realloc(old, new_outer_size);
60
// re-stamp header with new size
61
NMTPreInitAllocation* a = new(p) NMTPreInitAllocation(new_payload_size);
62
return a;
63
}
64
65
void NMTPreInitAllocation::do_free(NMTPreInitAllocation* p) {
66
assert(p->next == NULL, "unhang from map first");
67
raw_free(p);
68
}
69
70
// --------- NMTPreInitAllocationTable --------------
71
72
NMTPreInitAllocationTable::NMTPreInitAllocationTable() {
73
::memset(_entries, 0, sizeof(_entries));
74
}
75
76
// print a string describing the current state
77
void NMTPreInitAllocationTable::print_state(outputStream* st) const {
78
// Collect some statistics and print them
79
int num_entries = 0;
80
int num_primary_entries = 0;
81
int longest_chain = 0;
82
size_t sum_bytes = 0;
83
for (int i = 0; i < table_size; i++) {
84
int chain_len = 0;
85
for (NMTPreInitAllocation* a = _entries[i]; a != NULL; a = a->next) {
86
chain_len++;
87
sum_bytes += a->size;
88
}
89
if (chain_len > 0) {
90
num_primary_entries++;
91
}
92
num_entries += chain_len;
93
longest_chain = MAX2(chain_len, longest_chain);
94
}
95
st->print("entries: %d (primary: %d, empties: %d), sum bytes: " SIZE_FORMAT
96
", longest chain length: %d",
97
num_entries, num_primary_entries, table_size - num_primary_entries,
98
sum_bytes, longest_chain);
99
}
100
101
#ifdef ASSERT
102
void NMTPreInitAllocationTable::print_map(outputStream* st) const {
103
for (int i = 0; i < table_size; i++) {
104
st->print("[%d]: ", i);
105
for (NMTPreInitAllocation* a = _entries[i]; a != NULL; a = a->next) {
106
st->print( PTR_FORMAT "(" SIZE_FORMAT ") ", p2i(a->payload()), a->size);
107
}
108
st->cr();
109
}
110
}
111
112
void NMTPreInitAllocationTable::verify() const {
113
// This verifies the buildup of the lookup table, including the load and the chain lengths.
114
// We should see chain lens of 0-1 under normal conditions. Under artificial conditions
115
// (20000 VM args) we should see maybe 6-7. From a certain length on we can be sure something
116
// is broken.
117
const int longest_acceptable_chain_len = 30;
118
int num_chains_too_long = 0;
119
for (index_t i = 0; i < table_size; i++) {
120
int len = 0;
121
for (const NMTPreInitAllocation* a = _entries[i]; a != NULL; a = a->next) {
122
index_t i2 = index_for_key(a->payload());
123
assert(i2 == i, "wrong hash");
124
assert(a->size > 0, "wrong size");
125
len++;
126
// very paranoid: search for dups
127
bool found = false;
128
for (const NMTPreInitAllocation* a2 = _entries[i]; a2 != NULL; a2 = a2->next) {
129
if (a == a2) {
130
assert(!found, "dup!");
131
found = true;
132
}
133
}
134
}
135
if (len > longest_acceptable_chain_len) {
136
num_chains_too_long++;
137
}
138
}
139
if (num_chains_too_long > 0) {
140
assert(false, "NMT preinit lookup table degenerated (%d/%d chains longer than %d)",
141
num_chains_too_long, table_size, longest_acceptable_chain_len);
142
}
143
}
144
#endif // ASSERT
145
146
// --------- NMTPreinit --------------
147
148
NMTPreInitAllocationTable* NMTPreInit::_table = NULL;
149
bool NMTPreInit::_nmt_was_initialized = false;
150
151
// Some statistics
152
unsigned NMTPreInit::_num_mallocs_pre = 0;
153
unsigned NMTPreInit::_num_reallocs_pre = 0;
154
unsigned NMTPreInit::_num_frees_pre = 0;
155
156
void NMTPreInit::create_table() {
157
assert(_table == NULL, "just once");
158
void* p = raw_malloc(sizeof(NMTPreInitAllocationTable));
159
_table = new(p) NMTPreInitAllocationTable();
160
}
161
162
// Allocate with os::malloc (hidden to prevent having to include os.hpp)
163
void* NMTPreInit::do_os_malloc(size_t size) {
164
return os::malloc(size, mtNMT);
165
}
166
167
// Switches from NMT pre-init state to NMT post-init state;
168
// in post-init, no modifications to the lookup table are possible.
169
void NMTPreInit::pre_to_post() {
170
assert(_nmt_was_initialized == false, "just once");
171
_nmt_was_initialized = true;
172
DEBUG_ONLY(verify();)
173
}
174
175
#ifdef ASSERT
176
void NMTPreInit::verify() {
177
if (_table != NULL) {
178
_table->verify();
179
}
180
assert(_num_reallocs_pre <= _num_mallocs_pre &&
181
_num_frees_pre <= _num_mallocs_pre, "stats are off");
182
}
183
#endif // ASSERT
184
185
void NMTPreInit::print_state(outputStream* st) {
186
if (_table != NULL) {
187
_table->print_state(st);
188
st->cr();
189
}
190
st->print_cr("pre-init mallocs: %u, pre-init reallocs: %u, pre-init frees: %u",
191
_num_mallocs_pre, _num_reallocs_pre, _num_frees_pre);
192
}
193
194
#endif // INCLUDE_NMT
195
196