src/share/vm/gc_implementation/g1/ptrQueue.cpp

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 6198
55fb97c4c58d
child 6876
710a3c8b516e
child 7445
42c091d63c72
permissions
-rw-r--r--

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

ysr@777 1 /*
mikael@6198 2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/ptrQueue.hpp"
stefank@2314 27 #include "memory/allocation.hpp"
stefank@2314 28 #include "memory/allocation.inline.hpp"
stefank@2314 29 #include "runtime/mutex.hpp"
stefank@2314 30 #include "runtime/mutexLocker.hpp"
stefank@4299 31 #include "runtime/thread.inline.hpp"
ysr@777 32
tonyp@2469 33 PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) :
tonyp@2469 34 _qset(qset), _buf(NULL), _index(0), _active(active),
ysr@777 35 _perm(perm), _lock(NULL)
ysr@777 36 {}
ysr@777 37
iveresov@876 38 void PtrQueue::flush() {
ysr@777 39 if (!_perm && _buf != NULL) {
ysr@777 40 if (_index == _sz) {
ysr@777 41 // No work to do.
ysr@777 42 qset()->deallocate_buffer(_buf);
ysr@777 43 } else {
ysr@777 44 // We must NULL out the unused entries, then enqueue.
ysr@777 45 for (size_t i = 0; i < _index; i += oopSize) {
ysr@777 46 _buf[byte_index_to_index((int)i)] = NULL;
ysr@777 47 }
ysr@777 48 qset()->enqueue_complete_buffer(_buf);
ysr@777 49 }
iveresov@876 50 _buf = NULL;
iveresov@876 51 _index = 0;
ysr@777 52 }
ysr@777 53 }
ysr@777 54
ysr@777 55
ysr@777 56 void PtrQueue::enqueue_known_active(void* ptr) {
ysr@777 57 assert(0 <= _index && _index <= _sz, "Invariant.");
ysr@777 58 assert(_index == 0 || _buf != NULL, "invariant");
ysr@777 59
ysr@777 60 while (_index == 0) {
ysr@777 61 handle_zero_index();
ysr@777 62 }
iveresov@1546 63
ysr@777 64 assert(_index > 0, "postcondition");
ysr@777 65 _index -= oopSize;
ysr@777 66 _buf[byte_index_to_index((int)_index)] = ptr;
ysr@777 67 assert(0 <= _index && _index <= _sz, "Invariant.");
ysr@777 68 }
ysr@777 69
ysr@777 70 void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
ysr@777 71 assert(_lock->owned_by_self(), "Required.");
johnc@1604 72
johnc@1604 73 // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
johnc@1604 74 // we acquire DirtyCardQ_CBL_mon inside enqeue_complete_buffer as they
johnc@1604 75 // have the same rank and we may get the "possible deadlock" message
ysr@777 76 _lock->unlock();
johnc@1604 77
ysr@777 78 qset()->enqueue_complete_buffer(buf);
ysr@777 79 // We must relock only because the caller will unlock, for the normal
ysr@777 80 // case.
ysr@777 81 _lock->lock_without_safepoint_check();
ysr@777 82 }
ysr@777 83
ysr@777 84
ysr@777 85 PtrQueueSet::PtrQueueSet(bool notify_when_complete) :
ysr@777 86 _max_completed_queue(0),
ysr@777 87 _cbl_mon(NULL), _fl_lock(NULL),
ysr@777 88 _notify_when_complete(notify_when_complete),
ysr@777 89 _sz(0),
ysr@777 90 _completed_buffers_head(NULL),
ysr@777 91 _completed_buffers_tail(NULL),
ysr@777 92 _n_completed_buffers(0),
ysr@777 93 _process_completed_threshold(0), _process_completed(false),
ysr@777 94 _buf_free_list(NULL), _buf_free_list_sz(0)
iveresov@1051 95 {
iveresov@1051 96 _fl_owner = this;
iveresov@1051 97 }
ysr@777 98
ysr@777 99 void** PtrQueueSet::allocate_buffer() {
ysr@777 100 assert(_sz > 0, "Didn't set a buffer size.");
iveresov@1051 101 MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
iveresov@1051 102 if (_fl_owner->_buf_free_list != NULL) {
iveresov@1546 103 void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list);
iveresov@1546 104 _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next();
iveresov@1051 105 _fl_owner->_buf_free_list_sz--;
ysr@777 106 return res;
ysr@777 107 } else {
iveresov@1546 108 // Allocate space for the BufferNode in front of the buffer.
zgu@3900 109 char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC);
iveresov@1546 110 return BufferNode::make_buffer_from_block(b);
ysr@777 111 }
ysr@777 112 }
ysr@777 113
ysr@777 114 void PtrQueueSet::deallocate_buffer(void** buf) {
ysr@777 115 assert(_sz > 0, "Didn't set a buffer size.");
iveresov@1051 116 MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
iveresov@1546 117 BufferNode *node = BufferNode::make_node_from_buffer(buf);
iveresov@1546 118 node->set_next(_fl_owner->_buf_free_list);
iveresov@1546 119 _fl_owner->_buf_free_list = node;
iveresov@1051 120 _fl_owner->_buf_free_list_sz++;
ysr@777 121 }
ysr@777 122
ysr@777 123 void PtrQueueSet::reduce_free_list() {
iveresov@1546 124 assert(_fl_owner == this, "Free list reduction is allowed only for the owner");
ysr@777 125 // For now we'll adopt the strategy of deleting half.
ysr@777 126 MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
ysr@777 127 size_t n = _buf_free_list_sz / 2;
ysr@777 128 while (n > 0) {
ysr@777 129 assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong.");
iveresov@1546 130 void* b = BufferNode::make_block_from_node(_buf_free_list);
iveresov@1546 131 _buf_free_list = _buf_free_list->next();
zgu@3900 132 FREE_C_HEAP_ARRAY(char, b, mtGC);
johnc@1519 133 _buf_free_list_sz --;
ysr@777 134 n--;
ysr@777 135 }
ysr@777 136 }
ysr@777 137
iveresov@1546 138 void PtrQueue::handle_zero_index() {
tonyp@2469 139 assert(_index == 0, "Precondition.");
tonyp@2469 140
iveresov@1546 141 // This thread records the full buffer and allocates a new one (while
iveresov@1546 142 // holding the lock if there is one).
iveresov@1546 143 if (_buf != NULL) {
tonyp@2469 144 if (!should_enqueue_buffer()) {
tonyp@2469 145 assert(_index > 0, "the buffer can only be re-used if it's not full");
tonyp@2469 146 return;
tonyp@2469 147 }
tonyp@2469 148
iveresov@1546 149 if (_lock) {
johnc@1604 150 assert(_lock->owned_by_self(), "Required.");
johnc@1604 151
johnc@1604 152 // The current PtrQ may be the shared dirty card queue and
johnc@1604 153 // may be being manipulated by more than one worker thread
johnc@1604 154 // during a pause. Since the enqueuing of the completed
johnc@1604 155 // buffer unlocks the Shared_DirtyCardQ_lock more than one
johnc@1604 156 // worker thread can 'race' on reading the shared queue attributes
johnc@1604 157 // (_buf and _index) and multiple threads can call into this
johnc@1604 158 // routine for the same buffer. This will cause the completed
johnc@1604 159 // buffer to be added to the CBL multiple times.
johnc@1604 160
johnc@1604 161 // We "claim" the current buffer by caching value of _buf in
johnc@1604 162 // a local and clearing the field while holding _lock. When
johnc@1604 163 // _lock is released (while enqueueing the completed buffer)
johnc@1604 164 // the thread that acquires _lock will skip this code,
johnc@1604 165 // preventing the subsequent the multiple enqueue, and
johnc@1604 166 // install a newly allocated buffer below.
johnc@1604 167
johnc@1604 168 void** buf = _buf; // local pointer to completed buffer
johnc@1604 169 _buf = NULL; // clear shared _buf field
johnc@1604 170
johnc@1604 171 locking_enqueue_completed_buffer(buf); // enqueue completed buffer
johnc@1604 172
johnc@1604 173 // While the current thread was enqueuing the buffer another thread
johnc@1604 174 // may have a allocated a new buffer and inserted it into this pointer
johnc@1604 175 // queue. If that happens then we just return so that the current
johnc@1604 176 // thread doesn't overwrite the buffer allocated by the other thread
johnc@1604 177 // and potentially losing some dirtied cards.
johnc@1604 178
johnc@1604 179 if (_buf != NULL) return;
iveresov@1546 180 } else {
iveresov@1546 181 if (qset()->process_or_enqueue_complete_buffer(_buf)) {
iveresov@1546 182 // Recycle the buffer. No allocation.
iveresov@1546 183 _sz = qset()->buffer_size();
iveresov@1546 184 _index = _sz;
iveresov@1546 185 return;
iveresov@1546 186 }
iveresov@1546 187 }
iveresov@1546 188 }
iveresov@1546 189 // Reallocate the buffer
iveresov@1546 190 _buf = qset()->allocate_buffer();
iveresov@1546 191 _sz = qset()->buffer_size();
iveresov@1546 192 _index = _sz;
iveresov@1546 193 assert(0 <= _index && _index <= _sz, "Invariant.");
iveresov@1546 194 }
ysr@777 195
iveresov@1546 196 bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
iveresov@1546 197 if (Thread::current()->is_Java_thread()) {
iveresov@1546 198 // We don't lock. It is fine to be epsilon-precise here.
iveresov@1546 199 if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
iveresov@1546 200 _n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
iveresov@1546 201 bool b = mut_process_buffer(buf);
iveresov@1546 202 if (b) {
iveresov@1546 203 // True here means that the buffer hasn't been deallocated and the caller may reuse it.
iveresov@1546 204 return true;
iveresov@1546 205 }
iveresov@1546 206 }
iveresov@1546 207 }
iveresov@1546 208 // The buffer will be enqueued. The caller will have to get a new one.
iveresov@1546 209 enqueue_complete_buffer(buf);
iveresov@1546 210 return false;
iveresov@1546 211 }
ysr@777 212
iveresov@1546 213 void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
iveresov@1546 214 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
iveresov@1546 215 BufferNode* cbn = BufferNode::new_from_buffer(buf);
iveresov@1546 216 cbn->set_index(index);
ysr@777 217 if (_completed_buffers_tail == NULL) {
ysr@777 218 assert(_completed_buffers_head == NULL, "Well-formedness");
ysr@777 219 _completed_buffers_head = cbn;
ysr@777 220 _completed_buffers_tail = cbn;
ysr@777 221 } else {
iveresov@1546 222 _completed_buffers_tail->set_next(cbn);
ysr@777 223 _completed_buffers_tail = cbn;
ysr@777 224 }
ysr@777 225 _n_completed_buffers++;
ysr@777 226
iveresov@1546 227 if (!_process_completed && _process_completed_threshold >= 0 &&
iveresov@1229 228 _n_completed_buffers >= _process_completed_threshold) {
ysr@777 229 _process_completed = true;
ysr@777 230 if (_notify_when_complete)
iveresov@1546 231 _cbl_mon->notify();
ysr@777 232 }
ysr@777 233 debug_only(assert_completed_buffer_list_len_correct_locked());
ysr@777 234 }
ysr@777 235
ysr@777 236 int PtrQueueSet::completed_buffers_list_length() {
ysr@777 237 int n = 0;
iveresov@1546 238 BufferNode* cbn = _completed_buffers_head;
ysr@777 239 while (cbn != NULL) {
ysr@777 240 n++;
iveresov@1546 241 cbn = cbn->next();
ysr@777 242 }
ysr@777 243 return n;
ysr@777 244 }
ysr@777 245
ysr@777 246 void PtrQueueSet::assert_completed_buffer_list_len_correct() {
ysr@777 247 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
ysr@777 248 assert_completed_buffer_list_len_correct_locked();
ysr@777 249 }
ysr@777 250
ysr@777 251 void PtrQueueSet::assert_completed_buffer_list_len_correct_locked() {
iveresov@1546 252 guarantee(completed_buffers_list_length() == _n_completed_buffers,
ysr@777 253 "Completed buffer length is wrong.");
ysr@777 254 }
ysr@777 255
ysr@777 256 void PtrQueueSet::set_buffer_size(size_t sz) {
ysr@777 257 assert(_sz == 0 && sz > 0, "Should be called only once.");
ysr@777 258 _sz = sz * oopSize;
ysr@777 259 }
ysr@777 260
iveresov@1546 261 // Merge lists of buffers. Notify the processing threads.
iveresov@1546 262 // The source queue is emptied as a result. The queues
iveresov@1051 263 // must share the monitor.
iveresov@1051 264 void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) {
iveresov@1051 265 assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
iveresov@1051 266 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
iveresov@1051 267 if (_completed_buffers_tail == NULL) {
iveresov@1051 268 assert(_completed_buffers_head == NULL, "Well-formedness");
iveresov@1051 269 _completed_buffers_head = src->_completed_buffers_head;
iveresov@1051 270 _completed_buffers_tail = src->_completed_buffers_tail;
iveresov@1051 271 } else {
iveresov@1051 272 assert(_completed_buffers_head != NULL, "Well formedness");
iveresov@1051 273 if (src->_completed_buffers_head != NULL) {
iveresov@1546 274 _completed_buffers_tail->set_next(src->_completed_buffers_head);
iveresov@1051 275 _completed_buffers_tail = src->_completed_buffers_tail;
iveresov@1051 276 }
iveresov@1051 277 }
iveresov@1051 278 _n_completed_buffers += src->_n_completed_buffers;
iveresov@1051 279
iveresov@1051 280 src->_n_completed_buffers = 0;
iveresov@1051 281 src->_completed_buffers_head = NULL;
iveresov@1051 282 src->_completed_buffers_tail = NULL;
iveresov@1051 283
iveresov@1051 284 assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
iveresov@1051 285 _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
iveresov@1051 286 "Sanity");
iveresov@1546 287 }
iveresov@1051 288
iveresov@1546 289 void PtrQueueSet::notify_if_necessary() {
iveresov@1546 290 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
iveresov@1546 291 if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) {
iveresov@1051 292 _process_completed = true;
iveresov@1051 293 if (_notify_when_complete)
iveresov@1546 294 _cbl_mon->notify();
iveresov@1051 295 }
iveresov@1051 296 }

mercurial