Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp
41149 views
1
/*
2
* Copyright (c) 2006, 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 it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 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 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include "precompiled.hpp"
26
#include "gc/parallel/mutableNUMASpace.hpp"
27
#include "gc/shared/collectedHeap.hpp"
28
#include "gc/shared/gc_globals.hpp"
29
#include "gc/shared/spaceDecorator.hpp"
30
#include "gc/shared/workgroup.hpp"
31
#include "memory/allocation.inline.hpp"
32
#include "oops/oop.inline.hpp"
33
#include "oops/typeArrayOop.hpp"
34
#include "runtime/atomic.hpp"
35
#include "runtime/java.hpp"
36
#include "runtime/os.inline.hpp"
37
#include "runtime/thread.inline.hpp"
38
#include "runtime/threadSMR.hpp"
39
#include "utilities/align.hpp"
40
41
MutableNUMASpace::MutableNUMASpace(size_t alignment) : MutableSpace(alignment), _must_use_large_pages(false) {
42
_lgrp_spaces = new (ResourceObj::C_HEAP, mtGC) GrowableArray<LGRPSpace*>(0, mtGC);
43
_page_size = os::vm_page_size();
44
_adaptation_cycles = 0;
45
_samples_count = 0;
46
47
#ifdef LINUX
48
// Changing the page size can lead to freeing of memory. When using large pages
49
// and the memory has been both reserved and committed, Linux does not support
50
// freeing parts of it.
51
if (UseLargePages && !os::can_commit_large_page_memory()) {
52
_must_use_large_pages = true;
53
}
54
#endif // LINUX
55
56
update_layout(true);
57
}
58
59
MutableNUMASpace::~MutableNUMASpace() {
60
for (int i = 0; i < lgrp_spaces()->length(); i++) {
61
delete lgrp_spaces()->at(i);
62
}
63
delete lgrp_spaces();
64
}
65
66
#ifndef PRODUCT
67
void MutableNUMASpace::mangle_unused_area() {
68
// This method should do nothing.
69
// It can be called on a numa space during a full compaction.
70
}
71
void MutableNUMASpace::mangle_unused_area_complete() {
72
// This method should do nothing.
73
// It can be called on a numa space during a full compaction.
74
}
75
void MutableNUMASpace::mangle_region(MemRegion mr) {
76
// This method should do nothing because numa spaces are not mangled.
77
}
78
void MutableNUMASpace::set_top_for_allocations(HeapWord* v) {
79
assert(false, "Do not mangle MutableNUMASpace's");
80
}
81
void MutableNUMASpace::set_top_for_allocations() {
82
// This method should do nothing.
83
}
84
void MutableNUMASpace::check_mangled_unused_area(HeapWord* limit) {
85
// This method should do nothing.
86
}
87
void MutableNUMASpace::check_mangled_unused_area_complete() {
88
// This method should do nothing.
89
}
90
#endif // NOT_PRODUCT
91
92
// There may be unallocated holes in the middle chunks
93
// that should be filled with dead objects to ensure parsability.
94
void MutableNUMASpace::ensure_parsability() {
95
for (int i = 0; i < lgrp_spaces()->length(); i++) {
96
LGRPSpace *ls = lgrp_spaces()->at(i);
97
MutableSpace *s = ls->space();
98
if (s->top() < top()) { // For all spaces preceding the one containing top()
99
if (s->free_in_words() > 0) {
100
HeapWord* cur_top = s->top();
101
size_t words_left_to_fill = pointer_delta(s->end(), s->top());;
102
while (words_left_to_fill > 0) {
103
size_t words_to_fill = MIN2(words_left_to_fill, CollectedHeap::filler_array_max_size());
104
assert(words_to_fill >= CollectedHeap::min_fill_size(),
105
"Remaining size (" SIZE_FORMAT ") is too small to fill (based on " SIZE_FORMAT " and " SIZE_FORMAT ")",
106
words_to_fill, words_left_to_fill, CollectedHeap::filler_array_max_size());
107
CollectedHeap::fill_with_object(cur_top, words_to_fill);
108
if (!os::numa_has_static_binding()) {
109
size_t touched_words = words_to_fill;
110
#ifndef ASSERT
111
if (!ZapUnusedHeapArea) {
112
touched_words = MIN2((size_t)align_object_size(typeArrayOopDesc::header_size(T_INT)),
113
touched_words);
114
}
115
#endif
116
MemRegion invalid;
117
HeapWord *crossing_start = align_up(cur_top, os::vm_page_size());
118
HeapWord *crossing_end = align_down(cur_top + touched_words, os::vm_page_size());
119
if (crossing_start != crossing_end) {
120
// If object header crossed a small page boundary we mark the area
121
// as invalid rounding it to a page_size().
122
HeapWord *start = MAX2(align_down(cur_top, page_size()), s->bottom());
123
HeapWord *end = MIN2(align_up(cur_top + touched_words, page_size()), s->end());
124
invalid = MemRegion(start, end);
125
}
126
127
ls->add_invalid_region(invalid);
128
}
129
cur_top += words_to_fill;
130
words_left_to_fill -= words_to_fill;
131
}
132
}
133
} else {
134
if (!os::numa_has_static_binding()) {
135
#ifdef ASSERT
136
MemRegion invalid(s->top(), s->end());
137
ls->add_invalid_region(invalid);
138
#else
139
if (ZapUnusedHeapArea) {
140
MemRegion invalid(s->top(), s->end());
141
ls->add_invalid_region(invalid);
142
} else {
143
return;
144
}
145
#endif
146
} else {
147
return;
148
}
149
}
150
}
151
}
152
153
size_t MutableNUMASpace::used_in_words() const {
154
size_t s = 0;
155
for (int i = 0; i < lgrp_spaces()->length(); i++) {
156
s += lgrp_spaces()->at(i)->space()->used_in_words();
157
}
158
return s;
159
}
160
161
size_t MutableNUMASpace::free_in_words() const {
162
size_t s = 0;
163
for (int i = 0; i < lgrp_spaces()->length(); i++) {
164
s += lgrp_spaces()->at(i)->space()->free_in_words();
165
}
166
return s;
167
}
168
169
170
size_t MutableNUMASpace::tlab_capacity(Thread *thr) const {
171
guarantee(thr != NULL, "No thread");
172
int lgrp_id = thr->lgrp_id();
173
if (lgrp_id == -1) {
174
// This case can occur after the topology of the system has
175
// changed. Thread can change their location, the new home
176
// group will be determined during the first allocation
177
// attempt. For now we can safely assume that all spaces
178
// have equal size because the whole space will be reinitialized.
179
if (lgrp_spaces()->length() > 0) {
180
return capacity_in_bytes() / lgrp_spaces()->length();
181
} else {
182
assert(false, "There should be at least one locality group");
183
return 0;
184
}
185
}
186
// That's the normal case, where we know the locality group of the thread.
187
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
188
if (i == -1) {
189
return 0;
190
}
191
return lgrp_spaces()->at(i)->space()->capacity_in_bytes();
192
}
193
194
size_t MutableNUMASpace::tlab_used(Thread *thr) const {
195
// Please see the comments for tlab_capacity().
196
guarantee(thr != NULL, "No thread");
197
int lgrp_id = thr->lgrp_id();
198
if (lgrp_id == -1) {
199
if (lgrp_spaces()->length() > 0) {
200
return (used_in_bytes()) / lgrp_spaces()->length();
201
} else {
202
assert(false, "There should be at least one locality group");
203
return 0;
204
}
205
}
206
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
207
if (i == -1) {
208
return 0;
209
}
210
return lgrp_spaces()->at(i)->space()->used_in_bytes();
211
}
212
213
214
size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const {
215
// Please see the comments for tlab_capacity().
216
guarantee(thr != NULL, "No thread");
217
int lgrp_id = thr->lgrp_id();
218
if (lgrp_id == -1) {
219
if (lgrp_spaces()->length() > 0) {
220
return free_in_bytes() / lgrp_spaces()->length();
221
} else {
222
assert(false, "There should be at least one locality group");
223
return 0;
224
}
225
}
226
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
227
if (i == -1) {
228
return 0;
229
}
230
return lgrp_spaces()->at(i)->space()->free_in_bytes();
231
}
232
233
234
size_t MutableNUMASpace::capacity_in_words(Thread* thr) const {
235
guarantee(thr != NULL, "No thread");
236
int lgrp_id = thr->lgrp_id();
237
if (lgrp_id == -1) {
238
if (lgrp_spaces()->length() > 0) {
239
return capacity_in_words() / lgrp_spaces()->length();
240
} else {
241
assert(false, "There should be at least one locality group");
242
return 0;
243
}
244
}
245
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
246
if (i == -1) {
247
return 0;
248
}
249
return lgrp_spaces()->at(i)->space()->capacity_in_words();
250
}
251
252
// Check if the NUMA topology has changed. Add and remove spaces if needed.
253
// The update can be forced by setting the force parameter equal to true.
254
bool MutableNUMASpace::update_layout(bool force) {
255
// Check if the topology had changed.
256
bool changed = os::numa_topology_changed();
257
if (force || changed) {
258
// Compute lgrp intersection. Add/remove spaces.
259
int lgrp_limit = (int)os::numa_get_groups_num();
260
int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtGC);
261
int lgrp_num = (int)os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);
262
assert(lgrp_num > 0, "There should be at least one locality group");
263
// Add new spaces for the new nodes
264
for (int i = 0; i < lgrp_num; i++) {
265
bool found = false;
266
for (int j = 0; j < lgrp_spaces()->length(); j++) {
267
if (lgrp_spaces()->at(j)->lgrp_id() == lgrp_ids[i]) {
268
found = true;
269
break;
270
}
271
}
272
if (!found) {
273
lgrp_spaces()->append(new LGRPSpace(lgrp_ids[i], alignment()));
274
}
275
}
276
277
// Remove spaces for the removed nodes.
278
for (int i = 0; i < lgrp_spaces()->length();) {
279
bool found = false;
280
for (int j = 0; j < lgrp_num; j++) {
281
if (lgrp_spaces()->at(i)->lgrp_id() == lgrp_ids[j]) {
282
found = true;
283
break;
284
}
285
}
286
if (!found) {
287
delete lgrp_spaces()->at(i);
288
lgrp_spaces()->remove_at(i);
289
} else {
290
i++;
291
}
292
}
293
294
FREE_C_HEAP_ARRAY(int, lgrp_ids);
295
296
if (changed) {
297
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
298
thread->set_lgrp_id(-1);
299
}
300
}
301
return true;
302
}
303
return false;
304
}
305
306
// Bias region towards the first-touching lgrp. Set the right page sizes.
307
void MutableNUMASpace::bias_region(MemRegion mr, int lgrp_id) {
308
HeapWord *start = align_up(mr.start(), page_size());
309
HeapWord *end = align_down(mr.end(), page_size());
310
if (end > start) {
311
MemRegion aligned_region(start, end);
312
assert((intptr_t)aligned_region.start() % page_size() == 0 &&
313
(intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment");
314
assert(region().contains(aligned_region), "Sanity");
315
// First we tell the OS which page size we want in the given range. The underlying
316
// large page can be broken down if we require small pages.
317
os::realign_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());
318
// Then we uncommit the pages in the range.
319
os::free_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());
320
// And make them local/first-touch biased.
321
os::numa_make_local((char*)aligned_region.start(), aligned_region.byte_size(), lgrp_id);
322
}
323
}
324
325
// Free all pages in the region.
326
void MutableNUMASpace::free_region(MemRegion mr) {
327
HeapWord *start = align_up(mr.start(), page_size());
328
HeapWord *end = align_down(mr.end(), page_size());
329
if (end > start) {
330
MemRegion aligned_region(start, end);
331
assert((intptr_t)aligned_region.start() % page_size() == 0 &&
332
(intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment");
333
assert(region().contains(aligned_region), "Sanity");
334
os::free_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());
335
}
336
}
337
338
// Update space layout. Perform adaptation.
339
void MutableNUMASpace::update() {
340
if (update_layout(false)) {
341
// If the topology has changed, make all chunks zero-sized.
342
// And clear the alloc-rate statistics.
343
// In future we may want to handle this more gracefully in order
344
// to avoid the reallocation of the pages as much as possible.
345
for (int i = 0; i < lgrp_spaces()->length(); i++) {
346
LGRPSpace *ls = lgrp_spaces()->at(i);
347
MutableSpace *s = ls->space();
348
s->set_end(s->bottom());
349
s->set_top(s->bottom());
350
ls->clear_alloc_rate();
351
}
352
// A NUMA space is never mangled
353
initialize(region(),
354
SpaceDecorator::Clear,
355
SpaceDecorator::DontMangle);
356
} else {
357
bool should_initialize = false;
358
if (!os::numa_has_static_binding()) {
359
for (int i = 0; i < lgrp_spaces()->length(); i++) {
360
if (!lgrp_spaces()->at(i)->invalid_region().is_empty()) {
361
should_initialize = true;
362
break;
363
}
364
}
365
}
366
367
if (should_initialize ||
368
(UseAdaptiveNUMAChunkSizing && adaptation_cycles() < samples_count())) {
369
// A NUMA space is never mangled
370
initialize(region(),
371
SpaceDecorator::Clear,
372
SpaceDecorator::DontMangle);
373
}
374
}
375
376
if (NUMAStats) {
377
for (int i = 0; i < lgrp_spaces()->length(); i++) {
378
lgrp_spaces()->at(i)->accumulate_statistics(page_size());
379
}
380
}
381
382
scan_pages(NUMAPageScanRate);
383
}
384
385
// Scan pages. Free pages that have smaller size or wrong placement.
386
void MutableNUMASpace::scan_pages(size_t page_count)
387
{
388
size_t pages_per_chunk = page_count / lgrp_spaces()->length();
389
if (pages_per_chunk > 0) {
390
for (int i = 0; i < lgrp_spaces()->length(); i++) {
391
LGRPSpace *ls = lgrp_spaces()->at(i);
392
ls->scan_pages(page_size(), pages_per_chunk);
393
}
394
}
395
}
396
397
// Accumulate statistics about the allocation rate of each lgrp.
398
void MutableNUMASpace::accumulate_statistics() {
399
if (UseAdaptiveNUMAChunkSizing) {
400
for (int i = 0; i < lgrp_spaces()->length(); i++) {
401
lgrp_spaces()->at(i)->sample();
402
}
403
increment_samples_count();
404
}
405
406
if (NUMAStats) {
407
for (int i = 0; i < lgrp_spaces()->length(); i++) {
408
lgrp_spaces()->at(i)->accumulate_statistics(page_size());
409
}
410
}
411
}
412
413
// Get the current size of a chunk.
414
// This function computes the size of the chunk based on the
415
// difference between chunk ends. This allows it to work correctly in
416
// case the whole space is resized and during the process of adaptive
417
// chunk resizing.
418
size_t MutableNUMASpace::current_chunk_size(int i) {
419
HeapWord *cur_end, *prev_end;
420
if (i == 0) {
421
prev_end = bottom();
422
} else {
423
prev_end = lgrp_spaces()->at(i - 1)->space()->end();
424
}
425
if (i == lgrp_spaces()->length() - 1) {
426
cur_end = end();
427
} else {
428
cur_end = lgrp_spaces()->at(i)->space()->end();
429
}
430
if (cur_end > prev_end) {
431
return pointer_delta(cur_end, prev_end, sizeof(char));
432
}
433
return 0;
434
}
435
436
// Return the default chunk size by equally diving the space.
437
// page_size() aligned.
438
size_t MutableNUMASpace::default_chunk_size() {
439
return base_space_size() / lgrp_spaces()->length() * page_size();
440
}
441
442
// Produce a new chunk size. page_size() aligned.
443
// This function is expected to be called on sequence of i's from 0 to
444
// lgrp_spaces()->length().
445
size_t MutableNUMASpace::adaptive_chunk_size(int i, size_t limit) {
446
size_t pages_available = base_space_size();
447
for (int j = 0; j < i; j++) {
448
pages_available -= align_down(current_chunk_size(j), page_size()) / page_size();
449
}
450
pages_available -= lgrp_spaces()->length() - i - 1;
451
assert(pages_available > 0, "No pages left");
452
float alloc_rate = 0;
453
for (int j = i; j < lgrp_spaces()->length(); j++) {
454
alloc_rate += lgrp_spaces()->at(j)->alloc_rate()->average();
455
}
456
size_t chunk_size = 0;
457
if (alloc_rate > 0) {
458
LGRPSpace *ls = lgrp_spaces()->at(i);
459
chunk_size = (size_t)(ls->alloc_rate()->average() / alloc_rate * pages_available) * page_size();
460
}
461
chunk_size = MAX2(chunk_size, page_size());
462
463
if (limit > 0) {
464
limit = align_down(limit, page_size());
465
if (chunk_size > current_chunk_size(i)) {
466
size_t upper_bound = pages_available * page_size();
467
if (upper_bound > limit &&
468
current_chunk_size(i) < upper_bound - limit) {
469
// The resulting upper bound should not exceed the available
470
// amount of memory (pages_available * page_size()).
471
upper_bound = current_chunk_size(i) + limit;
472
}
473
chunk_size = MIN2(chunk_size, upper_bound);
474
} else {
475
size_t lower_bound = page_size();
476
if (current_chunk_size(i) > limit) { // lower_bound shouldn't underflow.
477
lower_bound = current_chunk_size(i) - limit;
478
}
479
chunk_size = MAX2(chunk_size, lower_bound);
480
}
481
}
482
assert(chunk_size <= pages_available * page_size(), "Chunk size out of range");
483
return chunk_size;
484
}
485
486
487
// Return the bottom_region and the top_region. Align them to page_size() boundary.
488
// |------------------new_region---------------------------------|
489
// |----bottom_region--|---intersection---|------top_region------|
490
void MutableNUMASpace::select_tails(MemRegion new_region, MemRegion intersection,
491
MemRegion* bottom_region, MemRegion *top_region) {
492
// Is there bottom?
493
if (new_region.start() < intersection.start()) { // Yes
494
// Try to coalesce small pages into a large one.
495
if (UseLargePages && page_size() >= alignment()) {
496
HeapWord* p = align_up(intersection.start(), alignment());
497
if (new_region.contains(p)
498
&& pointer_delta(p, new_region.start(), sizeof(char)) >= alignment()) {
499
if (intersection.contains(p)) {
500
intersection = MemRegion(p, intersection.end());
501
} else {
502
intersection = MemRegion(p, p);
503
}
504
}
505
}
506
*bottom_region = MemRegion(new_region.start(), intersection.start());
507
} else {
508
*bottom_region = MemRegion();
509
}
510
511
// Is there top?
512
if (intersection.end() < new_region.end()) { // Yes
513
// Try to coalesce small pages into a large one.
514
if (UseLargePages && page_size() >= alignment()) {
515
HeapWord* p = align_down(intersection.end(), alignment());
516
if (new_region.contains(p)
517
&& pointer_delta(new_region.end(), p, sizeof(char)) >= alignment()) {
518
if (intersection.contains(p)) {
519
intersection = MemRegion(intersection.start(), p);
520
} else {
521
intersection = MemRegion(p, p);
522
}
523
}
524
}
525
*top_region = MemRegion(intersection.end(), new_region.end());
526
} else {
527
*top_region = MemRegion();
528
}
529
}
530
531
// Try to merge the invalid region with the bottom or top region by decreasing
532
// the intersection area. Return the invalid_region aligned to the page_size()
533
// boundary if it's inside the intersection. Return non-empty invalid_region
534
// if it lies inside the intersection (also page-aligned).
535
// |------------------new_region---------------------------------|
536
// |----------------|-------invalid---|--------------------------|
537
// |----bottom_region--|---intersection---|------top_region------|
538
void MutableNUMASpace::merge_regions(MemRegion new_region, MemRegion* intersection,
539
MemRegion *invalid_region) {
540
if (intersection->start() >= invalid_region->start() && intersection->contains(invalid_region->end())) {
541
*intersection = MemRegion(invalid_region->end(), intersection->end());
542
*invalid_region = MemRegion();
543
} else
544
if (intersection->end() <= invalid_region->end() && intersection->contains(invalid_region->start())) {
545
*intersection = MemRegion(intersection->start(), invalid_region->start());
546
*invalid_region = MemRegion();
547
} else
548
if (intersection->equals(*invalid_region) || invalid_region->contains(*intersection)) {
549
*intersection = MemRegion(new_region.start(), new_region.start());
550
*invalid_region = MemRegion();
551
} else
552
if (intersection->contains(invalid_region)) {
553
// That's the only case we have to make an additional bias_region() call.
554
HeapWord* start = invalid_region->start();
555
HeapWord* end = invalid_region->end();
556
if (UseLargePages && page_size() >= alignment()) {
557
HeapWord *p = align_down(start, alignment());
558
if (new_region.contains(p)) {
559
start = p;
560
}
561
p = align_up(end, alignment());
562
if (new_region.contains(end)) {
563
end = p;
564
}
565
}
566
if (intersection->start() > start) {
567
*intersection = MemRegion(start, intersection->end());
568
}
569
if (intersection->end() < end) {
570
*intersection = MemRegion(intersection->start(), end);
571
}
572
*invalid_region = MemRegion(start, end);
573
}
574
}
575
576
void MutableNUMASpace::initialize(MemRegion mr,
577
bool clear_space,
578
bool mangle_space,
579
bool setup_pages,
580
WorkGang* pretouch_gang) {
581
assert(clear_space, "Reallocation will destroy data!");
582
assert(lgrp_spaces()->length() > 0, "There should be at least one space");
583
584
MemRegion old_region = region(), new_region;
585
set_bottom(mr.start());
586
set_end(mr.end());
587
// Must always clear the space
588
clear(SpaceDecorator::DontMangle);
589
590
// Compute chunk sizes
591
size_t prev_page_size = page_size();
592
set_page_size(UseLargePages ? alignment() : os::vm_page_size());
593
HeapWord* rounded_bottom = align_up(bottom(), page_size());
594
HeapWord* rounded_end = align_down(end(), page_size());
595
size_t base_space_size_pages = pointer_delta(rounded_end, rounded_bottom, sizeof(char)) / page_size();
596
597
// Try small pages if the chunk size is too small
598
if (base_space_size_pages / lgrp_spaces()->length() == 0
599
&& page_size() > (size_t)os::vm_page_size()) {
600
// Changing the page size below can lead to freeing of memory. So we fail initialization.
601
if (_must_use_large_pages) {
602
vm_exit_during_initialization("Failed initializing NUMA with large pages. Too small heap size");
603
}
604
set_page_size(os::vm_page_size());
605
rounded_bottom = align_up(bottom(), page_size());
606
rounded_end = align_down(end(), page_size());
607
base_space_size_pages = pointer_delta(rounded_end, rounded_bottom, sizeof(char)) / page_size();
608
}
609
guarantee(base_space_size_pages / lgrp_spaces()->length() > 0, "Space too small");
610
set_base_space_size(base_space_size_pages);
611
612
// Handle space resize
613
MemRegion top_region, bottom_region;
614
if (!old_region.equals(region())) {
615
new_region = MemRegion(rounded_bottom, rounded_end);
616
MemRegion intersection = new_region.intersection(old_region);
617
if (intersection.start() == NULL ||
618
intersection.end() == NULL ||
619
prev_page_size > page_size()) { // If the page size got smaller we have to change
620
// the page size preference for the whole space.
621
intersection = MemRegion(new_region.start(), new_region.start());
622
}
623
select_tails(new_region, intersection, &bottom_region, &top_region);
624
bias_region(bottom_region, lgrp_spaces()->at(0)->lgrp_id());
625
bias_region(top_region, lgrp_spaces()->at(lgrp_spaces()->length() - 1)->lgrp_id());
626
}
627
628
// Check if the space layout has changed significantly?
629
// This happens when the space has been resized so that either head or tail
630
// chunk became less than a page.
631
bool layout_valid = UseAdaptiveNUMAChunkSizing &&
632
current_chunk_size(0) > page_size() &&
633
current_chunk_size(lgrp_spaces()->length() - 1) > page_size();
634
635
636
for (int i = 0; i < lgrp_spaces()->length(); i++) {
637
LGRPSpace *ls = lgrp_spaces()->at(i);
638
MutableSpace *s = ls->space();
639
old_region = s->region();
640
641
size_t chunk_byte_size = 0, old_chunk_byte_size = 0;
642
if (i < lgrp_spaces()->length() - 1) {
643
if (!UseAdaptiveNUMAChunkSizing ||
644
(UseAdaptiveNUMAChunkSizing && NUMAChunkResizeWeight == 0) ||
645
samples_count() < AdaptiveSizePolicyReadyThreshold) {
646
// No adaptation. Divide the space equally.
647
chunk_byte_size = default_chunk_size();
648
} else
649
if (!layout_valid || NUMASpaceResizeRate == 0) {
650
// Fast adaptation. If no space resize rate is set, resize
651
// the chunks instantly.
652
chunk_byte_size = adaptive_chunk_size(i, 0);
653
} else {
654
// Slow adaptation. Resize the chunks moving no more than
655
// NUMASpaceResizeRate bytes per collection.
656
size_t limit = NUMASpaceResizeRate /
657
(lgrp_spaces()->length() * (lgrp_spaces()->length() + 1) / 2);
658
chunk_byte_size = adaptive_chunk_size(i, MAX2(limit * (i + 1), page_size()));
659
}
660
661
assert(chunk_byte_size >= page_size(), "Chunk size too small");
662
assert(chunk_byte_size <= capacity_in_bytes(), "Sanity check");
663
}
664
665
if (i == 0) { // Bottom chunk
666
if (i != lgrp_spaces()->length() - 1) {
667
new_region = MemRegion(bottom(), rounded_bottom + (chunk_byte_size >> LogHeapWordSize));
668
} else {
669
new_region = MemRegion(bottom(), end());
670
}
671
} else
672
if (i < lgrp_spaces()->length() - 1) { // Middle chunks
673
MutableSpace *ps = lgrp_spaces()->at(i - 1)->space();
674
new_region = MemRegion(ps->end(),
675
ps->end() + (chunk_byte_size >> LogHeapWordSize));
676
} else { // Top chunk
677
MutableSpace *ps = lgrp_spaces()->at(i - 1)->space();
678
new_region = MemRegion(ps->end(), end());
679
}
680
guarantee(region().contains(new_region), "Region invariant");
681
682
683
// The general case:
684
// |---------------------|--invalid---|--------------------------|
685
// |------------------new_region---------------------------------|
686
// |----bottom_region--|---intersection---|------top_region------|
687
// |----old_region----|
688
// The intersection part has all pages in place we don't need to migrate them.
689
// Pages for the top and bottom part should be freed and then reallocated.
690
691
MemRegion intersection = old_region.intersection(new_region);
692
693
if (intersection.start() == NULL || intersection.end() == NULL) {
694
intersection = MemRegion(new_region.start(), new_region.start());
695
}
696
697
if (!os::numa_has_static_binding()) {
698
MemRegion invalid_region = ls->invalid_region().intersection(new_region);
699
// Invalid region is a range of memory that could've possibly
700
// been allocated on the other node. That's relevant only on Solaris where
701
// there is no static memory binding.
702
if (!invalid_region.is_empty()) {
703
merge_regions(new_region, &intersection, &invalid_region);
704
free_region(invalid_region);
705
ls->set_invalid_region(MemRegion());
706
}
707
}
708
709
select_tails(new_region, intersection, &bottom_region, &top_region);
710
711
if (!os::numa_has_static_binding()) {
712
// If that's a system with the first-touch policy then it's enough
713
// to free the pages.
714
free_region(bottom_region);
715
free_region(top_region);
716
} else {
717
// In a system with static binding we have to change the bias whenever
718
// we reshape the heap.
719
bias_region(bottom_region, ls->lgrp_id());
720
bias_region(top_region, ls->lgrp_id());
721
}
722
723
// Clear space (set top = bottom) but never mangle.
724
s->initialize(new_region, SpaceDecorator::Clear, SpaceDecorator::DontMangle, MutableSpace::DontSetupPages);
725
726
set_adaptation_cycles(samples_count());
727
}
728
}
729
730
// Set the top of the whole space.
731
// Mark the the holes in chunks below the top() as invalid.
732
void MutableNUMASpace::set_top(HeapWord* value) {
733
bool found_top = false;
734
for (int i = 0; i < lgrp_spaces()->length();) {
735
LGRPSpace *ls = lgrp_spaces()->at(i);
736
MutableSpace *s = ls->space();
737
HeapWord *top = MAX2(align_down(s->top(), page_size()), s->bottom());
738
739
if (s->contains(value)) {
740
// Check if setting the chunk's top to a given value would create a hole less than
741
// a minimal object; assuming that's not the last chunk in which case we don't care.
742
if (i < lgrp_spaces()->length() - 1) {
743
size_t remainder = pointer_delta(s->end(), value);
744
const size_t min_fill_size = CollectedHeap::min_fill_size();
745
if (remainder < min_fill_size && remainder > 0) {
746
// Add a minimum size filler object; it will cross the chunk boundary.
747
CollectedHeap::fill_with_object(value, min_fill_size);
748
value += min_fill_size;
749
assert(!s->contains(value), "Should be in the next chunk");
750
// Restart the loop from the same chunk, since the value has moved
751
// to the next one.
752
continue;
753
}
754
}
755
756
if (!os::numa_has_static_binding() && top < value && top < s->end()) {
757
ls->add_invalid_region(MemRegion(top, value));
758
}
759
s->set_top(value);
760
found_top = true;
761
} else {
762
if (found_top) {
763
s->set_top(s->bottom());
764
} else {
765
if (!os::numa_has_static_binding() && top < s->end()) {
766
ls->add_invalid_region(MemRegion(top, s->end()));
767
}
768
s->set_top(s->end());
769
}
770
}
771
i++;
772
}
773
MutableSpace::set_top(value);
774
}
775
776
void MutableNUMASpace::clear(bool mangle_space) {
777
MutableSpace::set_top(bottom());
778
for (int i = 0; i < lgrp_spaces()->length(); i++) {
779
// Never mangle NUMA spaces because the mangling will
780
// bind the memory to a possibly unwanted lgroup.
781
lgrp_spaces()->at(i)->space()->clear(SpaceDecorator::DontMangle);
782
}
783
}
784
785
/*
786
Linux supports static memory binding, therefore the most part of the
787
logic dealing with the possible invalid page allocation is effectively
788
disabled. Besides there is no notion of the home node in Linux. A
789
thread is allowed to migrate freely. Although the scheduler is rather
790
reluctant to move threads between the nodes. We check for the current
791
node every allocation. And with a high probability a thread stays on
792
the same node for some time allowing local access to recently allocated
793
objects.
794
*/
795
796
HeapWord* MutableNUMASpace::cas_allocate(size_t size) {
797
Thread* thr = Thread::current();
798
int lgrp_id = thr->lgrp_id();
799
if (lgrp_id == -1 || !os::numa_has_group_homing()) {
800
lgrp_id = os::numa_get_group_id();
801
thr->set_lgrp_id(lgrp_id);
802
}
803
804
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
805
// It is possible that a new CPU has been hotplugged and
806
// we haven't reshaped the space accordingly.
807
if (i == -1) {
808
i = os::random() % lgrp_spaces()->length();
809
}
810
LGRPSpace *ls = lgrp_spaces()->at(i);
811
MutableSpace *s = ls->space();
812
HeapWord *p = s->cas_allocate(size);
813
if (p != NULL) {
814
size_t remainder = pointer_delta(s->end(), p + size);
815
if (remainder < CollectedHeap::min_fill_size() && remainder > 0) {
816
if (s->cas_deallocate(p, size)) {
817
// We were the last to allocate and created a fragment less than
818
// a minimal object.
819
p = NULL;
820
} else {
821
guarantee(false, "Deallocation should always succeed");
822
}
823
}
824
}
825
if (p != NULL) {
826
HeapWord* cur_top, *cur_chunk_top = p + size;
827
while ((cur_top = top()) < cur_chunk_top) { // Keep _top updated.
828
if (Atomic::cmpxchg(top_addr(), cur_top, cur_chunk_top) == cur_top) {
829
break;
830
}
831
}
832
}
833
834
// Make the page allocation happen here if there is no static binding.
835
if (p != NULL && !os::numa_has_static_binding() ) {
836
for (HeapWord *i = p; i < p + size; i += os::vm_page_size() >> LogHeapWordSize) {
837
*(int*)i = 0;
838
}
839
}
840
if (p == NULL) {
841
ls->set_allocation_failed();
842
}
843
return p;
844
}
845
846
void MutableNUMASpace::print_short_on(outputStream* st) const {
847
MutableSpace::print_short_on(st);
848
st->print(" (");
849
for (int i = 0; i < lgrp_spaces()->length(); i++) {
850
st->print("lgrp %d: ", lgrp_spaces()->at(i)->lgrp_id());
851
lgrp_spaces()->at(i)->space()->print_short_on(st);
852
if (i < lgrp_spaces()->length() - 1) {
853
st->print(", ");
854
}
855
}
856
st->print(")");
857
}
858
859
void MutableNUMASpace::print_on(outputStream* st) const {
860
MutableSpace::print_on(st);
861
for (int i = 0; i < lgrp_spaces()->length(); i++) {
862
LGRPSpace *ls = lgrp_spaces()->at(i);
863
st->print(" lgrp %d", ls->lgrp_id());
864
ls->space()->print_on(st);
865
if (NUMAStats) {
866
for (int i = 0; i < lgrp_spaces()->length(); i++) {
867
lgrp_spaces()->at(i)->accumulate_statistics(page_size());
868
}
869
st->print(" local/remote/unbiased/uncommitted: " SIZE_FORMAT "K/"
870
SIZE_FORMAT "K/" SIZE_FORMAT "K/" SIZE_FORMAT
871
"K, large/small pages: " SIZE_FORMAT "/" SIZE_FORMAT "\n",
872
ls->space_stats()->_local_space / K,
873
ls->space_stats()->_remote_space / K,
874
ls->space_stats()->_unbiased_space / K,
875
ls->space_stats()->_uncommited_space / K,
876
ls->space_stats()->_large_pages,
877
ls->space_stats()->_small_pages);
878
}
879
}
880
}
881
882
void MutableNUMASpace::verify() {
883
// This can be called after setting an arbitrary value to the space's top,
884
// so an object can cross the chunk boundary. We ensure the parsability
885
// of the space and just walk the objects in linear fashion.
886
ensure_parsability();
887
MutableSpace::verify();
888
}
889
890
// Scan pages and gather stats about page placement and size.
891
void MutableNUMASpace::LGRPSpace::accumulate_statistics(size_t page_size) {
892
clear_space_stats();
893
char *start = (char*)align_up(space()->bottom(), page_size);
894
char* end = (char*)align_down(space()->end(), page_size);
895
if (start < end) {
896
for (char *p = start; p < end;) {
897
os::page_info info;
898
if (os::get_page_info(p, &info)) {
899
if (info.size > 0) {
900
if (info.size > (size_t)os::vm_page_size()) {
901
space_stats()->_large_pages++;
902
} else {
903
space_stats()->_small_pages++;
904
}
905
if (info.lgrp_id == lgrp_id()) {
906
space_stats()->_local_space += info.size;
907
} else {
908
space_stats()->_remote_space += info.size;
909
}
910
p += info.size;
911
} else {
912
p += os::vm_page_size();
913
space_stats()->_uncommited_space += os::vm_page_size();
914
}
915
} else {
916
return;
917
}
918
}
919
}
920
space_stats()->_unbiased_space = pointer_delta(start, space()->bottom(), sizeof(char)) +
921
pointer_delta(space()->end(), end, sizeof(char));
922
923
}
924
925
// Scan page_count pages and verify if they have the right size and right placement.
926
// If invalid pages are found they are freed in hope that subsequent reallocation
927
// will be more successful.
928
void MutableNUMASpace::LGRPSpace::scan_pages(size_t page_size, size_t page_count)
929
{
930
char* range_start = (char*)align_up(space()->bottom(), page_size);
931
char* range_end = (char*)align_down(space()->end(), page_size);
932
933
if (range_start > last_page_scanned() || last_page_scanned() >= range_end) {
934
set_last_page_scanned(range_start);
935
}
936
937
char *scan_start = last_page_scanned();
938
char* scan_end = MIN2(scan_start + page_size * page_count, range_end);
939
940
os::page_info page_expected, page_found;
941
page_expected.size = page_size;
942
page_expected.lgrp_id = lgrp_id();
943
944
char *s = scan_start;
945
while (s < scan_end) {
946
char *e = os::scan_pages(s, (char*)scan_end, &page_expected, &page_found);
947
if (e == NULL) {
948
break;
949
}
950
if (e != scan_end) {
951
assert(e < scan_end, "e: " PTR_FORMAT " scan_end: " PTR_FORMAT, p2i(e), p2i(scan_end));
952
953
if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id())
954
&& page_expected.size != 0) {
955
os::free_memory(s, pointer_delta(e, s, sizeof(char)), page_size);
956
}
957
page_expected = page_found;
958
}
959
s = e;
960
}
961
962
set_last_page_scanned(scan_end);
963
}
964
965