Fri, 10 Oct 2014 15:51:58 +0200
8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso
1 /*
2 * Copyright (c) 2014, 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 */
25 #include "precompiled.hpp"
26 #include "gc_implementation/g1/bufferingOopClosure.hpp"
27 #include "memory/iterator.hpp"
28 #include "utilities/debug.hpp"
30 /////////////// Unit tests ///////////////
32 #ifndef PRODUCT
34 class TestBufferingOopClosure {
36 // Helper class to fake a set of oop*s and narrowOop*s.
37 class FakeRoots {
38 public:
39 // Used for sanity checking of the values passed to the do_oops functions in the test.
40 static const uintptr_t NarrowOopMarker = uintptr_t(1) << (BitsPerWord -1);
42 int _num_narrow;
43 int _num_full;
44 void** _narrow;
45 void** _full;
47 FakeRoots(int num_narrow, int num_full) :
48 _num_narrow(num_narrow),
49 _num_full(num_full),
50 _narrow((void**)::malloc(sizeof(void*) * num_narrow)),
51 _full((void**)::malloc(sizeof(void*) * num_full)) {
53 for (int i = 0; i < num_narrow; i++) {
54 _narrow[i] = (void*)(NarrowOopMarker + (uintptr_t)i);
55 }
56 for (int i = 0; i < num_full; i++) {
57 _full[i] = (void*)(uintptr_t)i;
58 }
59 }
61 ~FakeRoots() {
62 ::free(_narrow);
63 ::free(_full);
64 }
66 void oops_do_narrow_then_full(OopClosure* cl) {
67 for (int i = 0; i < _num_narrow; i++) {
68 cl->do_oop((narrowOop*)_narrow[i]);
69 }
70 for (int i = 0; i < _num_full; i++) {
71 cl->do_oop((oop*)_full[i]);
72 }
73 }
75 void oops_do_full_then_narrow(OopClosure* cl) {
76 for (int i = 0; i < _num_full; i++) {
77 cl->do_oop((oop*)_full[i]);
78 }
79 for (int i = 0; i < _num_narrow; i++) {
80 cl->do_oop((narrowOop*)_narrow[i]);
81 }
82 }
84 void oops_do_mixed(OopClosure* cl) {
85 int i;
86 for (i = 0; i < _num_full && i < _num_narrow; i++) {
87 cl->do_oop((oop*)_full[i]);
88 cl->do_oop((narrowOop*)_narrow[i]);
89 }
90 for (int j = i; j < _num_full; j++) {
91 cl->do_oop((oop*)_full[i]);
92 }
93 for (int j = i; j < _num_narrow; j++) {
94 cl->do_oop((narrowOop*)_narrow[i]);
95 }
96 }
98 static const int MaxOrder = 2;
100 void oops_do(OopClosure* cl, int do_oop_order) {
101 switch(do_oop_order) {
102 case 0:
103 oops_do_narrow_then_full(cl);
104 break;
105 case 1:
106 oops_do_full_then_narrow(cl);
107 break;
108 case 2:
109 oops_do_mixed(cl);
110 break;
111 default:
112 oops_do_narrow_then_full(cl);
113 break;
114 }
115 }
116 };
118 class CountOopClosure : public OopClosure {
119 int _narrow_oop_count;
120 int _full_oop_count;
121 public:
122 CountOopClosure() : _narrow_oop_count(0), _full_oop_count(0) {}
123 void do_oop(narrowOop* p) {
124 assert((uintptr_t(p) & FakeRoots::NarrowOopMarker) != 0,
125 "The narrowOop was unexpectedly not marked with the NarrowOopMarker");
126 _narrow_oop_count++;
127 }
129 void do_oop(oop* p){
130 assert((uintptr_t(p) & FakeRoots::NarrowOopMarker) == 0,
131 "The oop was unexpectedly marked with the NarrowOopMarker");
132 _full_oop_count++;
133 }
135 int narrow_oop_count() { return _narrow_oop_count; }
136 int full_oop_count() { return _full_oop_count; }
137 int all_oop_count() { return _narrow_oop_count + _full_oop_count; }
138 };
140 class DoNothingOopClosure : public OopClosure {
141 public:
142 void do_oop(narrowOop* p) {}
143 void do_oop(oop* p) {}
144 };
146 static void testCount(int num_narrow, int num_full, int do_oop_order) {
147 FakeRoots fr(num_narrow, num_full);
149 CountOopClosure coc;
150 BufferingOopClosure boc(&coc);
152 fr.oops_do(&boc, do_oop_order);
154 boc.done();
156 #define assert_testCount(got, expected) \
157 assert((got) == (expected), \
158 err_msg("Expected: %d, got: %d, when running testCount(%d, %d, %d)", \
159 (got), (expected), num_narrow, num_full, do_oop_order))
161 assert_testCount(num_narrow, coc.narrow_oop_count());
162 assert_testCount(num_full, coc.full_oop_count());
163 assert_testCount(num_narrow + num_full, coc.all_oop_count());
164 }
166 static void testCount() {
167 int buffer_length = BufferingOopClosure::BufferLength;
169 for (int order = 0; order < FakeRoots::MaxOrder; order++) {
170 testCount(0, 0, order);
171 testCount(10, 0, order);
172 testCount(0, 10, order);
173 testCount(10, 10, order);
174 testCount(buffer_length, 10, order);
175 testCount(10, buffer_length, order);
176 testCount(buffer_length, buffer_length, order);
177 testCount(buffer_length + 1, 10, order);
178 testCount(10, buffer_length + 1, order);
179 testCount(buffer_length + 1, buffer_length, order);
180 testCount(buffer_length, buffer_length + 1, order);
181 testCount(buffer_length + 1, buffer_length + 1, order);
182 }
183 }
185 static void testIsBufferEmptyOrFull(int num_narrow, int num_full, bool expect_empty, bool expect_full) {
186 FakeRoots fr(num_narrow, num_full);
188 DoNothingOopClosure cl;
189 BufferingOopClosure boc(&cl);
191 fr.oops_do(&boc, 0);
193 #define assert_testIsBufferEmptyOrFull(got, expected) \
194 assert((got) == (expected), \
195 err_msg("Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \
196 (got), (expected), num_narrow, num_full, \
197 BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full)))
199 assert_testIsBufferEmptyOrFull(expect_empty, boc.is_buffer_empty());
200 assert_testIsBufferEmptyOrFull(expect_full, boc.is_buffer_full());
201 }
203 static void testIsBufferEmptyOrFull() {
204 int bl = BufferingOopClosure::BufferLength;
206 testIsBufferEmptyOrFull(0, 0, true, false);
207 testIsBufferEmptyOrFull(1, 0, false, false);
208 testIsBufferEmptyOrFull(0, 1, false, false);
209 testIsBufferEmptyOrFull(1, 1, false, false);
210 testIsBufferEmptyOrFull(10, 0, false, false);
211 testIsBufferEmptyOrFull(0, 10, false, false);
212 testIsBufferEmptyOrFull(10, 10, false, false);
213 testIsBufferEmptyOrFull(0, bl, false, true);
214 testIsBufferEmptyOrFull(bl, 0, false, true);
215 testIsBufferEmptyOrFull(bl/2, bl/2, false, true);
216 testIsBufferEmptyOrFull(bl-1, 1, false, true);
217 testIsBufferEmptyOrFull(1, bl-1, false, true);
218 // Processed
219 testIsBufferEmptyOrFull(bl+1, 0, false, false);
220 testIsBufferEmptyOrFull(bl*2, 0, false, true);
221 }
223 static void testEmptyAfterDone(int num_narrow, int num_full) {
224 FakeRoots fr(num_narrow, num_full);
226 DoNothingOopClosure cl;
227 BufferingOopClosure boc(&cl);
229 fr.oops_do(&boc, 0);
231 // Make sure all get processed.
232 boc.done();
234 assert(boc.is_buffer_empty(),
235 err_msg("Should be empty after call to done(). testEmptyAfterDone(%d, %d)",
236 num_narrow, num_full));
237 }
239 static void testEmptyAfterDone() {
240 int bl = BufferingOopClosure::BufferLength;
242 testEmptyAfterDone(0, 0);
243 testEmptyAfterDone(1, 0);
244 testEmptyAfterDone(0, 1);
245 testEmptyAfterDone(1, 1);
246 testEmptyAfterDone(10, 0);
247 testEmptyAfterDone(0, 10);
248 testEmptyAfterDone(10, 10);
249 testEmptyAfterDone(0, bl);
250 testEmptyAfterDone(bl, 0);
251 testEmptyAfterDone(bl/2, bl/2);
252 testEmptyAfterDone(bl-1, 1);
253 testEmptyAfterDone(1, bl-1);
254 // Processed
255 testEmptyAfterDone(bl+1, 0);
256 testEmptyAfterDone(bl*2, 0);
257 }
259 public:
260 static void test() {
261 testCount();
262 testIsBufferEmptyOrFull();
263 testEmptyAfterDone();
264 }
265 };
267 void TestBufferingOopClosure_test() {
268 TestBufferingOopClosure::test();
269 }
271 #endif