jdk

Форк
0
/
test_committed_virtualmemory.cpp 
259 строк · 8.9 Кб
1
/*
2
 * Copyright (c) 2018, 2024, 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
#include "nmt/memTracker.hpp"
26
#include "nmt/virtualMemoryTracker.hpp"
27
#include "runtime/thread.hpp"
28
#include "utilities/globalDefinitions.hpp"
29
#include "utilities/macros.hpp"
30
#include "unittest.hpp"
31

32
class CommittedVirtualMemoryTest {
33
public:
34
  static void test() {
35
    Thread* thr = Thread::current();
36
    address stack_end = thr->stack_end();
37
    size_t  stack_size = thr->stack_size();
38

39
    MemTracker::record_thread_stack(stack_end, stack_size);
40

41
    VirtualMemoryTracker::add_reserved_region(stack_end, stack_size, CALLER_PC, mtThreadStack);
42

43
    // snapshot current stack usage
44
    VirtualMemoryTracker::snapshot_thread_stacks();
45

46
    ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(stack_end, stack_size));
47
    ASSERT_TRUE(rmr != nullptr);
48

49
    ASSERT_EQ(rmr->base(), stack_end);
50
    ASSERT_EQ(rmr->size(), stack_size);
51

52
    CommittedRegionIterator iter = rmr->iterate_committed_regions();
53
    int i = 0;
54
    address i_addr = (address)&i;
55
    bool found_i_addr = false;
56

57
    // stack grows downward
58
    address stack_top = stack_end + stack_size;
59
    bool found_stack_top = false;
60

61
    for (const CommittedMemoryRegion* region = iter.next(); region != nullptr; region = iter.next()) {
62
      if (region->base() + region->size() == stack_top) {
63
        ASSERT_TRUE(region->size() <= stack_size);
64
        found_stack_top = true;
65
      }
66

67
      if(i_addr < stack_top && i_addr >= region->base()) {
68
        found_i_addr = true;
69
      }
70

71
      i++;
72
    }
73

74
    // stack and guard pages may be contiguous as one region
75
    ASSERT_TRUE(i >= 1);
76
    ASSERT_TRUE(found_stack_top);
77
    ASSERT_TRUE(found_i_addr);
78
  }
79

80
  static void check_covered_pages(address addr, size_t size, address base, size_t touch_pages, int* page_num) {
81
    const size_t page_sz = os::vm_page_size();
82
    size_t index;
83
    for (index = 0; index < touch_pages; index ++) {
84
      address page_addr = base + page_num[index] * page_sz;
85
      // The range covers this page, marks the page
86
      if (page_addr >= addr && page_addr < addr + size) {
87
        page_num[index] = -1;
88
      }
89
    }
90
  }
91

92
  static void test_committed_region_impl(size_t num_pages, size_t touch_pages, int* page_num) {
93
    const size_t page_sz = os::vm_page_size();
94
    const size_t size = num_pages * page_sz;
95
    char* base = os::reserve_memory(size, !ExecMem, mtThreadStack);
96
    bool result = os::commit_memory(base, size, !ExecMem);
97
    size_t index;
98
    ASSERT_NE(base, (char*)nullptr);
99
    for (index = 0; index < touch_pages; index ++) {
100
      char* touch_addr = base + page_sz * page_num[index];
101
      *touch_addr = 'a';
102
    }
103

104
    address frame = (address)0x1235;
105
    NativeCallStack stack(&frame, 1);
106
    VirtualMemoryTracker::add_reserved_region((address)base, size, stack, mtThreadStack);
107

108
    // trigger the test
109
    VirtualMemoryTracker::snapshot_thread_stacks();
110

111
    ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion((address)base, size));
112
    ASSERT_TRUE(rmr != nullptr);
113

114
    bool precise_tracking_supported = false;
115
    CommittedRegionIterator iter = rmr->iterate_committed_regions();
116
    for (const CommittedMemoryRegion* region = iter.next(); region != nullptr; region = iter.next()) {
117
      if (region->size() == size) {
118
        // platforms that do not support precise tracking.
119
        ASSERT_TRUE(iter.next() == nullptr);
120
        break;
121
      } else {
122
        precise_tracking_supported = true;
123
        check_covered_pages(region->base(), region->size(), (address)base, touch_pages, page_num);
124
      }
125
    }
126

127
    if (precise_tracking_supported) {
128
      // All touched pages should be committed
129
      for (size_t index = 0; index < touch_pages; index ++) {
130
        ASSERT_EQ(page_num[index], -1);
131
      }
132
    }
133

134
    // Cleanup
135
    os::disclaim_memory(base, size);
136
    VirtualMemoryTracker::remove_released_region((address)base, size);
137

138
    rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion((address)base, size));
139
    ASSERT_TRUE(rmr == nullptr);
140
  }
141

142
  static void test_committed_region() {
143
    // On Linux, we scan 1024 pages at a time.
144
    // Here, we test scenario that scans < 1024 pages.
145
    int small_range[] = {3, 9, 46};
146
    int mid_range[] = {0, 45, 100, 399, 400, 1000, 1031};
147
    int large_range[] = {100, 301, 1024, 2047, 2048, 2049, 2050, 3000};
148

149
    test_committed_region_impl(47, 3, small_range);
150
    test_committed_region_impl(1088, 5, mid_range);
151
    test_committed_region_impl(3074, 8, large_range);
152
  }
153

154
  static void test_partial_region() {
155
    bool   result;
156
    size_t committed_size;
157
    address committed_start;
158
    size_t index;
159

160
    const size_t page_sz = os::vm_page_size();
161
    const size_t num_pages = 4;
162
    const size_t size = num_pages * page_sz;
163
    char* base = os::reserve_memory(size, !ExecMem, mtTest);
164
    ASSERT_NE(base, (char*)nullptr);
165
    result = os::commit_memory(base, size, !ExecMem);
166

167
    ASSERT_TRUE(result);
168
    // touch all pages
169
    for (index = 0; index < num_pages; index ++) {
170
      *(base + index * page_sz) = 'a';
171
    }
172

173
    // Test whole range
174
    result = os::committed_in_range((address)base, size, committed_start, committed_size);
175
    ASSERT_TRUE(result);
176
    ASSERT_EQ(num_pages * page_sz, committed_size);
177
    ASSERT_EQ(committed_start, (address)base);
178

179
    // Test beginning of the range
180
    result = os::committed_in_range((address)base, 2 * page_sz, committed_start, committed_size);
181
    ASSERT_TRUE(result);
182
    ASSERT_EQ(2 * page_sz, committed_size);
183
    ASSERT_EQ(committed_start, (address)base);
184

185
    // Test end of the range
186
    result = os::committed_in_range((address)(base + page_sz), 3 * page_sz, committed_start, committed_size);
187
    ASSERT_TRUE(result);
188
    ASSERT_EQ(3 * page_sz, committed_size);
189
    ASSERT_EQ(committed_start, (address)(base + page_sz));
190

191
    // Test middle of the range
192
    result = os::committed_in_range((address)(base + page_sz), 2 * page_sz, committed_start, committed_size);
193
    ASSERT_TRUE(result);
194
    ASSERT_EQ(2 * page_sz, committed_size);
195
    ASSERT_EQ(committed_start, (address)(base + page_sz));
196

197
    os::release_memory(base, size);
198
  }
199

200
  static void test_committed_in_range(size_t num_pages, size_t pages_to_touch) {
201
    bool result;
202
    size_t committed_size;
203
    address committed_start;
204
    size_t index;
205

206
    const size_t page_sz = os::vm_page_size();
207
    const size_t size = num_pages * page_sz;
208

209
    char* base = os::reserve_memory(size, !ExecMem, mtTest);
210
    ASSERT_NE(base, (char*)nullptr);
211

212
    result = os::commit_memory(base, size, !ExecMem);
213
    ASSERT_TRUE(result);
214

215
    result = os::committed_in_range((address)base, size, committed_start, committed_size);
216
    ASSERT_FALSE(result);
217

218
    // Touch pages
219
    for (index = 0; index < pages_to_touch; index ++) {
220
      base[index * page_sz] = 'a';
221
    }
222

223
    result = os::committed_in_range((address)base, size, committed_start, committed_size);
224
    ASSERT_TRUE(result);
225
    ASSERT_EQ(pages_to_touch * page_sz, committed_size);
226
    ASSERT_EQ(committed_start, (address)base);
227

228
    os::uncommit_memory(base, size, false);
229

230
    result = os::committed_in_range((address)base, size, committed_start, committed_size);
231
    ASSERT_FALSE(result);
232

233
    os::release_memory(base, size);
234
  }
235
};
236

237
TEST_VM(CommittedVirtualMemoryTracker, test_committed_virtualmemory_region) {
238

239
  //  This tests the VM-global NMT facility. The test must *not* modify global state,
240
  //  since that interferes with other tests!
241
  // The gtestLauncher are called with and without -XX:NativeMemoryTracking during jtreg-controlled
242
  //  gtests.
243

244
  if (MemTracker::tracking_level() >= NMT_detail) {
245
    CommittedVirtualMemoryTest::test();
246
    CommittedVirtualMemoryTest::test_committed_region();
247
    CommittedVirtualMemoryTest::test_partial_region();
248
  } else {
249
    tty->print_cr("skipped.");
250
  }
251

252
}
253

254
#if !defined(_WINDOWS) && !defined(_AIX)
255
TEST_VM(CommittedVirtualMemory, test_committed_in_range){
256
  CommittedVirtualMemoryTest::test_committed_in_range(1024, 1024);
257
  CommittedVirtualMemoryTest::test_committed_in_range(2, 1);
258
}
259
#endif
260

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.