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 | |
36 | namespace { |
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 | |
50 | static 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 | |
69 | class VirtualMemoryTrackerTest { |
70 | public: |
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 | |
542 | TEST_VM(VirtualMemoryTracker, add_committed_region) { |
543 | VirtualMemoryTrackerTest::test_add_committed_region(); |
544 | } |
545 | |
546 | TEST_VM(VirtualMemoryTracker, remove_uncommitted_region) { |
547 | VirtualMemoryTrackerTest::test_remove_uncommitted_region(); |
548 | } |
549 | |
550 | #endif // INCLUDE_NMT |
551 | |