--- old/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2015-04-15 20:20:03.664264265 +0300 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2015-04-15 20:20:03.588263095 +0300 @@ -119,7 +119,6 @@ size_t gclab_word_size = _g1h->desired_plab_sz(dest); if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { G1ParGCAllocBuffer* alloc_buf = alloc_buffer(dest, context); - add_to_alloc_buffer_waste(alloc_buf->words_remaining()); alloc_buf->retire(); HeapWord* buf = _g1h->par_allocate_during_gc(dest, gclab_word_size, context); @@ -153,8 +152,19 @@ for (uint state = 0; state < InCSetState::Num; state++) { G1ParGCAllocBuffer* const buf = _alloc_buffers[state]; if (buf != NULL) { - add_to_alloc_buffer_waste(buf->words_remaining()); buf->flush_and_retire_stats(_g1h->alloc_buffer_stats(state)); } } } + +G1PLABWasteStat G1DefaultParGCAllocator::wasted() { + G1PLABWasteStat total_wasted; + for (uint state = 0; state < InCSetState::Num; state++) { + G1ParGCAllocBuffer * const buf = _alloc_buffers[state]; + if (buf != NULL) { + total_wasted.add_wasted(buf->wasted()); + total_wasted.add_undo_wasted(buf->undo_wasted()); + } + } + return total_wasted; +} --- old/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2015-04-15 20:20:03.924268264 +0300 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2015-04-15 20:20:03.848267095 +0300 @@ -147,6 +147,32 @@ } }; +class G1PLABWasteStat VALUE_OBJ_CLASS_SPEC { +private: + size_t _wasted; + size_t _undo_wasted; +public: + + G1PLABWasteStat() : _wasted(0), _undo_wasted(0) { + } + + void add_wasted(size_t word_sz) { + _wasted += word_sz; + } + + void add_undo_wasted(size_t word_sz) { + _undo_wasted += word_sz; + } + + size_t wasted() { + return _wasted; + } + + size_t undo_wasted() { + return _undo_wasted; + } +}; + class G1ParGCAllocBuffer: public ParGCAllocBuffer { private: bool _retired; @@ -183,12 +209,6 @@ // architectures have a special compare against zero instructions. const uint _survivor_alignment_bytes; - size_t _alloc_buffer_waste; - size_t _undo_waste; - - void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } - void add_to_undo_waste(size_t waste) { _undo_waste += waste; } - virtual void retire_alloc_buffers() = 0; virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0; @@ -208,15 +228,13 @@ public: G1ParGCAllocator(G1CollectedHeap* g1h) : - _g1h(g1h), _survivor_alignment_bytes(calc_survivor_alignment_bytes()), - _alloc_buffer_waste(0), _undo_waste(0) { + _g1h(g1h), _survivor_alignment_bytes(calc_survivor_alignment_bytes()) { } static G1ParGCAllocator* create_allocator(G1CollectedHeap* g1h); - size_t alloc_buffer_waste() { return _alloc_buffer_waste; } - size_t undo_waste() {return _undo_waste; } - + virtual G1PLABWasteStat wasted() = 0; + // Allocate word_sz words in dest, either directly into the regions or by // allocating a new PLAB. Returns the address of the allocated memory, NULL if // not successful. @@ -247,14 +265,7 @@ } void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context) { - if (alloc_buffer(dest, context)->contains(obj)) { - assert(alloc_buffer(dest, context)->contains(obj + word_sz - 1), - "should contain whole object"); - alloc_buffer(dest, context)->undo_allocation(obj, word_sz); - } else { - CollectedHeap::fill_with_object(obj, word_sz); - add_to_undo_waste(word_sz); - } + alloc_buffer(dest, context)->undo_allocation(obj, word_sz); } }; @@ -274,7 +285,9 @@ return _alloc_buffers[dest.value()]; } - virtual void retire_alloc_buffers() ; + virtual void retire_alloc_buffers(); + + virtual G1PLABWasteStat wasted(); }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1ALLOCATOR_HPP --- old/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp 2015-04-15 20:20:04.184272262 +0300 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp 2015-04-15 20:20:04.112271155 +0300 @@ -95,8 +95,9 @@ const double elapsed_ms = elapsed_time() * 1000.0; const double s_roots_ms = strong_roots_time() * 1000.0; const double term_ms = term_time() * 1000.0; - const size_t alloc_buffer_waste = _g1_par_allocator->alloc_buffer_waste(); - const size_t undo_waste = _g1_par_allocator->undo_waste(); + G1PLABWasteStat wasted = _g1_par_allocator->wasted(); + const size_t alloc_buffer_waste = wasted.wasted(); + const size_t undo_waste = wasted.undo_wasted(); st->print_cr("%3d %9.2f %9.2f %6.2f " "%9.2f %6.2f " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7), --- old/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp 2015-04-15 20:20:04.452276386 +0300 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp 2015-04-15 20:20:04.372275155 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,9 +54,6 @@ uint _tenuring_threshold; G1ParScanClosure _scanner; - size_t _alloc_buffer_waste; - size_t _undo_waste; - OopsInHeapRegionClosure* _evac_failure_cl; int _hash_seed; @@ -78,9 +75,6 @@ #define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t)) - void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } - void add_to_undo_waste(size_t waste) { _undo_waste += waste; } - DirtyCardQueue& dirty_card_queue() { return _dcq; } G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } --- old/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2015-04-15 20:20:04.712280384 +0300 +++ new/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2015-04-15 20:20:04.636279214 +0300 @@ -272,16 +272,8 @@ } -void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, - size_t word_sz) { - // Is the alloc in the current alloc buffer? - if (to_space_alloc_buffer()->contains(obj)) { - assert(to_space_alloc_buffer()->contains(obj + word_sz - 1), - "Should contain whole object."); - to_space_alloc_buffer()->undo_allocation(obj, word_sz); - } else { - CollectedHeap::fill_with_object(obj, word_sz); - } +void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, size_t word_sz) { + to_space_alloc_buffer()->undo_allocation(obj, word_sz); } void ParScanThreadState::print_promotion_failure_size() { --- old/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp 2015-04-15 20:20:04.980284506 +0300 +++ new/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp 2015-04-15 20:20:04.908283398 +0300 @@ -39,7 +39,7 @@ ParGCAllocBuffer::ParGCAllocBuffer(size_t desired_plab_sz_) : _word_sz(desired_plab_sz_), _bottom(NULL), _top(NULL), - _end(NULL), _hard_end(NULL), _allocated(0), _wasted(0) + _end(NULL), _hard_end(NULL), _allocated(0), _wasted(0), _undo_wasted(0) { // ArrayOopDesc::header_size depends on command line initialization. AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? align_object_size(arrayOopDesc::header_size(T_INT)) : 0; @@ -62,13 +62,15 @@ // Now flush the statistics. stats->add_allocated(_allocated); stats->add_wasted(_wasted); + stats->add_undo_wasted(_undo_wasted); stats->add_unused(unused); // Since we have flushed the stats we need to clear the _allocated and _wasted // fields in case somebody retains an instance of this over GCs. Not doing so // will artifically inflate the values in the statistics. - _allocated = 0; - _wasted = 0; + _allocated = 0; + _wasted = 0; + _undo_wasted = 0; } void ParGCAllocBuffer::retire() { @@ -98,8 +100,9 @@ err_msg("Inconsistency in PLAB stats: " "_allocated: "SIZE_FORMAT", " "_wasted: "SIZE_FORMAT", " - "_unused: "SIZE_FORMAT, - _allocated, _wasted, _unused)); + "_unused: "SIZE_FORMAT", ", + "_undo_wasted: "SIZE_FORMAT, + _allocated, _wasted, _unused, _undo_wasted,)); _allocated = 1; } --- old/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp 2015-04-15 20:20:05.240288505 +0300 +++ new/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp 2015-04-15 20:20:05.164287336 +0300 @@ -45,6 +45,7 @@ // In support of ergonomic sizing of PLAB's size_t _allocated; // in HeapWord units size_t _wasted; // in HeapWord units + size_t _undo_wasted; char tail[32]; static size_t AlignmentReserve; @@ -61,6 +62,19 @@ // Fill in remaining space with a dummy object and invalidate the PLAB. Returns // the amount of remaining space. size_t retire_internal(); + + void add_undo_waste(HeapWord* obj, size_t word_sz) { + CollectedHeap::fill_with_object(obj, word_sz); + _undo_wasted += word_sz; + } + + // Undo the last allocation in the buffer, which is required to be of the + // "obj" of the given "word_sz". + void undo_last_allocation(HeapWord* obj, size_t word_sz) { + assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); + assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); + _top = obj; + } public: // Initializes the buffer to be empty, but with the given "word_sz". @@ -90,18 +104,26 @@ // Allocate the object aligned to "alignment_in_bytes". HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes); - // Undo the last allocation in the buffer, which is required to be of the + // Undo any allocation in the buffer, which is required to be of the // "obj" of the given "word_sz". void undo_allocation(HeapWord* obj, size_t word_sz) { - assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); - assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); - _top = obj; + // Is the alloc in the current alloc buffer? + if (contains(obj)) { + assert(contains(obj + word_sz - 1), + "should contain whole object"); + undo_last_allocation(obj, word_sz); + } else { + add_undo_waste(obj,word_sz); + } } // The total (word) size of the buffer, including both allocated and // unallocated space. size_t word_sz() { return _word_sz; } + size_t wasted() { return _wasted; } + size_t undo_wasted() { return _undo_wasted; } + // Should only be done if we are about to reset with a new buffer of the // given size. void set_word_size(size_t new_word_sz) { @@ -146,20 +168,23 @@ class PLABStats VALUE_OBJ_CLASS_SPEC { size_t _allocated; // Total allocated size_t _wasted; // of which wasted (internal fragmentation) + size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) size_t _unused; // Unused in last buffer size_t _desired_plab_sz;// Output of filter (below), suitably trimmed and quantized AdaptiveWeightedAverage _filter; // Integrator with decay void reset() { - _allocated = 0; - _wasted = 0; - _unused = 0; + _allocated = 0; + _wasted = 0; + _undo_wasted = 0; + _unused = 0; } public: PLABStats(size_t desired_plab_sz_, unsigned wt) : _allocated(0), _wasted(0), + _undo_wasted(0), _unused(0), _desired_plab_sz(desired_plab_sz_), _filter(wt) @@ -192,6 +217,10 @@ void add_wasted(size_t v) { Atomic::add_ptr(v, &_wasted); } + + void add_undo_wasted(size_t v) { + Atomic::add_ptr(v, &_undo_wasted); + } }; #endif // SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP