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/g1/g1NUMA.hpp"
27 #include "gc/g1/heapRegion.hpp"
28 #include "logging/log.hpp"
29 #include "runtime/globals.hpp"
30 #include "runtime/os.hpp"
31
32 G1NUMA* G1NUMA::_inst = NULL;
33
34 size_t G1NUMA::region_size() const {
35 assert(_region_size > 0, "Heap region size is not yet set");
36 return _region_size;
37 }
38
39 size_t G1NUMA::page_size() const {
40 assert(_page_size > 0, "Page size not is yet set");
41 return _page_size;
42 }
43
44 bool G1NUMA::is_enabled() const { return num_active_nodes() > 1; }
45
46 G1NUMA* G1NUMA::create() {
47 guarantee(_inst == NULL, "Should be called once.");
48 _inst = new G1NUMA();
57 return _inst;
58 }
59
60 // Returns memory node ids
61 const int* G1NUMA::node_ids() const {
62 return _node_ids;
63 }
64
65 uint G1NUMA::index_of_node_id(int node_id) const {
66 assert(node_id >= 0, "invalid node id %d", node_id);
67 assert(node_id < _len_node_id_to_index_map, "invalid node id %d", node_id);
68 uint node_index = _node_id_to_index_map[node_id];
69 assert(node_index != G1NUMA::UnknownNodeIndex,
70 "invalid node id %d", node_id);
71 return node_index;
72 }
73
74 G1NUMA::G1NUMA() :
75 _node_id_to_index_map(NULL), _len_node_id_to_index_map(0),
76 _node_ids(NULL), _num_active_node_ids(0),
77 _region_size(0), _page_size(0) {
78 }
79
80 void G1NUMA::initialize_without_numa() {
81 // If NUMA is not enabled or supported, initialize as having a singel node.
82 _num_active_node_ids = 1;
83 _node_ids = NEW_C_HEAP_ARRAY(int, _num_active_node_ids, mtGC);
84 _node_ids[0] = 0;
85 // Map index 0 to node 0
86 _len_node_id_to_index_map = 1;
87 _node_id_to_index_map = NEW_C_HEAP_ARRAY(uint, _len_node_id_to_index_map, mtGC);
88 _node_id_to_index_map[0] = 0;
89 }
90
91 void G1NUMA::initialize(bool use_numa) {
92 if (!use_numa) {
93 initialize_without_numa();
94 return;
95 }
96
97 assert(UseNUMA, "Invariant");
102 _num_active_node_ids = (uint)os::numa_get_leaf_groups(_node_ids, num_node_ids);
103
104 int max_node_id = 0;
105 for (uint i = 0; i < _num_active_node_ids; i++) {
106 max_node_id = MAX2(max_node_id, _node_ids[i]);
107 }
108
109 // Create a mapping between node_id and index.
110 _len_node_id_to_index_map = max_node_id + 1;
111 _node_id_to_index_map = NEW_C_HEAP_ARRAY(uint, _len_node_id_to_index_map, mtGC);
112
113 // Set all indices with unknown node id.
114 for (int i = 0; i < _len_node_id_to_index_map; i++) {
115 _node_id_to_index_map[i] = G1NUMA::UnknownNodeIndex;
116 }
117
118 // Set the indices for the actually retrieved node ids.
119 for (uint i = 0; i < _num_active_node_ids; i++) {
120 _node_id_to_index_map[_node_ids[i]] = i;
121 }
122 }
123
124 G1NUMA::~G1NUMA() {
125 FREE_C_HEAP_ARRAY(int, _node_id_to_index_map);
126 FREE_C_HEAP_ARRAY(int, _node_ids);
127 }
128
129 void G1NUMA::set_region_info(size_t region_size, size_t page_size) {
130 _region_size = region_size;
131 _page_size = page_size;
132 }
133
134 uint G1NUMA::num_active_nodes() const {
135 assert(_num_active_node_ids > 0, "just checking");
136 return _num_active_node_ids;
137 }
138
139 uint G1NUMA::index_of_current_thread() const {
140 if (!is_enabled()) {
141 return 0;
142 }
143 return index_of_node_id(os::numa_get_group_id());
144 }
198 // 2. G1HeapRegionSize(_region_size) is smaller than page size.
199 // Memory will be touched one page at a time because G1RegionToSpaceMapper commits
200 // pages one by one.
201 // * Page #: |-----0----||-----1----||-----2----||-----3----||-----4----||-----5----||-----6----||-----7----|
202 // * HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-|
203 // * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----|
204 void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) {
205 if (!is_enabled()) {
206 return;
207 }
208
209 if (size_in_bytes == 0) {
210 return;
211 }
212
213 uint node_index = preferred_node_index_for_index(region_index);
214
215 assert(is_aligned(aligned_address, page_size()), "Given address (" PTR_FORMAT ") should be aligned.", p2i(aligned_address));
216 assert(is_aligned(size_in_bytes, page_size()), "Given size (" SIZE_FORMAT ") should be aligned.", size_in_bytes);
217
218 log_debug(gc, heap, numa)("Request memory [" PTR_FORMAT ", " PTR_FORMAT ") to be numa id (%d).",
219 p2i(aligned_address), p2i((char*)aligned_address + size_in_bytes), _node_ids[node_index]);
220 os::numa_make_local((char*)aligned_address, size_in_bytes, _node_ids[node_index]);
221 }
222
223 uint G1NUMA::max_search_depth() const {
224 // Multiple of 3 is just random number to limit iterations.
225 // There would be some cases that 1 page may be consisted of multiple HeapRegions.
226 return 3 * MAX2((uint)(page_size() / region_size()), (uint)1) * num_active_nodes();
227 }
|
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/g1/g1NUMA.hpp"
27 #include "logging/logStream.hpp"
28 #include "runtime/globals.hpp"
29 #include "runtime/os.hpp"
30
31 G1NUMA* G1NUMA::_inst = NULL;
32
33 size_t G1NUMA::region_size() const {
34 assert(_region_size > 0, "Heap region size is not yet set");
35 return _region_size;
36 }
37
38 size_t G1NUMA::page_size() const {
39 assert(_page_size > 0, "Page size not is yet set");
40 return _page_size;
41 }
42
43 bool G1NUMA::is_enabled() const { return num_active_nodes() > 1; }
44
45 G1NUMA* G1NUMA::create() {
46 guarantee(_inst == NULL, "Should be called once.");
47 _inst = new G1NUMA();
56 return _inst;
57 }
58
59 // Returns memory node ids
60 const int* G1NUMA::node_ids() const {
61 return _node_ids;
62 }
63
64 uint G1NUMA::index_of_node_id(int node_id) const {
65 assert(node_id >= 0, "invalid node id %d", node_id);
66 assert(node_id < _len_node_id_to_index_map, "invalid node id %d", node_id);
67 uint node_index = _node_id_to_index_map[node_id];
68 assert(node_index != G1NUMA::UnknownNodeIndex,
69 "invalid node id %d", node_id);
70 return node_index;
71 }
72
73 G1NUMA::G1NUMA() :
74 _node_id_to_index_map(NULL), _len_node_id_to_index_map(0),
75 _node_ids(NULL), _num_active_node_ids(0),
76 _region_size(0), _page_size(0), _stats(NULL) {
77 }
78
79 void G1NUMA::initialize_without_numa() {
80 // If NUMA is not enabled or supported, initialize as having a singel node.
81 _num_active_node_ids = 1;
82 _node_ids = NEW_C_HEAP_ARRAY(int, _num_active_node_ids, mtGC);
83 _node_ids[0] = 0;
84 // Map index 0 to node 0
85 _len_node_id_to_index_map = 1;
86 _node_id_to_index_map = NEW_C_HEAP_ARRAY(uint, _len_node_id_to_index_map, mtGC);
87 _node_id_to_index_map[0] = 0;
88 }
89
90 void G1NUMA::initialize(bool use_numa) {
91 if (!use_numa) {
92 initialize_without_numa();
93 return;
94 }
95
96 assert(UseNUMA, "Invariant");
101 _num_active_node_ids = (uint)os::numa_get_leaf_groups(_node_ids, num_node_ids);
102
103 int max_node_id = 0;
104 for (uint i = 0; i < _num_active_node_ids; i++) {
105 max_node_id = MAX2(max_node_id, _node_ids[i]);
106 }
107
108 // Create a mapping between node_id and index.
109 _len_node_id_to_index_map = max_node_id + 1;
110 _node_id_to_index_map = NEW_C_HEAP_ARRAY(uint, _len_node_id_to_index_map, mtGC);
111
112 // Set all indices with unknown node id.
113 for (int i = 0; i < _len_node_id_to_index_map; i++) {
114 _node_id_to_index_map[i] = G1NUMA::UnknownNodeIndex;
115 }
116
117 // Set the indices for the actually retrieved node ids.
118 for (uint i = 0; i < _num_active_node_ids; i++) {
119 _node_id_to_index_map[_node_ids[i]] = i;
120 }
121
122 _stats = new G1NUMAStats(_node_ids, _num_active_node_ids);
123 }
124
125 G1NUMA::~G1NUMA() {
126 delete _stats;
127 FREE_C_HEAP_ARRAY(int, _node_id_to_index_map);
128 FREE_C_HEAP_ARRAY(int, _node_ids);
129 }
130
131 void G1NUMA::set_region_info(size_t region_size, size_t page_size) {
132 _region_size = region_size;
133 _page_size = page_size;
134 }
135
136 uint G1NUMA::num_active_nodes() const {
137 assert(_num_active_node_ids > 0, "just checking");
138 return _num_active_node_ids;
139 }
140
141 uint G1NUMA::index_of_current_thread() const {
142 if (!is_enabled()) {
143 return 0;
144 }
145 return index_of_node_id(os::numa_get_group_id());
146 }
200 // 2. G1HeapRegionSize(_region_size) is smaller than page size.
201 // Memory will be touched one page at a time because G1RegionToSpaceMapper commits
202 // pages one by one.
203 // * Page #: |-----0----||-----1----||-----2----||-----3----||-----4----||-----5----||-----6----||-----7----|
204 // * HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-|
205 // * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----|
206 void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) {
207 if (!is_enabled()) {
208 return;
209 }
210
211 if (size_in_bytes == 0) {
212 return;
213 }
214
215 uint node_index = preferred_node_index_for_index(region_index);
216
217 assert(is_aligned(aligned_address, page_size()), "Given address (" PTR_FORMAT ") should be aligned.", p2i(aligned_address));
218 assert(is_aligned(size_in_bytes, page_size()), "Given size (" SIZE_FORMAT ") should be aligned.", size_in_bytes);
219
220 log_trace(gc, heap, numa)("Request memory [" PTR_FORMAT ", " PTR_FORMAT ") to be NUMA id (%d)",
221 p2i(aligned_address), p2i((char*)aligned_address + size_in_bytes), _node_ids[node_index]);
222 os::numa_make_local((char*)aligned_address, size_in_bytes, _node_ids[node_index]);
223 }
224
225 uint G1NUMA::max_search_depth() const {
226 // Multiple of 3 is just random number to limit iterations.
227 // There would be some cases that 1 page may be consisted of multiple HeapRegions.
228 return 3 * MAX2((uint)(page_size() / region_size()), (uint)1) * num_active_nodes();
229 }
230
231 void G1NUMA::update_statistics(G1NUMAStats::NodeDataItems phase,
232 uint requested_node_index,
233 uint allocated_node_index) {
234 if (_stats == NULL) {
235 return;
236 }
237
238 uint converted_req_index;
239 if(requested_node_index < _num_active_node_ids) {
240 converted_req_index = requested_node_index;
241 } else {
242 assert(requested_node_index == AnyNodeIndex,
243 "Requested node index %u should be AnyNodeIndex.", requested_node_index);
244 converted_req_index = _num_active_node_ids;
245 }
246 _stats->update(phase, converted_req_index, allocated_node_index);
247 }
248
249 void G1NUMA::copy_statistics(G1NUMAStats::NodeDataItems phase,
250 uint requested_node_index,
251 size_t* allocated_stat) {
252 if (_stats == NULL) {
253 return;
254 }
255
256 _stats->copy(phase, requested_node_index, allocated_stat);
257 }
258
259 void G1NUMA::print() const {
260 if (_stats == NULL) {
261 return;
262 }
263
264 _stats->print();
265 }
266
267 NodeIndexCheckClosure::NodeIndexCheckClosure(G1NUMA* numa, LogStream* ls) :
268 _numa(numa), _ls(ls) {
269
270 uint num_nodes = _numa->num_active_nodes();
271 _matched = NEW_C_HEAP_ARRAY(uint, num_nodes, mtGC);
272 _total = NEW_C_HEAP_ARRAY(uint, num_nodes, mtGC);
273 memset(_matched, 0, sizeof(uint) * num_nodes);
274 memset(_total, 0, sizeof(uint) * num_nodes);
275 }
276
277 NodeIndexCheckClosure::~NodeIndexCheckClosure() {
278 _ls->print("NUMA region verification (id: matched / total): ");
279 const int* numa_ids = _numa->node_ids();
280 for (uint i = 0; i < _numa->num_active_nodes(); i++) {
281 _ls->print("%d: %u / %u, ", numa_ids[i], _matched[i], _total[i]);
282 }
283
284 FREE_C_HEAP_ARRAY(uint, _matched);
285 FREE_C_HEAP_ARRAY(uint, _total);
286 }
287
288 bool NodeIndexCheckClosure::do_heap_region(HeapRegion* hr) {
289 uint preferred_node_index = _numa->preferred_node_index_for_index(hr->hrm_index());
290 uint active_node_index;
291
292 if (hr->is_free() && !AlwaysPreTouch) {
293 active_node_index = G1NUMA::UnknownNodeIndex;
294 } else {
295 active_node_index = _numa->index_of_address(hr->bottom());
296 }
297
298 if (preferred_node_index == active_node_index) {
299 _matched[preferred_node_index]++;
300 }
301 _total[preferred_node_index]++;
302
303 return false;
304 }
|