src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp

Fri, 09 May 2008 16:34:08 +0400

author
iveresov
date
Fri, 09 May 2008 16:34:08 +0400
changeset 579
e3729351c946
parent 576
fcbfc50865ab
child 625
d1635bf93939
permissions
-rw-r--r--

6697534: Premature GC and invalid lgrp selection with NUMA-aware allocator.
Summary: Don't move tops of the chunks in ensure_parsibility(). Handle the situation with Solaris when a machine has a locality group with no memory.
Reviewed-by: apetrusenko, jcoomes, ysr

duke@435 1
duke@435 2 /*
duke@435 3 * Copyright 2006-2007 Sun Microsystems, Inc. All Rights Reserved.
duke@435 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 5 *
duke@435 6 * This code is free software; you can redistribute it and/or modify it
duke@435 7 * under the terms of the GNU General Public License version 2 only, as
duke@435 8 * published by the Free Software Foundation.
duke@435 9 *
duke@435 10 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 13 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 14 * accompanied this code).
duke@435 15 *
duke@435 16 * You should have received a copy of the GNU General Public License version
duke@435 17 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 19 *
duke@435 20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@435 21 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@435 22 * have any questions.
duke@435 23 *
duke@435 24 */
duke@435 25
duke@435 26 # include "incls/_precompiled.incl"
duke@435 27 # include "incls/_mutableNUMASpace.cpp.incl"
duke@435 28
duke@435 29
duke@435 30 MutableNUMASpace::MutableNUMASpace() {
duke@435 31 _lgrp_spaces = new (ResourceObj::C_HEAP) GrowableArray<LGRPSpace*>(0, true);
duke@435 32 _page_size = os::vm_page_size();
duke@435 33 _adaptation_cycles = 0;
duke@435 34 _samples_count = 0;
duke@435 35 update_layout(true);
duke@435 36 }
duke@435 37
duke@435 38 MutableNUMASpace::~MutableNUMASpace() {
duke@435 39 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 40 delete lgrp_spaces()->at(i);
duke@435 41 }
duke@435 42 delete lgrp_spaces();
duke@435 43 }
duke@435 44
duke@435 45 void MutableNUMASpace::mangle_unused_area() {
duke@435 46 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 47 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 48 MutableSpace *s = ls->space();
iveresov@576 49 if (!os::numa_has_static_binding()) {
iveresov@576 50 HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom());
iveresov@576 51 if (top < s->end()) {
iveresov@576 52 ls->add_invalid_region(MemRegion(top, s->end()));
iveresov@576 53 }
duke@435 54 }
duke@435 55 s->mangle_unused_area();
duke@435 56 }
duke@435 57 }
duke@435 58
duke@435 59 // There may be unallocated holes in the middle chunks
duke@435 60 // that should be filled with dead objects to ensure parseability.
duke@435 61 void MutableNUMASpace::ensure_parsability() {
duke@435 62 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 63 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 64 MutableSpace *s = ls->space();
iveresov@579 65 if (s->top() < top()) { // For all spaces preceeding the one containing top()
duke@435 66 if (s->free_in_words() > 0) {
duke@435 67 SharedHeap::fill_region_with_object(MemRegion(s->top(), s->end()));
iveresov@579 68 size_t area_touched_words = pointer_delta(s->end(), s->top());
duke@435 69 #ifndef ASSERT
duke@435 70 if (!ZapUnusedHeapArea) {
duke@435 71 area_touched_words = MIN2((size_t)align_object_size(typeArrayOopDesc::header_size(T_INT)),
duke@435 72 area_touched_words);
duke@435 73 }
duke@435 74 #endif
iveresov@576 75 if (!os::numa_has_static_binding()) {
iveresov@576 76 MemRegion invalid;
iveresov@576 77 HeapWord *crossing_start = (HeapWord*)round_to((intptr_t)s->top(), os::vm_page_size());
iveresov@576 78 HeapWord *crossing_end = (HeapWord*)round_to((intptr_t)(s->top() + area_touched_words),
iveresov@576 79 os::vm_page_size());
iveresov@576 80 if (crossing_start != crossing_end) {
iveresov@576 81 // If object header crossed a small page boundary we mark the area
iveresov@576 82 // as invalid rounding it to a page_size().
iveresov@576 83 HeapWord *start = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom());
iveresov@576 84 HeapWord *end = MIN2((HeapWord*)round_to((intptr_t)(s->top() + area_touched_words), page_size()),
iveresov@576 85 s->end());
iveresov@576 86 invalid = MemRegion(start, end);
iveresov@576 87 }
iveresov@576 88
iveresov@576 89 ls->add_invalid_region(invalid);
duke@435 90 }
duke@435 91 }
duke@435 92 } else {
iveresov@576 93 if (!os::numa_has_static_binding()) {
duke@435 94 #ifdef ASSERT
duke@435 95 MemRegion invalid(s->top(), s->end());
duke@435 96 ls->add_invalid_region(invalid);
iveresov@576 97 #else
iveresov@576 98 if (ZapUnusedHeapArea) {
iveresov@576 99 MemRegion invalid(s->top(), s->end());
iveresov@576 100 ls->add_invalid_region(invalid);
iveresov@579 101 } else {
iveresov@579 102 return;
iveresov@579 103 }
duke@435 104 #endif
iveresov@579 105 } else {
iveresov@579 106 return;
iveresov@576 107 }
duke@435 108 }
duke@435 109 }
duke@435 110 }
duke@435 111
duke@435 112 size_t MutableNUMASpace::used_in_words() const {
duke@435 113 size_t s = 0;
duke@435 114 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 115 s += lgrp_spaces()->at(i)->space()->used_in_words();
duke@435 116 }
duke@435 117 return s;
duke@435 118 }
duke@435 119
duke@435 120 size_t MutableNUMASpace::free_in_words() const {
duke@435 121 size_t s = 0;
duke@435 122 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 123 s += lgrp_spaces()->at(i)->space()->free_in_words();
duke@435 124 }
duke@435 125 return s;
duke@435 126 }
duke@435 127
duke@435 128
duke@435 129 size_t MutableNUMASpace::tlab_capacity(Thread *thr) const {
duke@435 130 guarantee(thr != NULL, "No thread");
duke@435 131 int lgrp_id = thr->lgrp_id();
duke@435 132 assert(lgrp_id != -1, "No lgrp_id set");
duke@435 133 int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
duke@435 134 if (i == -1) {
duke@435 135 return 0;
duke@435 136 }
duke@435 137 return lgrp_spaces()->at(i)->space()->capacity_in_bytes();
duke@435 138 }
duke@435 139
duke@435 140 size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const {
duke@435 141 guarantee(thr != NULL, "No thread");
duke@435 142 int lgrp_id = thr->lgrp_id();
duke@435 143 assert(lgrp_id != -1, "No lgrp_id set");
duke@435 144 int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
duke@435 145 if (i == -1) {
duke@435 146 return 0;
duke@435 147 }
duke@435 148 return lgrp_spaces()->at(i)->space()->free_in_bytes();
duke@435 149 }
duke@435 150
duke@435 151 // Check if the NUMA topology has changed. Add and remove spaces if needed.
duke@435 152 // The update can be forced by setting the force parameter equal to true.
duke@435 153 bool MutableNUMASpace::update_layout(bool force) {
duke@435 154 // Check if the topology had changed.
duke@435 155 bool changed = os::numa_topology_changed();
duke@435 156 if (force || changed) {
duke@435 157 // Compute lgrp intersection. Add/remove spaces.
duke@435 158 int lgrp_limit = (int)os::numa_get_groups_num();
duke@435 159 int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit);
duke@435 160 int lgrp_num = (int)os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);
duke@435 161 assert(lgrp_num > 0, "There should be at least one locality group");
duke@435 162 // Add new spaces for the new nodes
duke@435 163 for (int i = 0; i < lgrp_num; i++) {
duke@435 164 bool found = false;
duke@435 165 for (int j = 0; j < lgrp_spaces()->length(); j++) {
duke@435 166 if (lgrp_spaces()->at(j)->lgrp_id() == lgrp_ids[i]) {
duke@435 167 found = true;
duke@435 168 break;
duke@435 169 }
duke@435 170 }
duke@435 171 if (!found) {
duke@435 172 lgrp_spaces()->append(new LGRPSpace(lgrp_ids[i]));
duke@435 173 }
duke@435 174 }
duke@435 175
duke@435 176 // Remove spaces for the removed nodes.
duke@435 177 for (int i = 0; i < lgrp_spaces()->length();) {
duke@435 178 bool found = false;
duke@435 179 for (int j = 0; j < lgrp_num; j++) {
duke@435 180 if (lgrp_spaces()->at(i)->lgrp_id() == lgrp_ids[j]) {
duke@435 181 found = true;
duke@435 182 break;
duke@435 183 }
duke@435 184 }
duke@435 185 if (!found) {
duke@435 186 delete lgrp_spaces()->at(i);
duke@435 187 lgrp_spaces()->remove_at(i);
duke@435 188 } else {
duke@435 189 i++;
duke@435 190 }
duke@435 191 }
duke@435 192
duke@435 193 FREE_C_HEAP_ARRAY(int, lgrp_ids);
duke@435 194
duke@435 195 if (changed) {
duke@435 196 for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
duke@435 197 thread->set_lgrp_id(-1);
duke@435 198 }
duke@435 199 }
duke@435 200 return true;
duke@435 201 }
duke@435 202 return false;
duke@435 203 }
duke@435 204
duke@435 205 // Bias region towards the first-touching lgrp. Set the right page sizes.
iveresov@576 206 void MutableNUMASpace::bias_region(MemRegion mr, int lgrp_id) {
duke@435 207 HeapWord *start = (HeapWord*)round_to((intptr_t)mr.start(), page_size());
duke@435 208 HeapWord *end = (HeapWord*)round_down((intptr_t)mr.end(), page_size());
duke@435 209 if (end > start) {
duke@435 210 MemRegion aligned_region(start, end);
duke@435 211 assert((intptr_t)aligned_region.start() % page_size() == 0 &&
duke@435 212 (intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment");
duke@435 213 assert(region().contains(aligned_region), "Sanity");
iveresov@576 214 // First we tell the OS which page size we want in the given range. The underlying
iveresov@576 215 // large page can be broken down if we require small pages.
iveresov@576 216 os::realign_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());
iveresov@576 217 // Then we uncommit the pages in the range.
duke@435 218 os::free_memory((char*)aligned_region.start(), aligned_region.byte_size());
iveresov@576 219 // And make them local/first-touch biased.
iveresov@576 220 os::numa_make_local((char*)aligned_region.start(), aligned_region.byte_size(), lgrp_id);
duke@435 221 }
duke@435 222 }
duke@435 223
duke@435 224 // Free all pages in the region.
duke@435 225 void MutableNUMASpace::free_region(MemRegion mr) {
duke@435 226 HeapWord *start = (HeapWord*)round_to((intptr_t)mr.start(), page_size());
duke@435 227 HeapWord *end = (HeapWord*)round_down((intptr_t)mr.end(), page_size());
duke@435 228 if (end > start) {
duke@435 229 MemRegion aligned_region(start, end);
duke@435 230 assert((intptr_t)aligned_region.start() % page_size() == 0 &&
duke@435 231 (intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment");
duke@435 232 assert(region().contains(aligned_region), "Sanity");
duke@435 233 os::free_memory((char*)aligned_region.start(), aligned_region.byte_size());
duke@435 234 }
duke@435 235 }
duke@435 236
duke@435 237 // Update space layout. Perform adaptation.
duke@435 238 void MutableNUMASpace::update() {
duke@435 239 if (update_layout(false)) {
duke@435 240 // If the topology has changed, make all chunks zero-sized.
duke@435 241 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 242 MutableSpace *s = lgrp_spaces()->at(i)->space();
duke@435 243 s->set_end(s->bottom());
duke@435 244 s->set_top(s->bottom());
duke@435 245 }
duke@435 246 initialize(region(), true);
duke@435 247 } else {
duke@435 248 bool should_initialize = false;
iveresov@576 249 if (!os::numa_has_static_binding()) {
iveresov@576 250 for (int i = 0; i < lgrp_spaces()->length(); i++) {
iveresov@576 251 if (!lgrp_spaces()->at(i)->invalid_region().is_empty()) {
iveresov@576 252 should_initialize = true;
iveresov@576 253 break;
iveresov@576 254 }
duke@435 255 }
duke@435 256 }
duke@435 257
duke@435 258 if (should_initialize ||
duke@435 259 (UseAdaptiveNUMAChunkSizing && adaptation_cycles() < samples_count())) {
duke@435 260 initialize(region(), true);
duke@435 261 }
duke@435 262 }
duke@435 263
duke@435 264 if (NUMAStats) {
duke@435 265 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 266 lgrp_spaces()->at(i)->accumulate_statistics(page_size());
duke@435 267 }
duke@435 268 }
duke@435 269
duke@435 270 scan_pages(NUMAPageScanRate);
duke@435 271 }
duke@435 272
duke@435 273 // Scan pages. Free pages that have smaller size or wrong placement.
duke@435 274 void MutableNUMASpace::scan_pages(size_t page_count)
duke@435 275 {
duke@435 276 size_t pages_per_chunk = page_count / lgrp_spaces()->length();
duke@435 277 if (pages_per_chunk > 0) {
duke@435 278 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 279 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 280 ls->scan_pages(page_size(), pages_per_chunk);
duke@435 281 }
duke@435 282 }
duke@435 283 }
duke@435 284
duke@435 285 // Accumulate statistics about the allocation rate of each lgrp.
duke@435 286 void MutableNUMASpace::accumulate_statistics() {
duke@435 287 if (UseAdaptiveNUMAChunkSizing) {
duke@435 288 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 289 lgrp_spaces()->at(i)->sample();
duke@435 290 }
duke@435 291 increment_samples_count();
duke@435 292 }
duke@435 293
duke@435 294 if (NUMAStats) {
duke@435 295 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 296 lgrp_spaces()->at(i)->accumulate_statistics(page_size());
duke@435 297 }
duke@435 298 }
duke@435 299 }
duke@435 300
duke@435 301 // Get the current size of a chunk.
duke@435 302 // This function computes the size of the chunk based on the
duke@435 303 // difference between chunk ends. This allows it to work correctly in
duke@435 304 // case the whole space is resized and during the process of adaptive
duke@435 305 // chunk resizing.
duke@435 306 size_t MutableNUMASpace::current_chunk_size(int i) {
duke@435 307 HeapWord *cur_end, *prev_end;
duke@435 308 if (i == 0) {
duke@435 309 prev_end = bottom();
duke@435 310 } else {
duke@435 311 prev_end = lgrp_spaces()->at(i - 1)->space()->end();
duke@435 312 }
duke@435 313 if (i == lgrp_spaces()->length() - 1) {
duke@435 314 cur_end = end();
duke@435 315 } else {
duke@435 316 cur_end = lgrp_spaces()->at(i)->space()->end();
duke@435 317 }
duke@435 318 if (cur_end > prev_end) {
duke@435 319 return pointer_delta(cur_end, prev_end, sizeof(char));
duke@435 320 }
duke@435 321 return 0;
duke@435 322 }
duke@435 323
duke@435 324 // Return the default chunk size by equally diving the space.
duke@435 325 // page_size() aligned.
duke@435 326 size_t MutableNUMASpace::default_chunk_size() {
duke@435 327 return base_space_size() / lgrp_spaces()->length() * page_size();
duke@435 328 }
duke@435 329
duke@435 330 // Produce a new chunk size. page_size() aligned.
duke@435 331 size_t MutableNUMASpace::adaptive_chunk_size(int i, size_t limit) {
duke@435 332 size_t pages_available = base_space_size();
duke@435 333 for (int j = 0; j < i; j++) {
duke@435 334 pages_available -= round_down(current_chunk_size(j), page_size()) / page_size();
duke@435 335 }
duke@435 336 pages_available -= lgrp_spaces()->length() - i - 1;
duke@435 337 assert(pages_available > 0, "No pages left");
duke@435 338 float alloc_rate = 0;
duke@435 339 for (int j = i; j < lgrp_spaces()->length(); j++) {
duke@435 340 alloc_rate += lgrp_spaces()->at(j)->alloc_rate()->average();
duke@435 341 }
duke@435 342 size_t chunk_size = 0;
duke@435 343 if (alloc_rate > 0) {
duke@435 344 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 345 chunk_size = (size_t)(ls->alloc_rate()->average() * pages_available / alloc_rate) * page_size();
duke@435 346 }
duke@435 347 chunk_size = MAX2(chunk_size, page_size());
duke@435 348
duke@435 349 if (limit > 0) {
duke@435 350 limit = round_down(limit, page_size());
duke@435 351 if (chunk_size > current_chunk_size(i)) {
duke@435 352 chunk_size = MIN2((off_t)chunk_size, (off_t)current_chunk_size(i) + (off_t)limit);
duke@435 353 } else {
duke@435 354 chunk_size = MAX2((off_t)chunk_size, (off_t)current_chunk_size(i) - (off_t)limit);
duke@435 355 }
duke@435 356 }
duke@435 357 assert(chunk_size <= pages_available * page_size(), "Chunk size out of range");
duke@435 358 return chunk_size;
duke@435 359 }
duke@435 360
duke@435 361
duke@435 362 // Return the bottom_region and the top_region. Align them to page_size() boundary.
duke@435 363 // |------------------new_region---------------------------------|
duke@435 364 // |----bottom_region--|---intersection---|------top_region------|
duke@435 365 void MutableNUMASpace::select_tails(MemRegion new_region, MemRegion intersection,
duke@435 366 MemRegion* bottom_region, MemRegion *top_region) {
duke@435 367 // Is there bottom?
duke@435 368 if (new_region.start() < intersection.start()) { // Yes
duke@435 369 // Try to coalesce small pages into a large one.
duke@435 370 if (UseLargePages && page_size() >= os::large_page_size()) {
duke@435 371 HeapWord* p = (HeapWord*)round_to((intptr_t) intersection.start(), os::large_page_size());
duke@435 372 if (new_region.contains(p)
duke@435 373 && pointer_delta(p, new_region.start(), sizeof(char)) >= os::large_page_size()) {
duke@435 374 if (intersection.contains(p)) {
duke@435 375 intersection = MemRegion(p, intersection.end());
duke@435 376 } else {
duke@435 377 intersection = MemRegion(p, p);
duke@435 378 }
duke@435 379 }
duke@435 380 }
duke@435 381 *bottom_region = MemRegion(new_region.start(), intersection.start());
duke@435 382 } else {
duke@435 383 *bottom_region = MemRegion();
duke@435 384 }
duke@435 385
duke@435 386 // Is there top?
duke@435 387 if (intersection.end() < new_region.end()) { // Yes
duke@435 388 // Try to coalesce small pages into a large one.
duke@435 389 if (UseLargePages && page_size() >= os::large_page_size()) {
duke@435 390 HeapWord* p = (HeapWord*)round_down((intptr_t) intersection.end(), os::large_page_size());
duke@435 391 if (new_region.contains(p)
duke@435 392 && pointer_delta(new_region.end(), p, sizeof(char)) >= os::large_page_size()) {
duke@435 393 if (intersection.contains(p)) {
duke@435 394 intersection = MemRegion(intersection.start(), p);
duke@435 395 } else {
duke@435 396 intersection = MemRegion(p, p);
duke@435 397 }
duke@435 398 }
duke@435 399 }
duke@435 400 *top_region = MemRegion(intersection.end(), new_region.end());
duke@435 401 } else {
duke@435 402 *top_region = MemRegion();
duke@435 403 }
duke@435 404 }
duke@435 405
duke@435 406 // Try to merge the invalid region with the bottom or top region by decreasing
duke@435 407 // the intersection area. Return the invalid_region aligned to the page_size()
duke@435 408 // boundary if it's inside the intersection. Return non-empty invalid_region
duke@435 409 // if it lies inside the intersection (also page-aligned).
duke@435 410 // |------------------new_region---------------------------------|
duke@435 411 // |----------------|-------invalid---|--------------------------|
duke@435 412 // |----bottom_region--|---intersection---|------top_region------|
duke@435 413 void MutableNUMASpace::merge_regions(MemRegion new_region, MemRegion* intersection,
duke@435 414 MemRegion *invalid_region) {
duke@435 415 if (intersection->start() >= invalid_region->start() && intersection->contains(invalid_region->end())) {
duke@435 416 *intersection = MemRegion(invalid_region->end(), intersection->end());
duke@435 417 *invalid_region = MemRegion();
duke@435 418 } else
duke@435 419 if (intersection->end() <= invalid_region->end() && intersection->contains(invalid_region->start())) {
duke@435 420 *intersection = MemRegion(intersection->start(), invalid_region->start());
duke@435 421 *invalid_region = MemRegion();
duke@435 422 } else
duke@435 423 if (intersection->equals(*invalid_region) || invalid_region->contains(*intersection)) {
duke@435 424 *intersection = MemRegion(new_region.start(), new_region.start());
duke@435 425 *invalid_region = MemRegion();
duke@435 426 } else
duke@435 427 if (intersection->contains(invalid_region)) {
duke@435 428 // That's the only case we have to make an additional bias_region() call.
duke@435 429 HeapWord* start = invalid_region->start();
duke@435 430 HeapWord* end = invalid_region->end();
duke@435 431 if (UseLargePages && page_size() >= os::large_page_size()) {
duke@435 432 HeapWord *p = (HeapWord*)round_down((intptr_t) start, os::large_page_size());
duke@435 433 if (new_region.contains(p)) {
duke@435 434 start = p;
duke@435 435 }
duke@435 436 p = (HeapWord*)round_to((intptr_t) end, os::large_page_size());
duke@435 437 if (new_region.contains(end)) {
duke@435 438 end = p;
duke@435 439 }
duke@435 440 }
duke@435 441 if (intersection->start() > start) {
duke@435 442 *intersection = MemRegion(start, intersection->end());
duke@435 443 }
duke@435 444 if (intersection->end() < end) {
duke@435 445 *intersection = MemRegion(intersection->start(), end);
duke@435 446 }
duke@435 447 *invalid_region = MemRegion(start, end);
duke@435 448 }
duke@435 449 }
duke@435 450
duke@435 451 void MutableNUMASpace::initialize(MemRegion mr, bool clear_space) {
duke@435 452 assert(clear_space, "Reallocation will destory data!");
duke@435 453 assert(lgrp_spaces()->length() > 0, "There should be at least one space");
duke@435 454
duke@435 455 MemRegion old_region = region(), new_region;
duke@435 456 set_bottom(mr.start());
duke@435 457 set_end(mr.end());
duke@435 458 MutableSpace::set_top(bottom());
duke@435 459
duke@435 460 // Compute chunk sizes
duke@435 461 size_t prev_page_size = page_size();
duke@435 462 set_page_size(UseLargePages ? os::large_page_size() : os::vm_page_size());
duke@435 463 HeapWord* rounded_bottom = (HeapWord*)round_to((intptr_t) bottom(), page_size());
duke@435 464 HeapWord* rounded_end = (HeapWord*)round_down((intptr_t) end(), page_size());
duke@435 465 size_t base_space_size_pages = pointer_delta(rounded_end, rounded_bottom, sizeof(char)) / page_size();
duke@435 466
duke@435 467 // Try small pages if the chunk size is too small
duke@435 468 if (base_space_size_pages / lgrp_spaces()->length() == 0
duke@435 469 && page_size() > (size_t)os::vm_page_size()) {
duke@435 470 set_page_size(os::vm_page_size());
duke@435 471 rounded_bottom = (HeapWord*)round_to((intptr_t) bottom(), page_size());
duke@435 472 rounded_end = (HeapWord*)round_down((intptr_t) end(), page_size());
duke@435 473 base_space_size_pages = pointer_delta(rounded_end, rounded_bottom, sizeof(char)) / page_size();
duke@435 474 }
duke@435 475 guarantee(base_space_size_pages / lgrp_spaces()->length() > 0, "Space too small");
duke@435 476 set_base_space_size(base_space_size_pages);
duke@435 477
duke@435 478 // Handle space resize
duke@435 479 MemRegion top_region, bottom_region;
duke@435 480 if (!old_region.equals(region())) {
duke@435 481 new_region = MemRegion(rounded_bottom, rounded_end);
duke@435 482 MemRegion intersection = new_region.intersection(old_region);
duke@435 483 if (intersection.start() == NULL ||
duke@435 484 intersection.end() == NULL ||
duke@435 485 prev_page_size > page_size()) { // If the page size got smaller we have to change
duke@435 486 // the page size preference for the whole space.
duke@435 487 intersection = MemRegion(new_region.start(), new_region.start());
duke@435 488 }
duke@435 489 select_tails(new_region, intersection, &bottom_region, &top_region);
iveresov@576 490 bias_region(bottom_region, lgrp_spaces()->at(0)->lgrp_id());
iveresov@576 491 bias_region(top_region, lgrp_spaces()->at(lgrp_spaces()->length() - 1)->lgrp_id());
duke@435 492 }
duke@435 493
duke@435 494 // Check if the space layout has changed significantly?
duke@435 495 // This happens when the space has been resized so that either head or tail
duke@435 496 // chunk became less than a page.
duke@435 497 bool layout_valid = UseAdaptiveNUMAChunkSizing &&
duke@435 498 current_chunk_size(0) > page_size() &&
duke@435 499 current_chunk_size(lgrp_spaces()->length() - 1) > page_size();
duke@435 500
duke@435 501
duke@435 502 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 503 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 504 MutableSpace *s = ls->space();
duke@435 505 old_region = s->region();
duke@435 506
duke@435 507 size_t chunk_byte_size = 0, old_chunk_byte_size = 0;
duke@435 508 if (i < lgrp_spaces()->length() - 1) {
duke@435 509 if (!UseAdaptiveNUMAChunkSizing ||
duke@435 510 (UseAdaptiveNUMAChunkSizing && NUMAChunkResizeWeight == 0) ||
duke@435 511 samples_count() < AdaptiveSizePolicyReadyThreshold) {
duke@435 512 // No adaptation. Divide the space equally.
duke@435 513 chunk_byte_size = default_chunk_size();
duke@435 514 } else
duke@435 515 if (!layout_valid || NUMASpaceResizeRate == 0) {
duke@435 516 // Fast adaptation. If no space resize rate is set, resize
duke@435 517 // the chunks instantly.
duke@435 518 chunk_byte_size = adaptive_chunk_size(i, 0);
duke@435 519 } else {
duke@435 520 // Slow adaptation. Resize the chunks moving no more than
duke@435 521 // NUMASpaceResizeRate bytes per collection.
duke@435 522 size_t limit = NUMASpaceResizeRate /
duke@435 523 (lgrp_spaces()->length() * (lgrp_spaces()->length() + 1) / 2);
duke@435 524 chunk_byte_size = adaptive_chunk_size(i, MAX2(limit * (i + 1), page_size()));
duke@435 525 }
duke@435 526
duke@435 527 assert(chunk_byte_size >= page_size(), "Chunk size too small");
duke@435 528 assert(chunk_byte_size <= capacity_in_bytes(), "Sanity check");
duke@435 529 }
duke@435 530
duke@435 531 if (i == 0) { // Bottom chunk
duke@435 532 if (i != lgrp_spaces()->length() - 1) {
duke@435 533 new_region = MemRegion(bottom(), rounded_bottom + (chunk_byte_size >> LogHeapWordSize));
duke@435 534 } else {
duke@435 535 new_region = MemRegion(bottom(), end());
duke@435 536 }
duke@435 537 } else
duke@435 538 if (i < lgrp_spaces()->length() - 1) { // Middle chunks
duke@435 539 MutableSpace *ps = lgrp_spaces()->at(i - 1)->space();
duke@435 540 new_region = MemRegion(ps->end(),
duke@435 541 ps->end() + (chunk_byte_size >> LogHeapWordSize));
duke@435 542 } else { // Top chunk
duke@435 543 MutableSpace *ps = lgrp_spaces()->at(i - 1)->space();
duke@435 544 new_region = MemRegion(ps->end(), end());
duke@435 545 }
duke@435 546 guarantee(region().contains(new_region), "Region invariant");
duke@435 547
duke@435 548
duke@435 549 // The general case:
duke@435 550 // |---------------------|--invalid---|--------------------------|
duke@435 551 // |------------------new_region---------------------------------|
duke@435 552 // |----bottom_region--|---intersection---|------top_region------|
duke@435 553 // |----old_region----|
duke@435 554 // The intersection part has all pages in place we don't need to migrate them.
duke@435 555 // Pages for the top and bottom part should be freed and then reallocated.
duke@435 556
duke@435 557 MemRegion intersection = old_region.intersection(new_region);
duke@435 558
duke@435 559 if (intersection.start() == NULL || intersection.end() == NULL) {
duke@435 560 intersection = MemRegion(new_region.start(), new_region.start());
duke@435 561 }
duke@435 562
iveresov@576 563 if (!os::numa_has_static_binding()) {
iveresov@576 564 MemRegion invalid_region = ls->invalid_region().intersection(new_region);
iveresov@576 565 // Invalid region is a range of memory that could've possibly
iveresov@576 566 // been allocated on the other node. That's relevant only on Solaris where
iveresov@576 567 // there is no static memory binding.
iveresov@576 568 if (!invalid_region.is_empty()) {
iveresov@576 569 merge_regions(new_region, &intersection, &invalid_region);
iveresov@576 570 free_region(invalid_region);
iveresov@576 571 ls->set_invalid_region(MemRegion());
iveresov@576 572 }
duke@435 573 }
iveresov@576 574
duke@435 575 select_tails(new_region, intersection, &bottom_region, &top_region);
iveresov@576 576
iveresov@576 577 if (!os::numa_has_static_binding()) {
iveresov@576 578 // If that's a system with the first-touch policy then it's enough
iveresov@576 579 // to free the pages.
iveresov@576 580 free_region(bottom_region);
iveresov@576 581 free_region(top_region);
iveresov@576 582 } else {
iveresov@576 583 // In a system with static binding we have to change the bias whenever
iveresov@576 584 // we reshape the heap.
iveresov@576 585 bias_region(bottom_region, ls->lgrp_id());
iveresov@576 586 bias_region(top_region, ls->lgrp_id());
iveresov@576 587 }
duke@435 588
duke@435 589 // If we clear the region, we would mangle it in debug. That would cause page
duke@435 590 // allocation in a different place. Hence setting the top directly.
duke@435 591 s->initialize(new_region, false);
duke@435 592 s->set_top(s->bottom());
duke@435 593
duke@435 594 set_adaptation_cycles(samples_count());
duke@435 595 }
duke@435 596 }
duke@435 597
duke@435 598 // Set the top of the whole space.
duke@435 599 // Mark the the holes in chunks below the top() as invalid.
duke@435 600 void MutableNUMASpace::set_top(HeapWord* value) {
duke@435 601 bool found_top = false;
duke@435 602 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 603 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 604 MutableSpace *s = ls->space();
duke@435 605 HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom());
duke@435 606
duke@435 607 if (s->contains(value)) {
iveresov@576 608 if (!os::numa_has_static_binding() && top < value && top < s->end()) {
duke@435 609 ls->add_invalid_region(MemRegion(top, value));
duke@435 610 }
duke@435 611 s->set_top(value);
duke@435 612 found_top = true;
duke@435 613 } else {
duke@435 614 if (found_top) {
duke@435 615 s->set_top(s->bottom());
duke@435 616 } else {
iveresov@576 617 if (!os::numa_has_static_binding() && top < s->end()) {
iveresov@576 618 ls->add_invalid_region(MemRegion(top, s->end()));
iveresov@576 619 }
iveresov@576 620 s->set_top(s->end());
duke@435 621 }
duke@435 622 }
duke@435 623 }
duke@435 624 MutableSpace::set_top(value);
duke@435 625 }
duke@435 626
duke@435 627 void MutableNUMASpace::clear() {
duke@435 628 MutableSpace::set_top(bottom());
duke@435 629 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 630 lgrp_spaces()->at(i)->space()->clear();
duke@435 631 }
duke@435 632 }
duke@435 633
iveresov@576 634 /*
iveresov@576 635 Linux supports static memory binding, therefore the most part of the
iveresov@576 636 logic dealing with the possible invalid page allocation is effectively
iveresov@576 637 disabled. Besides there is no notion of the home node in Linux. A
iveresov@576 638 thread is allowed to migrate freely. Although the scheduler is rather
iveresov@576 639 reluctant to move threads between the nodes. We check for the current
iveresov@576 640 node every allocation. And with a high probability a thread stays on
iveresov@576 641 the same node for some time allowing local access to recently allocated
iveresov@576 642 objects.
iveresov@576 643 */
iveresov@576 644
duke@435 645 HeapWord* MutableNUMASpace::allocate(size_t size) {
iveresov@576 646 Thread* thr = Thread::current();
iveresov@576 647 int lgrp_id = thr->lgrp_id();
iveresov@576 648 if (lgrp_id == -1 || !os::numa_has_group_homing()) {
duke@435 649 lgrp_id = os::numa_get_group_id();
iveresov@576 650 thr->set_lgrp_id(lgrp_id);
duke@435 651 }
duke@435 652
duke@435 653 int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
duke@435 654
duke@435 655 // It is possible that a new CPU has been hotplugged and
duke@435 656 // we haven't reshaped the space accordingly.
duke@435 657 if (i == -1) {
duke@435 658 i = os::random() % lgrp_spaces()->length();
duke@435 659 }
duke@435 660
duke@435 661 MutableSpace *s = lgrp_spaces()->at(i)->space();
duke@435 662 HeapWord *p = s->allocate(size);
duke@435 663
iveresov@579 664 if (p != NULL) {
iveresov@579 665 size_t remainder = s->free_in_words();
iveresov@579 666 if (remainder < (size_t)oopDesc::header_size() && remainder > 0) {
iveresov@579 667 s->set_top(s->top() - size);
iveresov@579 668 p = NULL;
iveresov@579 669 }
duke@435 670 }
duke@435 671 if (p != NULL) {
duke@435 672 if (top() < s->top()) { // Keep _top updated.
duke@435 673 MutableSpace::set_top(s->top());
duke@435 674 }
duke@435 675 }
iveresov@576 676 // Make the page allocation happen here if there is no static binding..
iveresov@576 677 if (p != NULL && !os::numa_has_static_binding()) {
duke@435 678 for (HeapWord *i = p; i < p + size; i += os::vm_page_size() >> LogHeapWordSize) {
duke@435 679 *(int*)i = 0;
duke@435 680 }
duke@435 681 }
duke@435 682 return p;
duke@435 683 }
duke@435 684
duke@435 685 // This version is lock-free.
duke@435 686 HeapWord* MutableNUMASpace::cas_allocate(size_t size) {
iveresov@576 687 Thread* thr = Thread::current();
iveresov@576 688 int lgrp_id = thr->lgrp_id();
iveresov@576 689 if (lgrp_id == -1 || !os::numa_has_group_homing()) {
duke@435 690 lgrp_id = os::numa_get_group_id();
iveresov@576 691 thr->set_lgrp_id(lgrp_id);
duke@435 692 }
duke@435 693
duke@435 694 int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
duke@435 695 // It is possible that a new CPU has been hotplugged and
duke@435 696 // we haven't reshaped the space accordingly.
duke@435 697 if (i == -1) {
duke@435 698 i = os::random() % lgrp_spaces()->length();
duke@435 699 }
duke@435 700 MutableSpace *s = lgrp_spaces()->at(i)->space();
duke@435 701 HeapWord *p = s->cas_allocate(size);
iveresov@579 702 if (p != NULL) {
iveresov@579 703 size_t remainder = pointer_delta(s->end(), p);
iveresov@579 704 if (remainder < (size_t)oopDesc::header_size() && remainder > 0) {
iveresov@579 705 if (s->cas_deallocate(p, size)) {
iveresov@579 706 // We were the last to allocate and created a fragment less than
iveresov@579 707 // a minimal object.
iveresov@579 708 p = NULL;
iveresov@579 709 }
duke@435 710 }
duke@435 711 }
duke@435 712 if (p != NULL) {
duke@435 713 HeapWord* cur_top, *cur_chunk_top = p + size;
duke@435 714 while ((cur_top = top()) < cur_chunk_top) { // Keep _top updated.
duke@435 715 if (Atomic::cmpxchg_ptr(cur_chunk_top, top_addr(), cur_top) == cur_top) {
duke@435 716 break;
duke@435 717 }
duke@435 718 }
duke@435 719 }
duke@435 720
iveresov@576 721 // Make the page allocation happen here if there is no static binding.
iveresov@576 722 if (p != NULL && !os::numa_has_static_binding() ) {
duke@435 723 for (HeapWord *i = p; i < p + size; i += os::vm_page_size() >> LogHeapWordSize) {
duke@435 724 *(int*)i = 0;
duke@435 725 }
duke@435 726 }
duke@435 727 return p;
duke@435 728 }
duke@435 729
duke@435 730 void MutableNUMASpace::print_short_on(outputStream* st) const {
duke@435 731 MutableSpace::print_short_on(st);
duke@435 732 st->print(" (");
duke@435 733 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 734 st->print("lgrp %d: ", lgrp_spaces()->at(i)->lgrp_id());
duke@435 735 lgrp_spaces()->at(i)->space()->print_short_on(st);
duke@435 736 if (i < lgrp_spaces()->length() - 1) {
duke@435 737 st->print(", ");
duke@435 738 }
duke@435 739 }
duke@435 740 st->print(")");
duke@435 741 }
duke@435 742
duke@435 743 void MutableNUMASpace::print_on(outputStream* st) const {
duke@435 744 MutableSpace::print_on(st);
duke@435 745 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 746 LGRPSpace *ls = lgrp_spaces()->at(i);
duke@435 747 st->print(" lgrp %d", ls->lgrp_id());
duke@435 748 ls->space()->print_on(st);
duke@435 749 if (NUMAStats) {
iveresov@579 750 for (int i = 0; i < lgrp_spaces()->length(); i++) {
iveresov@579 751 lgrp_spaces()->at(i)->accumulate_statistics(page_size());
iveresov@579 752 }
duke@435 753 st->print(" local/remote/unbiased/uncommitted: %dK/%dK/%dK/%dK, large/small pages: %d/%d\n",
duke@435 754 ls->space_stats()->_local_space / K,
duke@435 755 ls->space_stats()->_remote_space / K,
duke@435 756 ls->space_stats()->_unbiased_space / K,
duke@435 757 ls->space_stats()->_uncommited_space / K,
duke@435 758 ls->space_stats()->_large_pages,
duke@435 759 ls->space_stats()->_small_pages);
duke@435 760 }
duke@435 761 }
duke@435 762 }
duke@435 763
duke@435 764 void MutableNUMASpace::verify(bool allow_dirty) const {
duke@435 765 for (int i = 0; i < lgrp_spaces()->length(); i++) {
duke@435 766 lgrp_spaces()->at(i)->space()->verify(allow_dirty);
duke@435 767 }
duke@435 768 }
duke@435 769
duke@435 770 // Scan pages and gather stats about page placement and size.
duke@435 771 void MutableNUMASpace::LGRPSpace::accumulate_statistics(size_t page_size) {
duke@435 772 clear_space_stats();
duke@435 773 char *start = (char*)round_to((intptr_t) space()->bottom(), page_size);
duke@435 774 char* end = (char*)round_down((intptr_t) space()->end(), page_size);
duke@435 775 if (start < end) {
duke@435 776 for (char *p = start; p < end;) {
duke@435 777 os::page_info info;
duke@435 778 if (os::get_page_info(p, &info)) {
duke@435 779 if (info.size > 0) {
duke@435 780 if (info.size > (size_t)os::vm_page_size()) {
duke@435 781 space_stats()->_large_pages++;
duke@435 782 } else {
duke@435 783 space_stats()->_small_pages++;
duke@435 784 }
duke@435 785 if (info.lgrp_id == lgrp_id()) {
duke@435 786 space_stats()->_local_space += info.size;
duke@435 787 } else {
duke@435 788 space_stats()->_remote_space += info.size;
duke@435 789 }
duke@435 790 p += info.size;
duke@435 791 } else {
duke@435 792 p += os::vm_page_size();
duke@435 793 space_stats()->_uncommited_space += os::vm_page_size();
duke@435 794 }
duke@435 795 } else {
duke@435 796 return;
duke@435 797 }
duke@435 798 }
duke@435 799 }
duke@435 800 space_stats()->_unbiased_space = pointer_delta(start, space()->bottom(), sizeof(char)) +
duke@435 801 pointer_delta(space()->end(), end, sizeof(char));
duke@435 802
duke@435 803 }
duke@435 804
duke@435 805 // Scan page_count pages and verify if they have the right size and right placement.
duke@435 806 // If invalid pages are found they are freed in hope that subsequent reallocation
duke@435 807 // will be more successful.
duke@435 808 void MutableNUMASpace::LGRPSpace::scan_pages(size_t page_size, size_t page_count)
duke@435 809 {
duke@435 810 char* range_start = (char*)round_to((intptr_t) space()->bottom(), page_size);
duke@435 811 char* range_end = (char*)round_down((intptr_t) space()->end(), page_size);
duke@435 812
duke@435 813 if (range_start > last_page_scanned() || last_page_scanned() >= range_end) {
duke@435 814 set_last_page_scanned(range_start);
duke@435 815 }
duke@435 816
duke@435 817 char *scan_start = last_page_scanned();
duke@435 818 char* scan_end = MIN2(scan_start + page_size * page_count, range_end);
duke@435 819
duke@435 820 os::page_info page_expected, page_found;
duke@435 821 page_expected.size = page_size;
duke@435 822 page_expected.lgrp_id = lgrp_id();
duke@435 823
duke@435 824 char *s = scan_start;
duke@435 825 while (s < scan_end) {
duke@435 826 char *e = os::scan_pages(s, (char*)scan_end, &page_expected, &page_found);
duke@435 827 if (e == NULL) {
duke@435 828 break;
duke@435 829 }
duke@435 830 if (e != scan_end) {
duke@435 831 if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id())
duke@435 832 && page_expected.size != 0) {
duke@435 833 os::free_memory(s, pointer_delta(e, s, sizeof(char)));
duke@435 834 }
duke@435 835 page_expected = page_found;
duke@435 836 }
duke@435 837 s = e;
duke@435 838 }
duke@435 839
duke@435 840 set_last_page_scanned(scan_end);
duke@435 841 }

mercurial