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

Sat, 07 Nov 2020 10:30:02 +0800

author
aoqi
date
Sat, 07 Nov 2020 10:30:02 +0800
changeset 10026
8c95980d0b66
parent 6876
710a3c8b516e
permissions
-rw-r--r--

Added tag mips-jdk8u275-b01 for changeset d3b4d62f391f

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 *
aoqi@0 23 */
aoqi@0 24
aoqi@0 25 #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP
aoqi@0 26 #define SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP
aoqi@0 27
aoqi@0 28 #include "utilities/macros.hpp"
aoqi@0 29 #if INCLUDE_ALL_GCS
aoqi@0 30 #include "gc_implementation/shared/gcUtil.hpp"
aoqi@0 31 #include "gc_implementation/shared/mutableSpace.hpp"
aoqi@0 32 #endif // INCLUDE_ALL_GCS
aoqi@0 33
aoqi@0 34 /*
aoqi@0 35 * The NUMA-aware allocator (MutableNUMASpace) is basically a modification
aoqi@0 36 * of MutableSpace which preserves interfaces but implements different
aoqi@0 37 * functionality. The space is split into chunks for each locality group
aoqi@0 38 * (resizing for adaptive size policy is also supported). For each thread
aoqi@0 39 * allocations are performed in the chunk corresponding to the home locality
aoqi@0 40 * group of the thread. Whenever any chunk fills-in the young generation
aoqi@0 41 * collection occurs.
aoqi@0 42 * The chunks can be also be adaptively resized. The idea behind the adaptive
aoqi@0 43 * sizing is to reduce the loss of the space in the eden due to fragmentation.
aoqi@0 44 * The main cause of fragmentation is uneven allocation rates of threads.
aoqi@0 45 * The allocation rate difference between locality groups may be caused either by
aoqi@0 46 * application specifics or by uneven LWP distribution by the OS. Besides,
aoqi@0 47 * application can have less threads then the number of locality groups.
aoqi@0 48 * In order to resize the chunk we measure the allocation rate of the
aoqi@0 49 * application between collections. After that we reshape the chunks to reflect
aoqi@0 50 * the allocation rate pattern. The AdaptiveWeightedAverage exponentially
aoqi@0 51 * decaying average is used to smooth the measurements. The NUMASpaceResizeRate
aoqi@0 52 * parameter is used to control the adaptation speed by restricting the number of
aoqi@0 53 * bytes that can be moved during the adaptation phase.
aoqi@0 54 * Chunks may contain pages from a wrong locality group. The page-scanner has
aoqi@0 55 * been introduced to address the problem. Remote pages typically appear due to
aoqi@0 56 * the memory shortage in the target locality group. Besides Solaris would
aoqi@0 57 * allocate a large page from the remote locality group even if there are small
aoqi@0 58 * local pages available. The page-scanner scans the pages right after the
aoqi@0 59 * collection and frees remote pages in hope that subsequent reallocation would
aoqi@0 60 * be more successful. This approach proved to be useful on systems with high
aoqi@0 61 * load where multiple processes are competing for the memory.
aoqi@0 62 */
aoqi@0 63
aoqi@0 64 class MutableNUMASpace : public MutableSpace {
aoqi@0 65 friend class VMStructs;
aoqi@0 66
aoqi@0 67 class LGRPSpace : public CHeapObj<mtGC> {
aoqi@0 68 int _lgrp_id;
aoqi@0 69 MutableSpace* _space;
aoqi@0 70 MemRegion _invalid_region;
aoqi@0 71 AdaptiveWeightedAverage *_alloc_rate;
aoqi@0 72 bool _allocation_failed;
aoqi@0 73
aoqi@0 74 struct SpaceStats {
aoqi@0 75 size_t _local_space, _remote_space, _unbiased_space, _uncommited_space;
aoqi@0 76 size_t _large_pages, _small_pages;
aoqi@0 77
aoqi@0 78 SpaceStats() {
aoqi@0 79 _local_space = 0;
aoqi@0 80 _remote_space = 0;
aoqi@0 81 _unbiased_space = 0;
aoqi@0 82 _uncommited_space = 0;
aoqi@0 83 _large_pages = 0;
aoqi@0 84 _small_pages = 0;
aoqi@0 85 }
aoqi@0 86 };
aoqi@0 87
aoqi@0 88 SpaceStats _space_stats;
aoqi@0 89
aoqi@0 90 char* _last_page_scanned;
aoqi@0 91 char* last_page_scanned() { return _last_page_scanned; }
aoqi@0 92 void set_last_page_scanned(char* p) { _last_page_scanned = p; }
aoqi@0 93 public:
aoqi@0 94 LGRPSpace(int l, size_t alignment) : _lgrp_id(l), _last_page_scanned(NULL), _allocation_failed(false) {
aoqi@0 95 _space = new MutableSpace(alignment);
aoqi@0 96 _alloc_rate = new AdaptiveWeightedAverage(NUMAChunkResizeWeight);
aoqi@0 97 }
aoqi@0 98 ~LGRPSpace() {
aoqi@0 99 delete _space;
aoqi@0 100 delete _alloc_rate;
aoqi@0 101 }
aoqi@0 102
aoqi@0 103 void add_invalid_region(MemRegion r) {
aoqi@0 104 if (!_invalid_region.is_empty()) {
aoqi@0 105 _invalid_region.set_start(MIN2(_invalid_region.start(), r.start()));
aoqi@0 106 _invalid_region.set_end(MAX2(_invalid_region.end(), r.end()));
aoqi@0 107 } else {
aoqi@0 108 _invalid_region = r;
aoqi@0 109 }
aoqi@0 110 }
aoqi@0 111
aoqi@0 112 static bool equals(void* lgrp_id_value, LGRPSpace* p) {
aoqi@0 113 return *(int*)lgrp_id_value == p->lgrp_id();
aoqi@0 114 }
aoqi@0 115
aoqi@0 116 // Report a failed allocation.
aoqi@0 117 void set_allocation_failed() { _allocation_failed = true; }
aoqi@0 118
aoqi@0 119 void sample() {
aoqi@0 120 // If there was a failed allocation make allocation rate equal
aoqi@0 121 // to the size of the whole chunk. This ensures the progress of
aoqi@0 122 // the adaptation process.
aoqi@0 123 size_t alloc_rate_sample;
aoqi@0 124 if (_allocation_failed) {
aoqi@0 125 alloc_rate_sample = space()->capacity_in_bytes();
aoqi@0 126 _allocation_failed = false;
aoqi@0 127 } else {
aoqi@0 128 alloc_rate_sample = space()->used_in_bytes();
aoqi@0 129 }
aoqi@0 130 alloc_rate()->sample(alloc_rate_sample);
aoqi@0 131 }
aoqi@0 132
aoqi@0 133 MemRegion invalid_region() const { return _invalid_region; }
aoqi@0 134 void set_invalid_region(MemRegion r) { _invalid_region = r; }
aoqi@0 135 int lgrp_id() const { return _lgrp_id; }
aoqi@0 136 MutableSpace* space() const { return _space; }
aoqi@0 137 AdaptiveWeightedAverage* alloc_rate() const { return _alloc_rate; }
aoqi@0 138 void clear_alloc_rate() { _alloc_rate->clear(); }
aoqi@0 139 SpaceStats* space_stats() { return &_space_stats; }
aoqi@0 140 void clear_space_stats() { _space_stats = SpaceStats(); }
aoqi@0 141
aoqi@0 142 void accumulate_statistics(size_t page_size);
aoqi@0 143 void scan_pages(size_t page_size, size_t page_count);
aoqi@0 144 };
aoqi@0 145
aoqi@0 146 GrowableArray<LGRPSpace*>* _lgrp_spaces;
aoqi@0 147 size_t _page_size;
aoqi@0 148 unsigned _adaptation_cycles, _samples_count;
aoqi@0 149
aoqi@0 150 void set_page_size(size_t psz) { _page_size = psz; }
aoqi@0 151 size_t page_size() const { return _page_size; }
aoqi@0 152
aoqi@0 153 unsigned adaptation_cycles() { return _adaptation_cycles; }
aoqi@0 154 void set_adaptation_cycles(int v) { _adaptation_cycles = v; }
aoqi@0 155
aoqi@0 156 unsigned samples_count() { return _samples_count; }
aoqi@0 157 void increment_samples_count() { ++_samples_count; }
aoqi@0 158
aoqi@0 159 size_t _base_space_size;
aoqi@0 160 void set_base_space_size(size_t v) { _base_space_size = v; }
aoqi@0 161 size_t base_space_size() const { return _base_space_size; }
aoqi@0 162
aoqi@0 163 // Check if the NUMA topology has changed. Add and remove spaces if needed.
aoqi@0 164 // The update can be forced by setting the force parameter equal to true.
aoqi@0 165 bool update_layout(bool force);
aoqi@0 166 // Bias region towards the lgrp.
aoqi@0 167 void bias_region(MemRegion mr, int lgrp_id);
aoqi@0 168 // Free pages in a given region.
aoqi@0 169 void free_region(MemRegion mr);
aoqi@0 170 // Get current chunk size.
aoqi@0 171 size_t current_chunk_size(int i);
aoqi@0 172 // Get default chunk size (equally divide the space).
aoqi@0 173 size_t default_chunk_size();
aoqi@0 174 // Adapt the chunk size to follow the allocation rate.
aoqi@0 175 size_t adaptive_chunk_size(int i, size_t limit);
aoqi@0 176 // Scan and free invalid pages.
aoqi@0 177 void scan_pages(size_t page_count);
aoqi@0 178 // Return the bottom_region and the top_region. Align them to page_size() boundary.
aoqi@0 179 // |------------------new_region---------------------------------|
aoqi@0 180 // |----bottom_region--|---intersection---|------top_region------|
aoqi@0 181 void select_tails(MemRegion new_region, MemRegion intersection,
aoqi@0 182 MemRegion* bottom_region, MemRegion *top_region);
aoqi@0 183 // Try to merge the invalid region with the bottom or top region by decreasing
aoqi@0 184 // the intersection area. Return the invalid_region aligned to the page_size()
aoqi@0 185 // boundary if it's inside the intersection. Return non-empty invalid_region
aoqi@0 186 // if it lies inside the intersection (also page-aligned).
aoqi@0 187 // |------------------new_region---------------------------------|
aoqi@0 188 // |----------------|-------invalid---|--------------------------|
aoqi@0 189 // |----bottom_region--|---intersection---|------top_region------|
aoqi@0 190 void merge_regions(MemRegion new_region, MemRegion* intersection,
aoqi@0 191 MemRegion *invalid_region);
aoqi@0 192
aoqi@0 193 public:
aoqi@0 194 GrowableArray<LGRPSpace*>* lgrp_spaces() const { return _lgrp_spaces; }
aoqi@0 195 MutableNUMASpace(size_t alignment);
aoqi@0 196 virtual ~MutableNUMASpace();
aoqi@0 197 // Space initialization.
aoqi@0 198 virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space, bool setup_pages = SetupPages);
aoqi@0 199 // Update space layout if necessary. Do all adaptive resizing job.
aoqi@0 200 virtual void update();
aoqi@0 201 // Update allocation rate averages.
aoqi@0 202 virtual void accumulate_statistics();
aoqi@0 203
aoqi@0 204 virtual void clear(bool mangle_space);
aoqi@0 205 virtual void mangle_unused_area() PRODUCT_RETURN;
aoqi@0 206 virtual void mangle_unused_area_complete() PRODUCT_RETURN;
aoqi@0 207 virtual void mangle_region(MemRegion mr) PRODUCT_RETURN;
aoqi@0 208 virtual void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
aoqi@0 209 virtual void check_mangled_unused_area_complete() PRODUCT_RETURN;
aoqi@0 210 virtual void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
aoqi@0 211 virtual void set_top_for_allocations() PRODUCT_RETURN;
aoqi@0 212
aoqi@0 213 virtual void ensure_parsability();
aoqi@0 214 virtual size_t used_in_words() const;
aoqi@0 215 virtual size_t free_in_words() const;
aoqi@0 216
aoqi@0 217 using MutableSpace::capacity_in_words;
aoqi@0 218 virtual size_t capacity_in_words(Thread* thr) const;
aoqi@0 219 virtual size_t tlab_capacity(Thread* thr) const;
aoqi@0 220 virtual size_t tlab_used(Thread* thr) const;
aoqi@0 221 virtual size_t unsafe_max_tlab_alloc(Thread* thr) const;
aoqi@0 222
aoqi@0 223 // Allocation (return NULL if full)
aoqi@0 224 virtual HeapWord* allocate(size_t word_size);
aoqi@0 225 virtual HeapWord* cas_allocate(size_t word_size);
aoqi@0 226
aoqi@0 227 // Debugging
aoqi@0 228 virtual void print_on(outputStream* st) const;
aoqi@0 229 virtual void print_short_on(outputStream* st) const;
aoqi@0 230 virtual void verify();
aoqi@0 231
aoqi@0 232 virtual void set_top(HeapWord* value);
aoqi@0 233 };
aoqi@0 234
aoqi@0 235 #endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP

mercurial