--- old/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp 2014-11-06 01:36:40.389526536 -0800 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp 2014-11-06 01:36:40.289526540 -0800 @@ -2591,7 +2591,8 @@ } } -HeapWord* CFLS_LAB::alloc(size_t word_sz) { +HeapWord* CFLS_LAB::alloc(const ParNewTracer* gc_tracer, size_t word_sz, + const oop old, const markOop m) { FreeChunk* res; assert(word_sz == _cfls->adjustObjectSize(word_sz), "Error"); if (word_sz >= CompactibleFreeListSpace::IndexSetSize) { @@ -2600,6 +2601,12 @@ Mutex::_no_safepoint_check_flag); res = _cfls->getChunkFromDictionaryExact(word_sz); if (res == NULL) return NULL; + if (gc_tracer->should_report_promotion_outside_plab_event()) { + uint age = m->has_displaced_mark_helper() ? + m->displaced_mark_helper()->age() : + m->age(); + gc_tracer->report_promotion_outside_plab_event(old, word_sz, age, true); + } } else { AdaptiveFreeList* fl = &_indexedFreeList[word_sz]; if (fl->count() == 0) { @@ -2607,6 +2614,13 @@ get_from_global_pool(word_sz, fl); // If it didn't work, give up. if (fl->count() == 0) return NULL; + if (gc_tracer->should_report_promotion_in_new_plab_event()) { + uint age = m->has_displaced_mark_helper() ? + m->displaced_mark_helper()->age() : + m->age(); + gc_tracer->report_promotion_in_new_plab_event(old, word_sz, age, true, + fl->count() * fl->size()); + } } res = fl->get_chunk_at_head(); assert(res != NULL, "Why was count non-zero?"); --- old/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp 2014-11-06 01:36:40.817526521 -0800 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp 2014-11-06 01:36:40.701526525 -0800 @@ -27,6 +27,7 @@ #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/blockOffsetTable.inline.hpp" #include "memory/freeList.hpp" @@ -682,7 +683,9 @@ CFLS_LAB(CompactibleFreeListSpace* cfls); // Allocate and return a block of the given size, or else return NULL. - HeapWord* alloc(size_t word_sz); + // The oop (old) is used to extract information for promotion trace event + HeapWord* alloc(const ParNewTracer* gc_tracer, size_t word_sz, + const oop old, const markOop m); // Return any unused portions of the buffer to the global pool. void retire(int tid); --- old/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp 2014-11-06 01:36:41.333526503 -0800 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp 2014-11-06 01:36:41.205526508 -0800 @@ -1118,7 +1118,8 @@ // Things to support parallel young-gen collection. oop -ConcurrentMarkSweepGeneration::par_promote(int thread_num, +ConcurrentMarkSweepGeneration::par_promote(const ParNewTracer* gc_tracer, + int thread_num, oop old, markOop m, size_t word_sz) { #ifndef PRODUCT @@ -1144,9 +1145,9 @@ } assert(promoInfo->has_spooling_space(), "Control point invariant"); const size_t alloc_sz = CompactibleFreeListSpace::adjustObjectSize(word_sz); - HeapWord* obj_ptr = ps->lab.alloc(alloc_sz); + HeapWord* obj_ptr = ps->lab.alloc(gc_tracer, alloc_sz, old, m); if (obj_ptr == NULL) { - obj_ptr = expand_and_par_lab_allocate(ps, alloc_sz); + obj_ptr = expand_and_par_lab_allocate(ps, gc_tracer, alloc_sz, old, m); if (obj_ptr == NULL) { return NULL; } @@ -3114,12 +3115,15 @@ } } -HeapWord* ConcurrentMarkSweepGeneration::expand_and_par_lab_allocate(CMSParGCThreadState* ps, size_t word_sz) { +HeapWord* ConcurrentMarkSweepGeneration::expand_and_par_lab_allocate(CMSParGCThreadState* ps, + const ParNewTracer* gc_tracer, + size_t word_sz, + const oop old, const markOop m) { HeapWord* res = NULL; MutexLocker x(ParGCRareEvent_lock); while (true) { // Expansion by some other thread might make alloc OK now: - res = ps->lab.alloc(word_sz); + res = ps->lab.alloc(gc_tracer, word_sz, old, m); if (res != NULL) return res; // If there's not enough expansion space available, give up. if (_virtual_space.uncommitted_size() < (word_sz * HeapWordSize)) { --- old/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp 2014-11-06 01:36:41.901526484 -0800 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp 2014-11-06 01:36:41.805526487 -0800 @@ -28,6 +28,7 @@ #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gSpaceCounters.hpp" #include "gc_implementation/shared/gcStats.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/generationCounters.hpp" #include "memory/freeBlockDictionary.hpp" @@ -1178,7 +1179,8 @@ void reset_direct_allocated_words() { _direct_allocated_words = 0; } // Overrides for parallel promotion. - virtual oop par_promote(int thread_num, + virtual oop par_promote(const ParNewTracer* gc_tracer, + int thread_num, oop obj, markOop m, size_t word_sz); // This one should not be called for CMS. virtual void par_promote_alloc_undo(int thread_num, @@ -1226,7 +1228,11 @@ virtual bool expand(size_t bytes, size_t expand_bytes); void shrink(size_t bytes); void shrink_by(size_t bytes); - HeapWord* expand_and_par_lab_allocate(CMSParGCThreadState* ps, size_t word_sz); + // The oop (old) is used to extract information for promotion trace event + HeapWord* expand_and_par_lab_allocate(CMSParGCThreadState* ps, + const ParNewTracer* gc_tracer, + size_t word_sz, + const oop old, const markOop m); bool expand_and_ensure_spooling_space(PromotionInfo* promo); // Iteration support and related enquiries --- old/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2014-11-06 01:36:42.289526470 -0800 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2014-11-06 01:36:42.193526473 -0800 @@ -28,6 +28,7 @@ #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionSet.inline.hpp" +#include "gc_implementation/shared/gcTrace.hpp" void G1DefaultAllocator::init_mutator_alloc_region() { assert(_mutator_alloc_region.get() == NULL, "pre-condition"); @@ -110,7 +111,9 @@ G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) : ParGCAllocBuffer(gclab_word_size), _retired(true) { } -HeapWord* G1ParGCAllocator::allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) { +HeapWord* G1ParGCAllocator::allocate_slow(GCAllocPurpose purpose, size_t word_sz, + const oop old, const uint age, + AllocationContext_t context) { HeapWord* obj = NULL; size_t gclab_word_size = _g1h->desired_plab_sz(purpose); if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { @@ -128,8 +131,20 @@ obj = alloc_buf->allocate(word_sz); assert(obj != NULL, "buffer was definitely big enough..."); + if (_g1h->_gc_tracer_stw->should_report_promotion_in_new_plab_event()) { + bool tenured = _g1h->heap_region_containing_raw(obj)->is_old(); + _g1h->_gc_tracer_stw->report_promotion_in_new_plab_event(old, word_sz, + age, tenured, + gclab_word_size); + } } else { obj = _g1h->par_allocate_during_gc(purpose, word_sz, context); + if (obj != NULL + && _g1h->_gc_tracer_stw->should_report_promotion_outside_plab_event()) { + bool tenured = _g1h->heap_region_containing_raw(obj)->is_old(); + _g1h->_gc_tracer_stw->report_promotion_outside_plab_event(old, word_sz, + age, tenured); + } } return obj; } --- old/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2014-11-06 01:36:42.601526459 -0800 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2014-11-06 01:36:42.509526462 -0800 @@ -184,7 +184,9 @@ void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } void add_to_undo_waste(size_t waste) { _undo_waste += waste; } - HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context); + HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz, + const oop old, const uint age, + AllocationContext_t context); virtual void retire_alloc_buffers() = 0; virtual G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose, AllocationContext_t context) = 0; @@ -199,7 +201,9 @@ size_t alloc_buffer_waste() { return _alloc_buffer_waste; } size_t undo_waste() {return _undo_waste; } - HeapWord* allocate(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) { + HeapWord* allocate(GCAllocPurpose purpose, size_t word_sz, + const oop old, const uint age, + AllocationContext_t context) { HeapWord* obj = NULL; if (purpose == GCAllocForSurvived) { obj = alloc_buffer(purpose, context)->allocate_aligned(word_sz, SurvivorAlignmentInBytes); @@ -209,7 +213,7 @@ if (obj != NULL) { return obj; } - return allocate_slow(purpose, word_sz, context); + return allocate_slow(purpose, word_sz, old, age, context); } void undo_allocation(GCAllocPurpose purpose, HeapWord* obj, size_t word_sz, AllocationContext_t context) { --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2014-11-06 01:36:42.977526446 -0800 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2014-11-06 01:36:42.877526450 -0800 @@ -4270,10 +4270,11 @@ if (state == G1CollectedHeap::InCSet) { oop forwardee; - if (obj->is_forwarded()) { - forwardee = obj->forwardee(); + markOop m = obj->mark(); + if (m->is_marked()) { + forwardee = (oop) m->decode_pointer(); } else { - forwardee = _par_scan_state->copy_to_survivor_space(obj); + forwardee = _par_scan_state->copy_to_survivor_space(obj, m); } assert(forwardee != NULL, "forwardee should not be NULL"); oopDesc::encode_store_heap_oop(p, forwardee); --- old/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp 2014-11-06 01:36:43.377526432 -0800 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp 2014-11-06 01:36:43.285526435 -0800 @@ -150,7 +150,8 @@ } while (!_refs->is_empty()); } -oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { +oop G1ParScanThreadState::copy_to_survivor_space(oop const old, + markOop const old_mark) { size_t word_sz = old->size(); HeapRegion* from_region = _g1h->heap_region_containing_raw(old); // +1 to make the -1 indexes valid... @@ -158,13 +159,12 @@ assert( (from_region->is_young() && young_index > 0) || (!from_region->is_young() && young_index == 0), "invariant" ); G1CollectorPolicy* g1p = _g1h->g1_policy(); - markOop m = old->mark(); - int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age() - : m->age(); + uint age = old_mark->has_displaced_mark_helper() ? old_mark->displaced_mark_helper()->age() + : old_mark->age(); GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age, word_sz); AllocationContext_t context = from_region->allocation_context(); - HeapWord* obj_ptr = _g1_par_allocator->allocate(alloc_purpose, word_sz, context); + HeapWord* obj_ptr = _g1_par_allocator->allocate(alloc_purpose, word_sz, old, age, context); #ifndef PRODUCT // Should this evacuation fail? if (_g1h->evacuation_should_fail()) { @@ -196,30 +196,23 @@ alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured; if (g1p->track_object_age(alloc_purpose)) { - // We could simply do obj->incr_age(). However, this causes a - // performance issue. obj->incr_age() will first check whether - // the object has a displaced mark by checking its mark word; - // getting the mark word from the new location of the object - // stalls. So, given that we already have the mark word and we - // are about to install it anyway, it's better to increase the - // age on the mark word, when the object does not have a - // displaced mark word. We're not expecting many objects to have - // a displaced marked word, so that case is not optimized - // further (it could be...) and we simply call obj->incr_age(). - - if (m->has_displaced_mark_helper()) { + if (old_mark->has_displaced_mark_helper()) { // in this case, we have to install the mark word first, // otherwise obj looks to be forwarded (the old mark word, // which contains the forward pointer, was copied) - obj->set_mark(m); - obj->incr_age(); + obj->set_mark(old_mark); + if (age < markOopDesc::max_age) { + markOop new_mark = old_mark->displaced_mark_helper()->set_age(++age); + old_mark->set_displaced_mark_helper(new_mark); + } } else { - m = m->incr_age(); - obj->set_mark(m); + if (age < markOopDesc::max_age) { + obj->set_mark(old_mark->set_age(++age)); + } } - age_table()->add(obj, word_sz); + age_table()->add(age, word_sz); } else { - obj->set_mark(m); + obj->set_mark(old_mark); } if (G1StringDedup::is_enabled()) { --- old/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp 2014-11-06 01:36:43.681526422 -0800 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp 2014-11-06 01:36:43.589526425 -0800 @@ -195,7 +195,7 @@ inline void dispatch_reference(StarTask ref); public: - oop copy_to_survivor_space(oop const obj); + oop copy_to_survivor_space(oop const obj, markOop const old_mark); void trim_queue(); --- old/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp 2014-11-06 01:36:43.981526411 -0800 +++ new/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp 2014-11-06 01:36:43.889526414 -0800 @@ -41,10 +41,11 @@ G1CollectedHeap::in_cset_state_t in_cset_state = _g1h->in_cset_state(obj); if (in_cset_state == G1CollectedHeap::InCSet) { oop forwardee; - if (obj->is_forwarded()) { - forwardee = obj->forwardee(); + markOop m = obj->mark(); + if (m->is_marked()) { + forwardee = (oop) m->decode_pointer(); } else { - forwardee = copy_to_survivor_space(obj); + forwardee = copy_to_survivor_space(obj, m); } oopDesc::encode_store_heap_oop(p, forwardee); } else if (in_cset_state == G1CollectedHeap::IsHumongous) { --- old/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2014-11-06 01:36:44.309526400 -0800 +++ new/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2014-11-06 01:36:44.217526403 -0800 @@ -69,6 +69,7 @@ ObjToScanQueueSet* work_queue_set_, Stack* overflow_stacks_, size_t desired_plab_sz_, + ParNewTracer* gc_tracer, ParallelTaskTerminator& term_) : _to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_), _work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false), @@ -83,6 +84,7 @@ work_queue_set_, &term_), _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), _keep_alive_closure(&_scan_weak_ref_closure), + _gc_tracer(gc_tracer), _strong_roots_time(0.0), _term_time(0.0) { #if TASKQUEUE_STATS @@ -222,7 +224,9 @@ assert(young_gen()->overflow_list() == NULL, "Error"); } -HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) { +HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz, + const oop old, + const uint age) { // Otherwise, if the object is small enough, try to reallocate the // buffer. @@ -252,6 +256,8 @@ plab->set_word_size(buf_size); plab->set_buf(buf_space); record_survivor_plab(buf_space, buf_size); + gc_tracer()->report_promotion_in_new_plab_event(old, word_sz, age, false, + buf_size); obj = plab->allocate_aligned(word_sz, SurvivorAlignmentInBytes); // Note that we cannot compare buf_size < word_sz below // because of AlignmentReserve (see ParGCAllocBuffer::allocate()). @@ -267,6 +273,7 @@ } else { // Too large; allocate the object individually. + gc_tracer()->report_promotion_outside_plab_event(old, word_sz, age, false); obj = sp->par_allocate(word_sz); } } @@ -303,6 +310,7 @@ ObjToScanQueueSet& queue_set, Stack* overflow_stacks_, size_t desired_plab_sz, + ParNewTracer* gc_tracer, ParallelTaskTerminator& term); ~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); } @@ -337,7 +345,8 @@ int num_threads, Space& to_space, ParNewGeneration& gen, Generation& old_gen, ObjToScanQueueSet& queue_set, Stack* overflow_stacks, - size_t desired_plab_sz, ParallelTaskTerminator& term) + size_t desired_plab_sz, ParNewTracer* gc_tracer, + ParallelTaskTerminator& term) : ResourceArray(sizeof(ParScanThreadState), num_threads), _gen(gen), _next_gen(old_gen), _term(term) { @@ -348,7 +357,7 @@ for (int i = 0; i < num_threads; ++i) { new ((ParScanThreadState*)_data + i) ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set, - overflow_stacks, desired_plab_sz, term); + overflow_stacks, desired_plab_sz, gc_tracer, term); } } @@ -980,7 +989,8 @@ ParallelTaskTerminator _term(n_workers, task_queues()); ParScanThreadStateSet thread_state_set(workers->active_workers(), *to(), *this, *_next_gen, *task_queues(), - _overflow_stacks, desired_plab_sz(), _term); + _overflow_stacks, desired_plab_sz(), + &gc_tracer, _term); ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); gch->set_par_threads(n_workers); @@ -1178,7 +1188,7 @@ // Try allocating obj in to-space (unless too old) if (dummyOld.age() < tenuring_threshold()) { - new_obj = (oop)par_scan_state->alloc_in_to_space(sz); + new_obj = (oop)par_scan_state->alloc_in_to_space(sz, old, dummyOld.age()); if (new_obj == NULL) { set_survivor_overflow(true); } @@ -1196,8 +1206,9 @@ return real_forwardee(old); } - new_obj = _next_gen->par_promote(par_scan_state->thread_num(), - old, m, sz); + new_obj = _next_gen->par_promote(par_scan_state->gc_tracer(), + par_scan_state->thread_num(), + old, m, sz); if (new_obj == NULL) { // promotion failed, forward to self @@ -1305,7 +1316,7 @@ // Try allocating obj in to-space (unless too old) if (dummyOld.age() < tenuring_threshold()) { - new_obj = (oop)par_scan_state->alloc_in_to_space(sz); + new_obj = (oop)par_scan_state->alloc_in_to_space(sz, old, dummyOld.age()); if (new_obj == NULL) { set_survivor_overflow(true); } @@ -1314,8 +1325,9 @@ if (new_obj == NULL) { // Either to-space is full or we decided to promote // try allocating obj tenured - new_obj = _next_gen->par_promote(par_scan_state->thread_num(), - old, m, sz); + new_obj = _next_gen->par_promote(par_scan_state->gc_tracer(), + par_scan_state->thread_num(), + old, m, sz); if (new_obj == NULL) { // promotion failed, forward to self --- old/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp 2014-11-06 01:36:44.661526387 -0800 +++ new/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp 2014-11-06 01:36:44.569526391 -0800 @@ -95,6 +95,8 @@ HeapWord *_young_old_boundary; + ParNewTracer* _gc_tracer; + int _hash_seed; int _thread_num; ageTable _ageTable; @@ -132,6 +134,7 @@ ObjToScanQueueSet* work_queue_set_, Stack* overflow_stacks_, size_t desired_plab_sz_, + ParNewTracer* gc_tracer, ParallelTaskTerminator& term_); public: @@ -161,16 +164,22 @@ // Is new_obj a candidate for scan_partial_array_and_push_remainder method. inline bool should_be_partially_scanned(oop new_obj, oop old_obj) const; + ParNewTracer* const gc_tracer() { return _gc_tracer; } + int* hash_seed() { return &_hash_seed; } int thread_num() { return _thread_num; } // Allocate a to-space block of size "sz", or else return NULL. - HeapWord* alloc_in_to_space_slow(size_t word_sz); + // The oop (old) is used to extract information for promotion trace event + HeapWord* alloc_in_to_space_slow(size_t word_sz, const oop old, const uint age); - HeapWord* alloc_in_to_space(size_t word_sz) { + HeapWord* alloc_in_to_space(size_t word_sz, const oop old, const uint age) { HeapWord* obj = to_space_alloc_buffer()->allocate_aligned(word_sz, SurvivorAlignmentInBytes); - if (obj != NULL) return obj; - else return alloc_in_to_space_slow(word_sz); + if (obj != NULL) { + return obj; + } else { + return alloc_in_to_space_slow(word_sz, old, age); + } } HeapWord* young_old_boundary() { return _young_old_boundary; } --- old/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp 2014-11-06 01:36:44.973526377 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp 2014-11-06 01:36:44.877526380 -0800 @@ -84,12 +84,11 @@ if (!test_mark->is_marked()) { bool new_obj_is_tenured = false; size_t new_obj_size = o->size(); + // Find the objects age, MT safe. + uint age = (test_mark->has_displaced_mark_helper() /* o->has_displaced_mark() */) ? + test_mark->displaced_mark_helper()->age() : test_mark->age(); if (!promote_immediately) { - // Find the objects age, MT safe. - uint age = (test_mark->has_displaced_mark_helper() /* o->has_displaced_mark() */) ? - test_mark->displaced_mark_helper()->age() : test_mark->age(); - // Try allocating obj in to-space (unless too old) if (age < PSScavenge::tenuring_threshold()) { new_obj = (oop) _young_lab.allocate(new_obj_size); @@ -98,6 +97,12 @@ if (new_obj_size > (YoungPLABSize / 2)) { // Allocate this object directly new_obj = (oop)young_space()->cas_allocate(new_obj_size); + if (new_obj != NULL) { + PSScavenge::gc_tracer()->report_promotion_outside_plab_event(o, + new_obj_size, + age, + false); + } } else { // Flush and fill _young_lab.flush(); @@ -107,6 +112,14 @@ _young_lab.initialize(MemRegion(lab_base, YoungPLABSize)); // Try the young lab allocation again. new_obj = (oop) _young_lab.allocate(new_obj_size); + if (new_obj != NULL) { + size_t lab_size = pointer_delta(_young_lab.end(), _young_lab.bottom()); + PSScavenge::gc_tracer()->report_promotion_in_new_plab_event(o, + new_obj_size, + age, + false, + lab_size); + } } else { _young_gen_is_full = true; } @@ -132,6 +145,12 @@ if (new_obj_size > (OldPLABSize / 2)) { // Allocate this object directly new_obj = (oop)old_gen()->cas_allocate(new_obj_size); + if (new_obj != NULL) { + PSScavenge::gc_tracer()->report_promotion_outside_plab_event(o, + new_obj_size, + age, + true); + } } else { // Flush and fill _old_lab.flush(); @@ -148,6 +167,14 @@ _old_lab.initialize(MemRegion(lab_base, OldPLABSize)); // Try the old lab allocation again. new_obj = (oop) _old_lab.allocate(new_obj_size); + if (new_obj != NULL) { + size_t lab_size = pointer_delta(_old_lab.end(), _old_lab.bottom()); + PSScavenge::gc_tracer()->report_promotion_in_new_plab_event(o, + new_obj_size, + age, + true, + lab_size); + } } } } --- old/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp 2014-11-06 01:36:45.277526366 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp 2014-11-06 01:36:45.185526369 -0800 @@ -99,6 +99,7 @@ static elapsedTimer* accumulated_time() { return &_accumulated_time; } static int consecutive_skipped_scavenges() { return _consecutive_skipped_scavenges; } + static ParallelScavengeTracer* const gc_tracer() { return &_gc_tracer; } // Performance Counters static CollectorCounters* counters() { return _counters; } --- old/src/share/vm/gc_implementation/shared/ageTable.hpp 2014-11-06 01:36:45.581526355 -0800 +++ new/src/share/vm/gc_implementation/shared/ageTable.hpp 2014-11-06 01:36:45.485526359 -0800 @@ -54,8 +54,11 @@ void clear(); // add entry - void add(oop p, size_t oop_size) { - uint age = p->age(); + void add(const oop p, const size_t oop_size) { + add(p->age(), oop_size); + } + + void add(const uint age, const size_t oop_size) { assert(age > 0 && age < table_size, "invalid age of object"); sizes[age] += oop_size; } --- old/src/share/vm/gc_implementation/shared/gcTrace.cpp 2014-11-06 01:36:45.881526345 -0800 +++ new/src/share/vm/gc_implementation/shared/gcTrace.cpp 2014-11-06 01:36:45.789526348 -0800 @@ -172,6 +172,25 @@ _tenuring_threshold = tenuring_threshold; } +bool YoungGCTracer::should_report_promotion_in_new_plab_event() const { + return should_send_promotion_in_new_plab_event(); +} + +bool YoungGCTracer::should_report_promotion_outside_plab_event() const { + return should_send_promotion_outside_plab_event(); +} + +void YoungGCTracer::report_promotion_in_new_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured, + size_t plab_size) const { + send_promotion_in_new_plab_event(old, obj_size, age, tenured, plab_size); +} + +void YoungGCTracer::report_promotion_outside_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured) const { + send_promotion_outside_plab_event(old, obj_size, age, tenured); +} + void OldGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { assert_set_gc_id(); --- old/src/share/vm/gc_implementation/shared/gcTrace.hpp 2014-11-06 01:36:46.185526334 -0800 +++ new/src/share/vm/gc_implementation/shared/gcTrace.hpp 2014-11-06 01:36:46.093526338 -0800 @@ -157,9 +157,38 @@ void report_promotion_failed(const PromotionFailedInfo& pf_info); void report_tenuring_threshold(const uint tenuring_threshold); + /* + * Methods for reporting Promotion in new or outside PLAB Events. + * + * The object age is always required as it is not certain that the mark word + * of the oop can be trusted at this stage. + * + * obj_size is the size of the promoted object in HeapWords + * + * tenured should be true if the object has been promoted to the old + * space during this GC, if the object is copied to survivor space + * from young space or survivor space (aging) tenured should be false. + * + * plab_size is the size of the newly allocated PLAB in HeapWords + */ + bool should_report_promotion_in_new_plab_event() const; + bool should_report_promotion_outside_plab_event() const; + void report_promotion_in_new_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured, + const size_t plab_size) const; + void report_promotion_outside_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured) const; + private: void send_young_gc_event() const; void send_promotion_failed_event(const PromotionFailedInfo& pf_info) const; + bool should_send_promotion_in_new_plab_event() const; + bool should_send_promotion_outside_plab_event() const; + void send_promotion_in_new_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured, + const size_t plab_size) const; + void send_promotion_outside_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured) const; }; class OldGCTracer : public GCTracer { --- old/src/share/vm/gc_implementation/shared/gcTraceSend.cpp 2014-11-06 01:36:46.489526324 -0800 +++ new/src/share/vm/gc_implementation/shared/gcTraceSend.cpp 2014-11-06 01:36:46.397526327 -0800 @@ -28,6 +28,7 @@ #include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" +#include "runtime/handles.hpp" #include "runtime/os.hpp" #include "trace/tracing.hpp" #include "trace/traceBackend.hpp" @@ -110,6 +111,46 @@ } } +bool YoungGCTracer::should_send_promotion_in_new_plab_event() const { + EventPromoteObjectInNewPLAB event; + return event.should_commit(); +} + +bool YoungGCTracer::should_send_promotion_outside_plab_event() const { + EventPromoteObjectOutsidePLAB event; + return event.should_commit(); +} + +void YoungGCTracer::send_promotion_in_new_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured, + size_t plab_size) const { + + EventPromoteObjectInNewPLAB event; + if (event.should_commit()) { + event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_class(KlassHandle(old->klass())()); + event.set_objectSize(obj_size * HeapWordSize); + event.set_tenured(tenured); + event.set_tenuringAge(age); + event.set_plabSize(plab_size * HeapWordSize); + event.commit(); + } +} + +void YoungGCTracer::send_promotion_outside_plab_event(const oop old, const size_t obj_size, + const uint age, bool tenured) const { + + EventPromoteObjectOutsidePLAB event; + if (event.should_commit()) { + event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_class(KlassHandle(old->klass())()); + event.set_objectSize(obj_size * HeapWordSize); + event.set_tenured(tenured); + event.set_tenuringAge(age); + event.commit(); + } +} + void OldGCTracer::send_old_gc_event() const { EventGCOldGarbageCollection e(UNTIMED); if (e.should_commit()) { --- old/src/share/vm/memory/generation.cpp 2014-11-06 01:36:46.817526312 -0800 +++ new/src/share/vm/memory/generation.cpp 2014-11-06 01:36:46.725526316 -0800 @@ -213,7 +213,7 @@ } } -oop Generation::par_promote(int thread_num, +oop Generation::par_promote(const ParNewTracer* _gc_tracer, int thread_num, oop obj, markOop m, size_t word_sz) { // Could do a bad general impl here that gets a lock. But no. ShouldNotCallThis(); --- old/src/share/vm/memory/generation.hpp 2014-11-06 01:36:47.173526300 -0800 +++ new/src/share/vm/memory/generation.hpp 2014-11-06 01:36:47.081526303 -0800 @@ -26,6 +26,7 @@ #define SHARE_VM_MEMORY_GENERATION_HPP #include "gc_implementation/shared/collectorCounters.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "memory/referenceProcessor.hpp" @@ -314,7 +315,7 @@ // word of "obj" may have been overwritten with a forwarding pointer, and // also taking care to copy the klass pointer *last*. Returns the new // object if successful, or else NULL. - virtual oop par_promote(int thread_num, + virtual oop par_promote(const ParNewTracer* _gc_tracer, int thread_num, oop obj, markOop m, size_t word_sz); // Undo, if possible, the most recent par_promote_alloc allocation by --- old/src/share/vm/memory/tenuredGeneration.cpp 2014-11-06 01:36:47.501526289 -0800 +++ new/src/share/vm/memory/tenuredGeneration.cpp 2014-11-06 01:36:47.409526292 -0800 @@ -27,6 +27,7 @@ #include "gc_implementation/shared/parGCAllocBuffer.hpp" #include "memory/allocation.inline.hpp" #include "memory/blockOffsetTable.inline.hpp" +#include "memory/defNewGeneration.hpp" #include "memory/generation.inline.hpp" #include "memory/generationSpec.hpp" #include "memory/space.hpp" @@ -200,12 +201,12 @@ #if INCLUDE_ALL_GCS -oop TenuredGeneration::par_promote(int thread_num, +oop TenuredGeneration::par_promote(const ParNewTracer* gc_tracer, + int thread_num, oop old, markOop m, size_t word_sz) { ParGCAllocBufferWithBOT* buf = _alloc_buffers[thread_num]; HeapWord* obj_ptr = buf->allocate(word_sz); - bool is_lab = true; if (obj_ptr == NULL) { #ifndef PRODUCT if (Universe::heap()->promotion_should_fail()) { @@ -226,6 +227,13 @@ buf->retire(false, false); buf->set_buf(buf_space); obj_ptr = buf->allocate(word_sz); + if (gc_tracer->should_report_promotion_in_new_plab_event()) { + uint age = m->has_displaced_mark_helper() ? + m->displaced_mark_helper()->age() : + m->age(); + gc_tracer->report_promotion_in_new_plab_event(old, word_sz, age, true, + buf->word_sz()); + } assert(obj_ptr != NULL, "Buffer was definitely big enough..."); } }; @@ -236,6 +244,12 @@ if (obj_ptr == NULL) { obj_ptr = expand_and_allocate(word_sz, false, true /* parallel */); } + if (gc_tracer->should_report_promotion_outside_plab_event()) { + uint age = m->has_displaced_mark_helper() ? + m->displaced_mark_helper()->age() : + m->age(); + gc_tracer->report_promotion_outside_plab_event(old, word_sz, age, true); + } } if (obj_ptr == NULL) return NULL; } --- old/src/share/vm/memory/tenuredGeneration.hpp 2014-11-06 01:36:47.805526278 -0800 +++ new/src/share/vm/memory/tenuredGeneration.hpp 2014-11-06 01:36:47.713526281 -0800 @@ -86,7 +86,7 @@ #if INCLUDE_ALL_GCS // Overrides. - virtual oop par_promote(int thread_num, + virtual oop par_promote(const ParNewTracer* gc_tracer, int thread_num, oop obj, markOop m, size_t word_sz); virtual void par_promote_alloc_undo(int thread_num, HeapWord* obj, size_t word_sz); --- old/src/share/vm/trace/trace.xml 2014-11-06 01:36:48.137526266 -0800 +++ new/src/share/vm/trace/trace.xml 2014-11-06 01:36:48.041526270 -0800 @@ -314,6 +314,28 @@ + + + + + + + + + + + + + + + + + +