1/*
2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24#include "precompiled.hpp"
25
26// Included early because the NMT flags don't include it.
27#include "utilities/macros.hpp"
28
29#if INCLUDE_NMT
30
31#include "services/memTracker.hpp"
32#include "services/virtualMemoryTracker.hpp"
33#include "utilities/globalDefinitions.hpp"
34#include "unittest.hpp"
35
36namespace {
37 struct R {
38 address _addr;
39 size_t _size;
40 };
41}
42
43#define check(rmr, regions) check_inner((rmr), (regions), ARRAY_SIZE(regions), __FILE__, __LINE__)
44
45#define check_empty(rmr) \
46 do { \
47 check_inner((rmr), NULL, 0, __FILE__, __LINE__); \
48 } while (false)
49
50static void check_inner(ReservedMemoryRegion* rmr, R* regions, size_t regions_size, const char* file, int line) {
51 CommittedRegionIterator iter = rmr->iterate_committed_regions();
52 size_t i = 0;
53 size_t size = 0;
54
55#define WHERE " from " << file << ":" << line
56
57 for (const CommittedMemoryRegion* region = iter.next(); region != NULL; region = iter.next()) {
58 EXPECT_LT(i, regions_size) << WHERE;
59 EXPECT_EQ(region->base(), regions[i]._addr) << WHERE;
60 EXPECT_EQ(region->size(), regions[i]._size) << WHERE;
61 size += region->size();
62 i++;
63 }
64
65 EXPECT_EQ(i, regions_size) << WHERE;
66 EXPECT_EQ(size, rmr->committed_size()) << WHERE;
67}
68
69class VirtualMemoryTrackerTest {
70public:
71 static void test_add_committed_region_adjacent() {
72 VirtualMemoryTracker::initialize(NMT_detail);
73 VirtualMemoryTracker::late_initialize(NMT_detail);
74
75 address addr = (address)0x10000000;
76 size_t size = 0x01000000;
77
78 address frame1 = (address)0x1234;
79 address frame2 = (address)0x1235;
80
81 NativeCallStack stack(&frame1, 1);
82 NativeCallStack stack2(&frame2, 1);
83
84 // Add the reserved memory
85 VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
86
87 // Fetch the added RMR added above
88 ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
89
90 ASSERT_EQ(rmr->size(), size);
91 ASSERT_EQ(rmr->base(), addr);
92
93 // Commit Size Granularity
94 const size_t cs = 0x1000;
95
96 // Commit adjacent regions with same stack
97
98 { // Commit one region
99 rmr->add_committed_region(addr + cs, cs, stack);
100 R r[] = { {addr + cs, cs} };
101 check(rmr, r);
102 }
103
104 { // Commit adjacent - lower address
105 rmr->add_committed_region(addr, cs, stack);
106 R r[] = { {addr, 2 * cs} };
107 check(rmr, r);
108 }
109
110 { // Commit adjacent - higher address
111 rmr->add_committed_region(addr + 2 * cs, cs, stack);
112 R r[] = { {addr, 3 * cs} };
113 check(rmr, r);
114 }
115
116 // Cleanup
117 rmr->remove_uncommitted_region(addr, 3 * cs);
118 ASSERT_EQ(rmr->committed_size(), 0u);
119
120
121 // Commit adjacent regions with different stacks
122
123 { // Commit one region
124 rmr->add_committed_region(addr + cs, cs, stack);
125 R r[] = { {addr + cs, cs} };
126 check(rmr, r);
127 }
128
129 { // Commit adjacent - lower address
130 rmr->add_committed_region(addr, cs, stack2);
131 R r[] = { {addr, cs},
132 {addr + cs, cs} };
133 check(rmr, r);
134 }
135
136 { // Commit adjacent - higher address
137 rmr->add_committed_region(addr + 2 * cs, cs, stack2);
138 R r[] = { {addr, cs},
139 {addr + cs, cs},
140 {addr + 2 * cs, cs} };
141 check(rmr, r);
142 }
143
144 // Cleanup
145 rmr->remove_uncommitted_region(addr, 3 * cs);
146 ASSERT_EQ(rmr->committed_size(), 0u);
147 }
148
149 static void test_add_committed_region_adjacent_overlapping() {
150 VirtualMemoryTracker::initialize(NMT_detail);
151 VirtualMemoryTracker::late_initialize(NMT_detail);
152
153 address addr = (address)0x10000000;
154 size_t size = 0x01000000;
155
156 address frame1 = (address)0x1234;
157 address frame2 = (address)0x1235;
158
159 NativeCallStack stack(&frame1, 1);
160 NativeCallStack stack2(&frame2, 1);
161
162 // Add the reserved memory
163 VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
164
165 // Fetch the added RMR added above
166 ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
167
168 ASSERT_EQ(rmr->size(), size);
169 ASSERT_EQ(rmr->base(), addr);
170
171 // Commit Size Granularity
172 const size_t cs = 0x1000;
173
174 // Commit adjacent and overlapping regions with same stack
175
176 { // Commit two non-adjacent regions
177 rmr->add_committed_region(addr, 2 * cs, stack);
178 rmr->add_committed_region(addr + 3 * cs, 2 * cs, stack);
179 R r[] = { {addr, 2 * cs},
180 {addr + 3 * cs, 2 * cs} };
181 check(rmr, r);
182 }
183
184 { // Commit adjacent and overlapping
185 rmr->add_committed_region(addr + 2 * cs, 2 * cs, stack);
186 R r[] = { {addr, 5 * cs} };
187 check(rmr, r);
188 }
189
190 // revert to two non-adjacent regions
191 rmr->remove_uncommitted_region(addr + 2 * cs, cs);
192 ASSERT_EQ(rmr->committed_size(), 4 * cs);
193
194 { // Commit overlapping and adjacent
195 rmr->add_committed_region(addr + cs, 2 * cs, stack);
196 R r[] = { {addr, 5 * cs} };
197 check(rmr, r);
198 }
199
200 // Cleanup
201 rmr->remove_uncommitted_region(addr, 5 * cs);
202 ASSERT_EQ(rmr->committed_size(), 0u);
203
204
205 // Commit adjacent and overlapping regions with different stacks
206
207 { // Commit two non-adjacent regions
208 rmr->add_committed_region(addr, 2 * cs, stack);
209 rmr->add_committed_region(addr + 3 * cs, 2 * cs, stack);
210 R r[] = { {addr, 2 * cs},
211 {addr + 3 * cs, 2 * cs} };
212 check(rmr, r);
213 }
214
215 { // Commit adjacent and overlapping
216 rmr->add_committed_region(addr + 2 * cs, 2 * cs, stack2);
217 R r[] = { {addr, 2 * cs},
218 {addr + 2 * cs, 2 * cs},
219 {addr + 4 * cs, cs} };
220 check(rmr, r);
221 }
222
223 // revert to two non-adjacent regions
224 rmr->add_committed_region(addr, 5 * cs, stack);
225 rmr->remove_uncommitted_region(addr + 2 * cs, cs);
226 ASSERT_EQ(rmr->committed_size(), 4 * cs);
227
228 { // Commit overlapping and adjacent
229 rmr->add_committed_region(addr + cs, 2 * cs, stack2);
230 R r[] = { {addr, cs},
231 {addr + cs, 2 * cs},
232 {addr + 3 * cs, 2 * cs} };
233 check(rmr, r);
234 }
235 }
236
237 static void test_add_committed_region_overlapping() {
238 VirtualMemoryTracker::initialize(NMT_detail);
239 VirtualMemoryTracker::late_initialize(NMT_detail);
240
241 address addr = (address)0x10000000;
242 size_t size = 0x01000000;
243
244 address frame1 = (address)0x1234;
245 address frame2 = (address)0x1235;
246
247 NativeCallStack stack(&frame1, 1);
248 NativeCallStack stack2(&frame2, 1);
249
250 // Add the reserved memory
251 VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
252
253 // Fetch the added RMR added above
254 ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
255
256 ASSERT_EQ(rmr->size(), size);
257 ASSERT_EQ(rmr->base(), addr);
258
259 // Commit Size Granularity
260 const size_t cs = 0x1000;
261
262 // With same stack
263
264 { // Commit one region
265 rmr->add_committed_region(addr, cs, stack);
266 R r[] = { {addr, cs} };
267 check(rmr, r);
268 }
269
270 { // Commit the same region
271 rmr->add_committed_region(addr, cs, stack);
272 R r[] = { {addr, cs} };
273 check(rmr, r);
274 }
275
276 { // Commit a succeeding region
277 rmr->add_committed_region(addr + cs, cs, stack);
278 R r[] = { {addr, 2 * cs} };
279 check(rmr, r);
280 }
281
282 { // Commit over two regions
283 rmr->add_committed_region(addr, 2 * cs, stack);
284 R r[] = { {addr, 2 * cs} };
285 check(rmr, r);
286 }
287
288 {// Commit first part of a region
289 rmr->add_committed_region(addr, cs, stack);
290 R r[] = { {addr, 2 * cs} };
291 check(rmr, r);
292 }
293
294 { // Commit second part of a region
295 rmr->add_committed_region(addr + cs, cs, stack);
296 R r[] = { {addr, 2 * cs} };
297 check(rmr, r);
298 }
299
300 { // Commit a third part
301 rmr->add_committed_region(addr + 2 * cs, cs, stack);
302 R r[] = { {addr, 3 * cs} };
303 check(rmr, r);
304 }
305
306 { // Commit in the middle of a region
307 rmr->add_committed_region(addr + 1 * cs, cs, stack);
308 R r[] = { {addr, 3 * cs} };
309 check(rmr, r);
310 }
311
312 // Cleanup
313 rmr->remove_uncommitted_region(addr, 3 * cs);
314 ASSERT_EQ(rmr->committed_size(), 0u);
315
316 // With preceding region
317
318 rmr->add_committed_region(addr, cs, stack);
319 rmr->add_committed_region(addr + 2 * cs, 3 * cs, stack);
320
321 rmr->add_committed_region(addr + 2 * cs, cs, stack);
322 {
323 R r[] = { {addr, cs},
324 {addr + 2 * cs, 3 * cs} };
325 check(rmr, r);
326 }
327
328 rmr->add_committed_region(addr + 3 * cs, cs, stack);
329 {
330 R r[] = { {addr, cs},
331 {addr + 2 * cs, 3 * cs} };
332 check(rmr, r);
333 }
334
335 rmr->add_committed_region(addr + 4 * cs, cs, stack);
336 {
337 R r[] = { {addr, cs},
338 {addr + 2 * cs, 3 * cs} };
339 check(rmr, r);
340 }
341
342 // Cleanup
343 rmr->remove_uncommitted_region(addr, 5 * cs);
344 ASSERT_EQ(rmr->committed_size(), 0u);
345
346 // With different stacks
347
348 { // Commit one region
349 rmr->add_committed_region(addr, cs, stack);
350 R r[] = { {addr, cs} };
351 check(rmr, r);
352 }
353
354 { // Commit the same region
355 rmr->add_committed_region(addr, cs, stack2);
356 R r[] = { {addr, cs} };
357 check(rmr, r);
358 }
359
360 { // Commit a succeeding region
361 rmr->add_committed_region(addr + cs, cs, stack);
362 R r[] = { {addr, cs},
363 {addr + cs, cs} };
364 check(rmr, r);
365 }
366
367 { // Commit over two regions
368 rmr->add_committed_region(addr, 2 * cs, stack);
369 R r[] = { {addr, 2 * cs} };
370 check(rmr, r);
371 }
372
373 {// Commit first part of a region
374 rmr->add_committed_region(addr, cs, stack2);
375 R r[] = { {addr, cs},
376 {addr + cs, cs} };
377 check(rmr, r);
378 }
379
380 { // Commit second part of a region
381 rmr->add_committed_region(addr + cs, cs, stack2);
382 R r[] = { {addr, 2 * cs} };
383 check(rmr, r);
384 }
385
386 { // Commit a third part
387 rmr->add_committed_region(addr + 2 * cs, cs, stack2);
388 R r[] = { {addr, 3 * cs} };
389 check(rmr, r);
390 }
391
392 { // Commit in the middle of a region
393 rmr->add_committed_region(addr + 1 * cs, cs, stack);
394 R r[] = { {addr, cs},
395 {addr + cs, cs},
396 {addr + 2 * cs, cs} };
397 check(rmr, r);
398 }
399 }
400
401 static void test_add_committed_region() {
402 test_add_committed_region_adjacent();
403 test_add_committed_region_adjacent_overlapping();
404 test_add_committed_region_overlapping();
405 }
406
407 template <size_t S>
408 static void fix(R r[S]) {
409
410 }
411
412 static void test_remove_uncommitted_region() {
413 VirtualMemoryTracker::initialize(NMT_detail);
414 VirtualMemoryTracker::late_initialize(NMT_detail);
415
416 address addr = (address)0x10000000;
417 size_t size = 0x01000000;
418
419 address frame1 = (address)0x1234;
420 address frame2 = (address)0x1235;
421
422 NativeCallStack stack(&frame1, 1);
423 NativeCallStack stack2(&frame2, 1);
424
425 // Add the reserved memory
426 VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
427
428 // Fetch the added RMR added above
429 ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
430
431 ASSERT_EQ(rmr->size(), size);
432 ASSERT_EQ(rmr->base(), addr);
433
434 // Commit Size Granularity
435 const size_t cs = 0x1000;
436
437 { // Commit regions
438 rmr->add_committed_region(addr, 3 * cs, stack);
439 R r[] = { {addr, 3 * cs} };
440 check(rmr, r);
441
442 // Remove only existing
443 rmr->remove_uncommitted_region(addr, 3 * cs);
444 check_empty(rmr);
445 }
446
447 {
448 rmr->add_committed_region(addr + 0 * cs, cs, stack);
449 rmr->add_committed_region(addr + 2 * cs, cs, stack);
450 rmr->add_committed_region(addr + 4 * cs, cs, stack);
451
452 { // Remove first
453 rmr->remove_uncommitted_region(addr, cs);
454 R r[] = { {addr + 2 * cs, cs},
455 {addr + 4 * cs, cs} };
456 check(rmr, r);
457 }
458
459 // add back
460 rmr->add_committed_region(addr, cs, stack);
461
462 { // Remove middle
463 rmr->remove_uncommitted_region(addr + 2 * cs, cs);
464 R r[] = { {addr + 0 * cs, cs},
465 {addr + 4 * cs, cs} };
466 check(rmr, r);
467 }
468
469 // add back
470 rmr->add_committed_region(addr + 2 * cs, cs, stack);
471
472 { // Remove end
473 rmr->remove_uncommitted_region(addr + 4 * cs, cs);
474 R r[] = { {addr + 0 * cs, cs},
475 {addr + 2 * cs, cs} };
476 check(rmr, r);
477 }
478
479 rmr->remove_uncommitted_region(addr, 5 * cs);
480 check_empty(rmr);
481 }
482
483 { // Remove larger region
484 rmr->add_committed_region(addr + 1 * cs, cs, stack);
485 rmr->remove_uncommitted_region(addr, 3 * cs);
486 check_empty(rmr);
487 }
488
489 { // Remove smaller region - in the middle
490 rmr->add_committed_region(addr, 3 * cs, stack);
491 rmr->remove_uncommitted_region(addr + 1 * cs, cs);
492 R r[] = { { addr + 0 * cs, cs},
493 { addr + 2 * cs, cs} };
494 check(rmr, r);
495
496 rmr->remove_uncommitted_region(addr, 3 * cs);
497 check_empty(rmr);
498 }
499
500 { // Remove smaller region - at the beginning
501 rmr->add_committed_region(addr, 3 * cs, stack);
502 rmr->remove_uncommitted_region(addr + 0 * cs, cs);
503 R r[] = { { addr + 1 * cs, 2 * cs} };
504 check(rmr, r);
505
506 rmr->remove_uncommitted_region(addr, 3 * cs);
507 check_empty(rmr);
508 }
509
510 { // Remove smaller region - at the end
511 rmr->add_committed_region(addr, 3 * cs, stack);
512 rmr->remove_uncommitted_region(addr + 2 * cs, cs);
513 R r[] = { { addr, 2 * cs} };
514 check(rmr, r);
515
516 rmr->remove_uncommitted_region(addr, 3 * cs);
517 check_empty(rmr);
518 }
519
520 { // Remove smaller, overlapping region - at the beginning
521 rmr->add_committed_region(addr + 1 * cs, 4 * cs, stack);
522 rmr->remove_uncommitted_region(addr, 2 * cs);
523 R r[] = { { addr + 2 * cs, 3 * cs} };
524 check(rmr, r);
525
526 rmr->remove_uncommitted_region(addr + 1 * cs, 4 * cs);
527 check_empty(rmr);
528 }
529
530 { // Remove smaller, overlapping region - at the end
531 rmr->add_committed_region(addr, 3 * cs, stack);
532 rmr->remove_uncommitted_region(addr + 2 * cs, 2 * cs);
533 R r[] = { { addr, 2 * cs} };
534 check(rmr, r);
535
536 rmr->remove_uncommitted_region(addr, 3 * cs);
537 check_empty(rmr);
538 }
539 }
540};
541
542TEST_VM(VirtualMemoryTracker, add_committed_region) {
543 VirtualMemoryTrackerTest::test_add_committed_region();
544}
545
546TEST_VM(VirtualMemoryTracker, remove_uncommitted_region) {
547 VirtualMemoryTrackerTest::test_remove_uncommitted_region();
548}
549
550#endif // INCLUDE_NMT
551