Path: blob/jdk8u272-b10-aarch32-20201026/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp
48726 views
1/*2* Copyright (c) 2006, 2014, 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 "gc_implementation/shared/mutableNUMASpace.hpp"27#include "gc_implementation/shared/spaceDecorator.hpp"28#include "memory/sharedHeap.hpp"29#include "oops/oop.inline.hpp"30#include "runtime/thread.inline.hpp"3132PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC3334MutableNUMASpace::MutableNUMASpace(size_t alignment) : MutableSpace(alignment) {35_lgrp_spaces = new (ResourceObj::C_HEAP, mtGC) GrowableArray<LGRPSpace*>(0, true);36_page_size = os::vm_page_size();37_adaptation_cycles = 0;38_samples_count = 0;39update_layout(true);40}4142MutableNUMASpace::~MutableNUMASpace() {43for (int i = 0; i < lgrp_spaces()->length(); i++) {44delete lgrp_spaces()->at(i);45}46delete lgrp_spaces();47}4849#ifndef PRODUCT50void MutableNUMASpace::mangle_unused_area() {51// This method should do nothing.52// It can be called on a numa space during a full compaction.53}54void MutableNUMASpace::mangle_unused_area_complete() {55// This method should do nothing.56// It can be called on a numa space during a full compaction.57}58void MutableNUMASpace::mangle_region(MemRegion mr) {59// This method should do nothing because numa spaces are not mangled.60}61void MutableNUMASpace::set_top_for_allocations(HeapWord* v) {62assert(false, "Do not mangle MutableNUMASpace's");63}64void MutableNUMASpace::set_top_for_allocations() {65// This method should do nothing.66}67void MutableNUMASpace::check_mangled_unused_area(HeapWord* limit) {68// This method should do nothing.69}70void MutableNUMASpace::check_mangled_unused_area_complete() {71// This method should do nothing.72}73#endif // NOT_PRODUCT7475// There may be unallocated holes in the middle chunks76// that should be filled with dead objects to ensure parseability.77void MutableNUMASpace::ensure_parsability() {78for (int i = 0; i < lgrp_spaces()->length(); i++) {79LGRPSpace *ls = lgrp_spaces()->at(i);80MutableSpace *s = ls->space();81if (s->top() < top()) { // For all spaces preceding the one containing top()82if (s->free_in_words() > 0) {83intptr_t cur_top = (intptr_t)s->top();84size_t words_left_to_fill = pointer_delta(s->end(), s->top());;85while (words_left_to_fill > 0) {86size_t words_to_fill = MIN2(words_left_to_fill, CollectedHeap::filler_array_max_size());87assert(words_to_fill >= CollectedHeap::min_fill_size(),88err_msg("Remaining size (" SIZE_FORMAT ") is too small to fill (based on " SIZE_FORMAT " and " SIZE_FORMAT ")",89words_to_fill, words_left_to_fill, CollectedHeap::filler_array_max_size()));90CollectedHeap::fill_with_object((HeapWord*)cur_top, words_to_fill);91if (!os::numa_has_static_binding()) {92size_t touched_words = words_to_fill;93#ifndef ASSERT94if (!ZapUnusedHeapArea) {95touched_words = MIN2((size_t)align_object_size(typeArrayOopDesc::header_size(T_INT)),96touched_words);97}98#endif99MemRegion invalid;100HeapWord *crossing_start = (HeapWord*)round_to(cur_top, os::vm_page_size());101HeapWord *crossing_end = (HeapWord*)round_to(cur_top + touched_words, os::vm_page_size());102if (crossing_start != crossing_end) {103// If object header crossed a small page boundary we mark the area104// as invalid rounding it to a page_size().105HeapWord *start = MAX2((HeapWord*)round_down(cur_top, page_size()), s->bottom());106HeapWord *end = MIN2((HeapWord*)round_to(cur_top + touched_words, page_size()), s->end());107invalid = MemRegion(start, end);108}109110ls->add_invalid_region(invalid);111}112cur_top = cur_top + (words_to_fill * HeapWordSize);113words_left_to_fill -= words_to_fill;114}115}116} else {117if (!os::numa_has_static_binding()) {118#ifdef ASSERT119MemRegion invalid(s->top(), s->end());120ls->add_invalid_region(invalid);121#else122if (ZapUnusedHeapArea) {123MemRegion invalid(s->top(), s->end());124ls->add_invalid_region(invalid);125} else {126return;127}128#endif129} else {130return;131}132}133}134}135136size_t MutableNUMASpace::used_in_words() const {137size_t s = 0;138for (int i = 0; i < lgrp_spaces()->length(); i++) {139s += lgrp_spaces()->at(i)->space()->used_in_words();140}141return s;142}143144size_t MutableNUMASpace::free_in_words() const {145size_t s = 0;146for (int i = 0; i < lgrp_spaces()->length(); i++) {147s += lgrp_spaces()->at(i)->space()->free_in_words();148}149return s;150}151152153size_t MutableNUMASpace::tlab_capacity(Thread *thr) const {154guarantee(thr != NULL, "No thread");155int lgrp_id = thr->lgrp_id();156if (lgrp_id == -1) {157// This case can occur after the topology of the system has158// changed. Thread can change their location, the new home159// group will be determined during the first allocation160// attempt. For now we can safely assume that all spaces161// have equal size because the whole space will be reinitialized.162if (lgrp_spaces()->length() > 0) {163return capacity_in_bytes() / lgrp_spaces()->length();164} else {165assert(false, "There should be at least one locality group");166return 0;167}168}169// That's the normal case, where we know the locality group of the thread.170int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);171if (i == -1) {172return 0;173}174return lgrp_spaces()->at(i)->space()->capacity_in_bytes();175}176177size_t MutableNUMASpace::tlab_used(Thread *thr) const {178// Please see the comments for tlab_capacity().179guarantee(thr != NULL, "No thread");180int lgrp_id = thr->lgrp_id();181if (lgrp_id == -1) {182if (lgrp_spaces()->length() > 0) {183return (used_in_bytes()) / lgrp_spaces()->length();184} else {185assert(false, "There should be at least one locality group");186return 0;187}188}189int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);190if (i == -1) {191return 0;192}193return lgrp_spaces()->at(i)->space()->used_in_bytes();194}195196197size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const {198// Please see the comments for tlab_capacity().199guarantee(thr != NULL, "No thread");200int lgrp_id = thr->lgrp_id();201if (lgrp_id == -1) {202if (lgrp_spaces()->length() > 0) {203return free_in_bytes() / lgrp_spaces()->length();204} else {205assert(false, "There should be at least one locality group");206return 0;207}208}209int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);210if (i == -1) {211return 0;212}213return lgrp_spaces()->at(i)->space()->free_in_bytes();214}215216217size_t MutableNUMASpace::capacity_in_words(Thread* thr) const {218guarantee(thr != NULL, "No thread");219int lgrp_id = thr->lgrp_id();220if (lgrp_id == -1) {221if (lgrp_spaces()->length() > 0) {222return capacity_in_words() / lgrp_spaces()->length();223} else {224assert(false, "There should be at least one locality group");225return 0;226}227}228int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);229if (i == -1) {230return 0;231}232return lgrp_spaces()->at(i)->space()->capacity_in_words();233}234235// Check if the NUMA topology has changed. Add and remove spaces if needed.236// The update can be forced by setting the force parameter equal to true.237bool MutableNUMASpace::update_layout(bool force) {238// Check if the topology had changed.239bool changed = os::numa_topology_changed();240if (force || changed) {241// Compute lgrp intersection. Add/remove spaces.242int lgrp_limit = (int)os::numa_get_groups_num();243int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtGC);244int lgrp_num = (int)os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);245assert(lgrp_num > 0, "There should be at least one locality group");246// Add new spaces for the new nodes247for (int i = 0; i < lgrp_num; i++) {248bool found = false;249for (int j = 0; j < lgrp_spaces()->length(); j++) {250if (lgrp_spaces()->at(j)->lgrp_id() == lgrp_ids[i]) {251found = true;252break;253}254}255if (!found) {256lgrp_spaces()->append(new LGRPSpace(lgrp_ids[i], alignment()));257}258}259260// Remove spaces for the removed nodes.261for (int i = 0; i < lgrp_spaces()->length();) {262bool found = false;263for (int j = 0; j < lgrp_num; j++) {264if (lgrp_spaces()->at(i)->lgrp_id() == lgrp_ids[j]) {265found = true;266break;267}268}269if (!found) {270delete lgrp_spaces()->at(i);271lgrp_spaces()->remove_at(i);272} else {273i++;274}275}276277FREE_C_HEAP_ARRAY(int, lgrp_ids, mtGC);278279if (changed) {280for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) {281thread->set_lgrp_id(-1);282}283}284return true;285}286return false;287}288289// Bias region towards the first-touching lgrp. Set the right page sizes.290void MutableNUMASpace::bias_region(MemRegion mr, int lgrp_id) {291HeapWord *start = (HeapWord*)round_to((intptr_t)mr.start(), page_size());292HeapWord *end = (HeapWord*)round_down((intptr_t)mr.end(), page_size());293if (end > start) {294MemRegion aligned_region(start, end);295assert((intptr_t)aligned_region.start() % page_size() == 0 &&296(intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment");297assert(region().contains(aligned_region), "Sanity");298// First we tell the OS which page size we want in the given range. The underlying299// large page can be broken down if we require small pages.300os::realign_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());301// Then we uncommit the pages in the range.302os::free_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());303// And make them local/first-touch biased.304os::numa_make_local((char*)aligned_region.start(), aligned_region.byte_size(), lgrp_id);305}306}307308// Free all pages in the region.309void MutableNUMASpace::free_region(MemRegion mr) {310HeapWord *start = (HeapWord*)round_to((intptr_t)mr.start(), page_size());311HeapWord *end = (HeapWord*)round_down((intptr_t)mr.end(), page_size());312if (end > start) {313MemRegion aligned_region(start, end);314assert((intptr_t)aligned_region.start() % page_size() == 0 &&315(intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment");316assert(region().contains(aligned_region), "Sanity");317os::free_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size());318}319}320321// Update space layout. Perform adaptation.322void MutableNUMASpace::update() {323if (update_layout(false)) {324// If the topology has changed, make all chunks zero-sized.325// And clear the alloc-rate statistics.326// In future we may want to handle this more gracefully in order327// to avoid the reallocation of the pages as much as possible.328for (int i = 0; i < lgrp_spaces()->length(); i++) {329LGRPSpace *ls = lgrp_spaces()->at(i);330MutableSpace *s = ls->space();331s->set_end(s->bottom());332s->set_top(s->bottom());333ls->clear_alloc_rate();334}335// A NUMA space is never mangled336initialize(region(),337SpaceDecorator::Clear,338SpaceDecorator::DontMangle);339} else {340bool should_initialize = false;341if (!os::numa_has_static_binding()) {342for (int i = 0; i < lgrp_spaces()->length(); i++) {343if (!lgrp_spaces()->at(i)->invalid_region().is_empty()) {344should_initialize = true;345break;346}347}348}349350if (should_initialize ||351(UseAdaptiveNUMAChunkSizing && adaptation_cycles() < samples_count())) {352// A NUMA space is never mangled353initialize(region(),354SpaceDecorator::Clear,355SpaceDecorator::DontMangle);356}357}358359if (NUMAStats) {360for (int i = 0; i < lgrp_spaces()->length(); i++) {361lgrp_spaces()->at(i)->accumulate_statistics(page_size());362}363}364365scan_pages(NUMAPageScanRate);366}367368// Scan pages. Free pages that have smaller size or wrong placement.369void MutableNUMASpace::scan_pages(size_t page_count)370{371size_t pages_per_chunk = page_count / lgrp_spaces()->length();372if (pages_per_chunk > 0) {373for (int i = 0; i < lgrp_spaces()->length(); i++) {374LGRPSpace *ls = lgrp_spaces()->at(i);375ls->scan_pages(page_size(), pages_per_chunk);376}377}378}379380// Accumulate statistics about the allocation rate of each lgrp.381void MutableNUMASpace::accumulate_statistics() {382if (UseAdaptiveNUMAChunkSizing) {383for (int i = 0; i < lgrp_spaces()->length(); i++) {384lgrp_spaces()->at(i)->sample();385}386increment_samples_count();387}388389if (NUMAStats) {390for (int i = 0; i < lgrp_spaces()->length(); i++) {391lgrp_spaces()->at(i)->accumulate_statistics(page_size());392}393}394}395396// Get the current size of a chunk.397// This function computes the size of the chunk based on the398// difference between chunk ends. This allows it to work correctly in399// case the whole space is resized and during the process of adaptive400// chunk resizing.401size_t MutableNUMASpace::current_chunk_size(int i) {402HeapWord *cur_end, *prev_end;403if (i == 0) {404prev_end = bottom();405} else {406prev_end = lgrp_spaces()->at(i - 1)->space()->end();407}408if (i == lgrp_spaces()->length() - 1) {409cur_end = end();410} else {411cur_end = lgrp_spaces()->at(i)->space()->end();412}413if (cur_end > prev_end) {414return pointer_delta(cur_end, prev_end, sizeof(char));415}416return 0;417}418419// Return the default chunk size by equally diving the space.420// page_size() aligned.421size_t MutableNUMASpace::default_chunk_size() {422return base_space_size() / lgrp_spaces()->length() * page_size();423}424425// Produce a new chunk size. page_size() aligned.426// This function is expected to be called on sequence of i's from 0 to427// lgrp_spaces()->length().428size_t MutableNUMASpace::adaptive_chunk_size(int i, size_t limit) {429size_t pages_available = base_space_size();430for (int j = 0; j < i; j++) {431pages_available -= round_down(current_chunk_size(j), page_size()) / page_size();432}433pages_available -= lgrp_spaces()->length() - i - 1;434assert(pages_available > 0, "No pages left");435float alloc_rate = 0;436for (int j = i; j < lgrp_spaces()->length(); j++) {437alloc_rate += lgrp_spaces()->at(j)->alloc_rate()->average();438}439size_t chunk_size = 0;440if (alloc_rate > 0) {441LGRPSpace *ls = lgrp_spaces()->at(i);442chunk_size = (size_t)(ls->alloc_rate()->average() / alloc_rate * pages_available) * page_size();443}444chunk_size = MAX2(chunk_size, page_size());445446if (limit > 0) {447limit = round_down(limit, page_size());448if (chunk_size > current_chunk_size(i)) {449size_t upper_bound = pages_available * page_size();450if (upper_bound > limit &&451current_chunk_size(i) < upper_bound - limit) {452// The resulting upper bound should not exceed the available453// amount of memory (pages_available * page_size()).454upper_bound = current_chunk_size(i) + limit;455}456chunk_size = MIN2(chunk_size, upper_bound);457} else {458size_t lower_bound = page_size();459if (current_chunk_size(i) > limit) { // lower_bound shouldn't underflow.460lower_bound = current_chunk_size(i) - limit;461}462chunk_size = MAX2(chunk_size, lower_bound);463}464}465assert(chunk_size <= pages_available * page_size(), "Chunk size out of range");466return chunk_size;467}468469470// Return the bottom_region and the top_region. Align them to page_size() boundary.471// |------------------new_region---------------------------------|472// |----bottom_region--|---intersection---|------top_region------|473void MutableNUMASpace::select_tails(MemRegion new_region, MemRegion intersection,474MemRegion* bottom_region, MemRegion *top_region) {475// Is there bottom?476if (new_region.start() < intersection.start()) { // Yes477// Try to coalesce small pages into a large one.478if (UseLargePages && page_size() >= alignment()) {479HeapWord* p = (HeapWord*)round_to((intptr_t) intersection.start(), alignment());480if (new_region.contains(p)481&& pointer_delta(p, new_region.start(), sizeof(char)) >= alignment()) {482if (intersection.contains(p)) {483intersection = MemRegion(p, intersection.end());484} else {485intersection = MemRegion(p, p);486}487}488}489*bottom_region = MemRegion(new_region.start(), intersection.start());490} else {491*bottom_region = MemRegion();492}493494// Is there top?495if (intersection.end() < new_region.end()) { // Yes496// Try to coalesce small pages into a large one.497if (UseLargePages && page_size() >= alignment()) {498HeapWord* p = (HeapWord*)round_down((intptr_t) intersection.end(), alignment());499if (new_region.contains(p)500&& pointer_delta(new_region.end(), p, sizeof(char)) >= alignment()) {501if (intersection.contains(p)) {502intersection = MemRegion(intersection.start(), p);503} else {504intersection = MemRegion(p, p);505}506}507}508*top_region = MemRegion(intersection.end(), new_region.end());509} else {510*top_region = MemRegion();511}512}513514// Try to merge the invalid region with the bottom or top region by decreasing515// the intersection area. Return the invalid_region aligned to the page_size()516// boundary if it's inside the intersection. Return non-empty invalid_region517// if it lies inside the intersection (also page-aligned).518// |------------------new_region---------------------------------|519// |----------------|-------invalid---|--------------------------|520// |----bottom_region--|---intersection---|------top_region------|521void MutableNUMASpace::merge_regions(MemRegion new_region, MemRegion* intersection,522MemRegion *invalid_region) {523if (intersection->start() >= invalid_region->start() && intersection->contains(invalid_region->end())) {524*intersection = MemRegion(invalid_region->end(), intersection->end());525*invalid_region = MemRegion();526} else527if (intersection->end() <= invalid_region->end() && intersection->contains(invalid_region->start())) {528*intersection = MemRegion(intersection->start(), invalid_region->start());529*invalid_region = MemRegion();530} else531if (intersection->equals(*invalid_region) || invalid_region->contains(*intersection)) {532*intersection = MemRegion(new_region.start(), new_region.start());533*invalid_region = MemRegion();534} else535if (intersection->contains(invalid_region)) {536// That's the only case we have to make an additional bias_region() call.537HeapWord* start = invalid_region->start();538HeapWord* end = invalid_region->end();539if (UseLargePages && page_size() >= alignment()) {540HeapWord *p = (HeapWord*)round_down((intptr_t) start, alignment());541if (new_region.contains(p)) {542start = p;543}544p = (HeapWord*)round_to((intptr_t) end, alignment());545if (new_region.contains(end)) {546end = p;547}548}549if (intersection->start() > start) {550*intersection = MemRegion(start, intersection->end());551}552if (intersection->end() < end) {553*intersection = MemRegion(intersection->start(), end);554}555*invalid_region = MemRegion(start, end);556}557}558559void MutableNUMASpace::initialize(MemRegion mr,560bool clear_space,561bool mangle_space,562bool setup_pages) {563assert(clear_space, "Reallocation will destory data!");564assert(lgrp_spaces()->length() > 0, "There should be at least one space");565566MemRegion old_region = region(), new_region;567set_bottom(mr.start());568set_end(mr.end());569// Must always clear the space570clear(SpaceDecorator::DontMangle);571572// Compute chunk sizes573size_t prev_page_size = page_size();574set_page_size(UseLargePages ? alignment() : os::vm_page_size());575HeapWord* rounded_bottom = (HeapWord*)round_to((intptr_t) bottom(), page_size());576HeapWord* rounded_end = (HeapWord*)round_down((intptr_t) end(), page_size());577size_t base_space_size_pages = pointer_delta(rounded_end, rounded_bottom, sizeof(char)) / page_size();578579// Try small pages if the chunk size is too small580if (base_space_size_pages / lgrp_spaces()->length() == 0581&& page_size() > (size_t)os::vm_page_size()) {582set_page_size(os::vm_page_size());583rounded_bottom = (HeapWord*)round_to((intptr_t) bottom(), page_size());584rounded_end = (HeapWord*)round_down((intptr_t) end(), page_size());585base_space_size_pages = pointer_delta(rounded_end, rounded_bottom, sizeof(char)) / page_size();586}587guarantee(base_space_size_pages / lgrp_spaces()->length() > 0, "Space too small");588set_base_space_size(base_space_size_pages);589590// Handle space resize591MemRegion top_region, bottom_region;592if (!old_region.equals(region())) {593new_region = MemRegion(rounded_bottom, rounded_end);594MemRegion intersection = new_region.intersection(old_region);595if (intersection.start() == NULL ||596intersection.end() == NULL ||597prev_page_size > page_size()) { // If the page size got smaller we have to change598// the page size preference for the whole space.599intersection = MemRegion(new_region.start(), new_region.start());600}601select_tails(new_region, intersection, &bottom_region, &top_region);602bias_region(bottom_region, lgrp_spaces()->at(0)->lgrp_id());603bias_region(top_region, lgrp_spaces()->at(lgrp_spaces()->length() - 1)->lgrp_id());604}605606// Check if the space layout has changed significantly?607// This happens when the space has been resized so that either head or tail608// chunk became less than a page.609bool layout_valid = UseAdaptiveNUMAChunkSizing &&610current_chunk_size(0) > page_size() &&611current_chunk_size(lgrp_spaces()->length() - 1) > page_size();612613614for (int i = 0; i < lgrp_spaces()->length(); i++) {615LGRPSpace *ls = lgrp_spaces()->at(i);616MutableSpace *s = ls->space();617old_region = s->region();618619size_t chunk_byte_size = 0, old_chunk_byte_size = 0;620if (i < lgrp_spaces()->length() - 1) {621if (!UseAdaptiveNUMAChunkSizing ||622(UseAdaptiveNUMAChunkSizing && NUMAChunkResizeWeight == 0) ||623samples_count() < AdaptiveSizePolicyReadyThreshold) {624// No adaptation. Divide the space equally.625chunk_byte_size = default_chunk_size();626} else627if (!layout_valid || NUMASpaceResizeRate == 0) {628// Fast adaptation. If no space resize rate is set, resize629// the chunks instantly.630chunk_byte_size = adaptive_chunk_size(i, 0);631} else {632// Slow adaptation. Resize the chunks moving no more than633// NUMASpaceResizeRate bytes per collection.634size_t limit = NUMASpaceResizeRate /635(lgrp_spaces()->length() * (lgrp_spaces()->length() + 1) / 2);636chunk_byte_size = adaptive_chunk_size(i, MAX2(limit * (i + 1), page_size()));637}638639assert(chunk_byte_size >= page_size(), "Chunk size too small");640assert(chunk_byte_size <= capacity_in_bytes(), "Sanity check");641}642643if (i == 0) { // Bottom chunk644if (i != lgrp_spaces()->length() - 1) {645new_region = MemRegion(bottom(), rounded_bottom + (chunk_byte_size >> LogHeapWordSize));646} else {647new_region = MemRegion(bottom(), end());648}649} else650if (i < lgrp_spaces()->length() - 1) { // Middle chunks651MutableSpace *ps = lgrp_spaces()->at(i - 1)->space();652new_region = MemRegion(ps->end(),653ps->end() + (chunk_byte_size >> LogHeapWordSize));654} else { // Top chunk655MutableSpace *ps = lgrp_spaces()->at(i - 1)->space();656new_region = MemRegion(ps->end(), end());657}658guarantee(region().contains(new_region), "Region invariant");659660661// The general case:662// |---------------------|--invalid---|--------------------------|663// |------------------new_region---------------------------------|664// |----bottom_region--|---intersection---|------top_region------|665// |----old_region----|666// The intersection part has all pages in place we don't need to migrate them.667// Pages for the top and bottom part should be freed and then reallocated.668669MemRegion intersection = old_region.intersection(new_region);670671if (intersection.start() == NULL || intersection.end() == NULL) {672intersection = MemRegion(new_region.start(), new_region.start());673}674675if (!os::numa_has_static_binding()) {676MemRegion invalid_region = ls->invalid_region().intersection(new_region);677// Invalid region is a range of memory that could've possibly678// been allocated on the other node. That's relevant only on Solaris where679// there is no static memory binding.680if (!invalid_region.is_empty()) {681merge_regions(new_region, &intersection, &invalid_region);682free_region(invalid_region);683ls->set_invalid_region(MemRegion());684}685}686687select_tails(new_region, intersection, &bottom_region, &top_region);688689if (!os::numa_has_static_binding()) {690// If that's a system with the first-touch policy then it's enough691// to free the pages.692free_region(bottom_region);693free_region(top_region);694} else {695// In a system with static binding we have to change the bias whenever696// we reshape the heap.697bias_region(bottom_region, ls->lgrp_id());698bias_region(top_region, ls->lgrp_id());699}700701// Clear space (set top = bottom) but never mangle.702s->initialize(new_region, SpaceDecorator::Clear, SpaceDecorator::DontMangle, MutableSpace::DontSetupPages);703704set_adaptation_cycles(samples_count());705}706}707708// Set the top of the whole space.709// Mark the the holes in chunks below the top() as invalid.710void MutableNUMASpace::set_top(HeapWord* value) {711bool found_top = false;712for (int i = 0; i < lgrp_spaces()->length();) {713LGRPSpace *ls = lgrp_spaces()->at(i);714MutableSpace *s = ls->space();715HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom());716717if (s->contains(value)) {718// Check if setting the chunk's top to a given value would create a hole less than719// a minimal object; assuming that's not the last chunk in which case we don't care.720if (i < lgrp_spaces()->length() - 1) {721size_t remainder = pointer_delta(s->end(), value);722const size_t min_fill_size = CollectedHeap::min_fill_size();723if (remainder < min_fill_size && remainder > 0) {724// Add a minimum size filler object; it will cross the chunk boundary.725CollectedHeap::fill_with_object(value, min_fill_size);726value += min_fill_size;727assert(!s->contains(value), "Should be in the next chunk");728// Restart the loop from the same chunk, since the value has moved729// to the next one.730continue;731}732}733734if (!os::numa_has_static_binding() && top < value && top < s->end()) {735ls->add_invalid_region(MemRegion(top, value));736}737s->set_top(value);738found_top = true;739} else {740if (found_top) {741s->set_top(s->bottom());742} else {743if (!os::numa_has_static_binding() && top < s->end()) {744ls->add_invalid_region(MemRegion(top, s->end()));745}746s->set_top(s->end());747}748}749i++;750}751MutableSpace::set_top(value);752}753754void MutableNUMASpace::clear(bool mangle_space) {755MutableSpace::set_top(bottom());756for (int i = 0; i < lgrp_spaces()->length(); i++) {757// Never mangle NUMA spaces because the mangling will758// bind the memory to a possibly unwanted lgroup.759lgrp_spaces()->at(i)->space()->clear(SpaceDecorator::DontMangle);760}761}762763/*764Linux supports static memory binding, therefore the most part of the765logic dealing with the possible invalid page allocation is effectively766disabled. Besides there is no notion of the home node in Linux. A767thread is allowed to migrate freely. Although the scheduler is rather768reluctant to move threads between the nodes. We check for the current769node every allocation. And with a high probability a thread stays on770the same node for some time allowing local access to recently allocated771objects.772*/773774HeapWord* MutableNUMASpace::allocate(size_t size) {775Thread* thr = Thread::current();776int lgrp_id = thr->lgrp_id();777if (lgrp_id == -1 || !os::numa_has_group_homing()) {778lgrp_id = os::numa_get_group_id();779thr->set_lgrp_id(lgrp_id);780}781782int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);783784// It is possible that a new CPU has been hotplugged and785// we haven't reshaped the space accordingly.786if (i == -1) {787i = os::random() % lgrp_spaces()->length();788}789790LGRPSpace* ls = lgrp_spaces()->at(i);791MutableSpace *s = ls->space();792HeapWord *p = s->allocate(size);793794if (p != NULL) {795size_t remainder = s->free_in_words();796if (remainder < CollectedHeap::min_fill_size() && remainder > 0) {797s->set_top(s->top() - size);798p = NULL;799}800}801if (p != NULL) {802if (top() < s->top()) { // Keep _top updated.803MutableSpace::set_top(s->top());804}805}806// Make the page allocation happen here if there is no static binding..807if (p != NULL && !os::numa_has_static_binding()) {808for (HeapWord *i = p; i < p + size; i += os::vm_page_size() >> LogHeapWordSize) {809*(int*)i = 0;810}811}812if (p == NULL) {813ls->set_allocation_failed();814}815return p;816}817818// This version is lock-free.819HeapWord* MutableNUMASpace::cas_allocate(size_t size) {820Thread* thr = Thread::current();821int lgrp_id = thr->lgrp_id();822if (lgrp_id == -1 || !os::numa_has_group_homing()) {823lgrp_id = os::numa_get_group_id();824thr->set_lgrp_id(lgrp_id);825}826827int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);828// It is possible that a new CPU has been hotplugged and829// we haven't reshaped the space accordingly.830if (i == -1) {831i = os::random() % lgrp_spaces()->length();832}833LGRPSpace *ls = lgrp_spaces()->at(i);834MutableSpace *s = ls->space();835HeapWord *p = s->cas_allocate(size);836if (p != NULL) {837size_t remainder = pointer_delta(s->end(), p + size);838if (remainder < CollectedHeap::min_fill_size() && remainder > 0) {839if (s->cas_deallocate(p, size)) {840// We were the last to allocate and created a fragment less than841// a minimal object.842p = NULL;843} else {844guarantee(false, "Deallocation should always succeed");845}846}847}848if (p != NULL) {849HeapWord* cur_top, *cur_chunk_top = p + size;850while ((cur_top = top()) < cur_chunk_top) { // Keep _top updated.851if (Atomic::cmpxchg_ptr(cur_chunk_top, top_addr(), cur_top) == cur_top) {852break;853}854}855}856857// Make the page allocation happen here if there is no static binding.858if (p != NULL && !os::numa_has_static_binding() ) {859for (HeapWord *i = p; i < p + size; i += os::vm_page_size() >> LogHeapWordSize) {860*(int*)i = 0;861}862}863if (p == NULL) {864ls->set_allocation_failed();865}866return p;867}868869void MutableNUMASpace::print_short_on(outputStream* st) const {870MutableSpace::print_short_on(st);871st->print(" (");872for (int i = 0; i < lgrp_spaces()->length(); i++) {873st->print("lgrp %d: ", lgrp_spaces()->at(i)->lgrp_id());874lgrp_spaces()->at(i)->space()->print_short_on(st);875if (i < lgrp_spaces()->length() - 1) {876st->print(", ");877}878}879st->print(")");880}881882void MutableNUMASpace::print_on(outputStream* st) const {883MutableSpace::print_on(st);884for (int i = 0; i < lgrp_spaces()->length(); i++) {885LGRPSpace *ls = lgrp_spaces()->at(i);886st->print(" lgrp %d", ls->lgrp_id());887ls->space()->print_on(st);888if (NUMAStats) {889for (int i = 0; i < lgrp_spaces()->length(); i++) {890lgrp_spaces()->at(i)->accumulate_statistics(page_size());891}892st->print(" local/remote/unbiased/uncommitted: %dK/%dK/%dK/%dK, large/small pages: %d/%d\n",893ls->space_stats()->_local_space / K,894ls->space_stats()->_remote_space / K,895ls->space_stats()->_unbiased_space / K,896ls->space_stats()->_uncommited_space / K,897ls->space_stats()->_large_pages,898ls->space_stats()->_small_pages);899}900}901}902903void MutableNUMASpace::verify() {904// This can be called after setting an arbitary value to the space's top,905// so an object can cross the chunk boundary. We ensure the parsablity906// of the space and just walk the objects in linear fashion.907ensure_parsability();908MutableSpace::verify();909}910911// Scan pages and gather stats about page placement and size.912void MutableNUMASpace::LGRPSpace::accumulate_statistics(size_t page_size) {913clear_space_stats();914char *start = (char*)round_to((intptr_t) space()->bottom(), page_size);915char* end = (char*)round_down((intptr_t) space()->end(), page_size);916if (start < end) {917for (char *p = start; p < end;) {918os::page_info info;919if (os::get_page_info(p, &info)) {920if (info.size > 0) {921if (info.size > (size_t)os::vm_page_size()) {922space_stats()->_large_pages++;923} else {924space_stats()->_small_pages++;925}926if (info.lgrp_id == lgrp_id()) {927space_stats()->_local_space += info.size;928} else {929space_stats()->_remote_space += info.size;930}931p += info.size;932} else {933p += os::vm_page_size();934space_stats()->_uncommited_space += os::vm_page_size();935}936} else {937return;938}939}940}941space_stats()->_unbiased_space = pointer_delta(start, space()->bottom(), sizeof(char)) +942pointer_delta(space()->end(), end, sizeof(char));943944}945946// Scan page_count pages and verify if they have the right size and right placement.947// If invalid pages are found they are freed in hope that subsequent reallocation948// will be more successful.949void MutableNUMASpace::LGRPSpace::scan_pages(size_t page_size, size_t page_count)950{951char* range_start = (char*)round_to((intptr_t) space()->bottom(), page_size);952char* range_end = (char*)round_down((intptr_t) space()->end(), page_size);953954if (range_start > last_page_scanned() || last_page_scanned() >= range_end) {955set_last_page_scanned(range_start);956}957958char *scan_start = last_page_scanned();959char* scan_end = MIN2(scan_start + page_size * page_count, range_end);960961os::page_info page_expected, page_found;962page_expected.size = page_size;963page_expected.lgrp_id = lgrp_id();964965char *s = scan_start;966while (s < scan_end) {967char *e = os::scan_pages(s, (char*)scan_end, &page_expected, &page_found);968if (e == NULL) {969break;970}971if (e != scan_end) {972assert(e < scan_end, err_msg("e: " PTR_FORMAT " scan_end: " PTR_FORMAT, e, scan_end));973974if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id())975&& page_expected.size != 0) {976os::free_memory(s, pointer_delta(e, s, sizeof(char)), page_size);977}978page_expected = page_found;979}980s = e;981}982983set_last_page_scanned(scan_end);984}985986987