--- old/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2015-04-20 17:36:07.620733402 +0300 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2015-04-20 17:36:07.544732225 +0300 @@ -119,7 +119,6 @@ size_t gclab_word_size = _g1h->desired_plab_sz(dest); if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { G1PLAB* 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++) { G1PLAB* 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)); } } } + +void G1DefaultParGCAllocator::waste(size_t& wasted, size_t& undo_wasted) { + wasted = 0; + undo_wasted = 0; + for (uint state = 0; state < InCSetState::Num; state++) { + G1PLAB * const buf = _alloc_buffers[state]; + if (buf != NULL) { + wasted += buf->waste(); + undo_wasted += buf->undo_waste(); + } + } +} --- old/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2015-04-20 17:36:08.052740097 +0300 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2015-04-20 17:36:07.976738919 +0300 @@ -183,12 +183,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 G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0; @@ -208,15 +202,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 void waste(size_t& wasted, size_t& undo_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 +239,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 +259,9 @@ return _alloc_buffers[dest.value()]; } - virtual void retire_alloc_buffers() ; + virtual void retire_alloc_buffers(); + + virtual void waste(size_t& wasted, size_t& undo_wasted); }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1ALLOCATOR_HPP --- old/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp 2015-04-20 17:36:08.472746605 +0300 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp 2015-04-20 17:36:08.396745427 +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(); + size_t alloc_buffer_waste = 0; + size_t undo_waste = 0; + _g1_par_allocator->waste(alloc_buffer_waste, undo_waste); 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-20 17:36:08.896753175 +0300 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp 2015-04-20 17:36:08.820751998 +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-20 17:36:09.312759621 +0300 +++ new/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2015-04-20 17:36:09.236758444 +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/plab.cpp 2015-04-20 17:36:09.764766625 +0300 +++ new/src/share/vm/gc_implementation/shared/plab.cpp 2015-04-20 17:36:09.688765447 +0300 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc_implementation/shared/plab.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/threadLocalAllocBuffer.hpp" #include "oops/arrayOop.hpp" #include "oops/oop.inline.hpp" @@ -39,7 +40,7 @@ PLAB::PLAB(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 +63,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 PLAB::retire() { @@ -84,6 +87,28 @@ return result; } +void PLAB::add_undo_waste(HeapWord* obj, size_t word_sz) { + CollectedHeap::fill_with_object(obj, word_sz); + _undo_wasted += word_sz; +} + +void PLAB::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; +} + +void PLAB::undo_allocation(HeapWord* obj, size_t word_sz) { + // 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); + } +} + // Compute desired plab size and latch result for later // use. This should be called once at the end of parallel // scavenge; it clears the sensor accumulators. @@ -98,8 +123,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/plab.hpp 2015-04-20 17:36:10.192773257 +0300 +++ new/src/share/vm/gc_implementation/shared/plab.hpp 2015-04-20 17:36:10.116772079 +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; @@ -62,6 +63,12 @@ // the amount of remaining space. size_t retire_internal(); + void add_undo_waste(HeapWord* obj, size_t 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); + public: // Initializes the buffer to be empty, but with the given "word_sz". // Must get initialized with "set_buf" for an allocation to succeed. @@ -90,18 +97,17 @@ // 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; - } + void undo_allocation(HeapWord* obj, size_t word_sz); // The total (word) size of the buffer, including both allocated and // unallocated space. size_t word_sz() { return _word_sz; } + size_t waste() { return _wasted; } + size_t undo_waste() { 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 +152,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 +201,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_SHARED_PLAB_HPP