提交 75eb81af 编写于 作者: J jcoomes

6970376: ParNew: shared TaskQueue statistics

Reviewed-by: ysr
上级 e6ad5bbe
...@@ -51,9 +51,14 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, ...@@ -51,9 +51,14 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
_is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
_keep_alive_closure(&_scan_weak_ref_closure), _keep_alive_closure(&_scan_weak_ref_closure),
_promotion_failure_size(0), _promotion_failure_size(0),
_pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0),
_strong_roots_time(0.0), _term_time(0.0) _strong_roots_time(0.0), _term_time(0.0)
{ {
#if TASKQUEUE_STATS
_term_attempts = 0;
_overflow_refills = 0;
_overflow_refill_objs = 0;
#endif // TASKQUEUE_STATS
_survivor_chunk_array = _survivor_chunk_array =
(ChunkArray*) old_gen()->get_data_recorder(thread_num()); (ChunkArray*) old_gen()->get_data_recorder(thread_num());
_hash_seed = 17; // Might want to take time-based random value. _hash_seed = 17; // Might want to take time-based random value.
...@@ -100,7 +105,6 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { ...@@ -100,7 +105,6 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) {
// Push remainder. // Push remainder.
bool ok = work_queue()->push(old); bool ok = work_queue()->push(old);
assert(ok, "just popped, push must be okay"); assert(ok, "just popped, push must be okay");
note_push();
} else { } else {
// Restore length so that it can be used if there // Restore length so that it can be used if there
// is a promotion failure and forwarding pointers // is a promotion failure and forwarding pointers
...@@ -126,7 +130,6 @@ void ParScanThreadState::trim_queues(int max_size) { ...@@ -126,7 +130,6 @@ void ParScanThreadState::trim_queues(int max_size) {
while (queue->size() > (juint)max_size) { while (queue->size() > (juint)max_size) {
oop obj_to_scan; oop obj_to_scan;
if (queue->pop_local(obj_to_scan)) { if (queue->pop_local(obj_to_scan)) {
note_pop();
if ((HeapWord *)obj_to_scan < young_old_boundary()) { if ((HeapWord *)obj_to_scan < young_old_boundary()) {
if (obj_to_scan->is_objArray() && if (obj_to_scan->is_objArray() &&
obj_to_scan->is_forwarded() && obj_to_scan->is_forwarded() &&
...@@ -271,20 +274,28 @@ public: ...@@ -271,20 +274,28 @@ public:
GrowableArray<oop>** overflow_stacks_, GrowableArray<oop>** overflow_stacks_,
size_t desired_plab_sz, size_t desired_plab_sz,
ParallelTaskTerminator& term); ParallelTaskTerminator& term);
~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); }
inline ParScanThreadState& thread_state(int i); inline ParScanThreadState& thread_state(int i);
int pushes() { return _pushes; }
int pops() { return _pops; }
int steals() { return _steals; }
void reset(bool promotion_failed); void reset(bool promotion_failed);
void flush(); void flush();
#if TASKQUEUE_STATS
static void
print_termination_stats_hdr(outputStream* const st = gclog_or_tty);
void print_termination_stats(outputStream* const st = gclog_or_tty);
static void
print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty);
void print_taskqueue_stats(outputStream* const st = gclog_or_tty);
void reset_stats();
#endif // TASKQUEUE_STATS
private: private:
ParallelTaskTerminator& _term; ParallelTaskTerminator& _term;
ParNewGeneration& _gen; ParNewGeneration& _gen;
Generation& _next_gen; Generation& _next_gen;
// staticstics
int _pushes;
int _pops;
int _steals;
}; };
...@@ -294,8 +305,7 @@ ParScanThreadStateSet::ParScanThreadStateSet( ...@@ -294,8 +305,7 @@ ParScanThreadStateSet::ParScanThreadStateSet(
GrowableArray<oop>** overflow_stack_set_, GrowableArray<oop>** overflow_stack_set_,
size_t desired_plab_sz, ParallelTaskTerminator& term) size_t desired_plab_sz, ParallelTaskTerminator& term)
: ResourceArray(sizeof(ParScanThreadState), num_threads), : ResourceArray(sizeof(ParScanThreadState), num_threads),
_gen(gen), _next_gen(old_gen), _term(term), _gen(gen), _next_gen(old_gen), _term(term)
_pushes(0), _pops(0), _steals(0)
{ {
assert(num_threads > 0, "sanity check!"); assert(num_threads > 0, "sanity check!");
// Initialize states. // Initialize states.
...@@ -323,6 +333,82 @@ void ParScanThreadStateSet::reset(bool promotion_failed) ...@@ -323,6 +333,82 @@ void ParScanThreadStateSet::reset(bool promotion_failed)
} }
} }
#if TASKQUEUE_STATS
void
ParScanThreadState::reset_stats()
{
taskqueue_stats().reset();
_term_attempts = 0;
_overflow_refills = 0;
_overflow_refill_objs = 0;
}
void ParScanThreadStateSet::reset_stats()
{
for (int i = 0; i < length(); ++i) {
thread_state(i).reset_stats();
}
}
void
ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st)
{
st->print_raw_cr("GC Termination Stats");
st->print_raw_cr(" elapsed --strong roots-- "
"-------termination-------");
st->print_raw_cr("thr ms ms % "
" ms % attempts");
st->print_raw_cr("--- --------- --------- ------ "
"--------- ------ --------");
}
void ParScanThreadStateSet::print_termination_stats(outputStream* const st)
{
print_termination_stats_hdr(st);
for (int i = 0; i < length(); ++i) {
const ParScanThreadState & pss = thread_state(i);
const double elapsed_ms = pss.elapsed_time() * 1000.0;
const double s_roots_ms = pss.strong_roots_time() * 1000.0;
const double term_ms = pss.term_time() * 1000.0;
st->print_cr("%3d %9.2f %9.2f %6.2f "
"%9.2f %6.2f " SIZE_FORMAT_W(8),
i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms,
term_ms, term_ms * 100 / elapsed_ms, pss.term_attempts());
}
}
// Print stats related to work queue activity.
void ParScanThreadStateSet::print_taskqueue_stats_hdr(outputStream* const st)
{
st->print_raw_cr("GC Task Stats");
st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr();
st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr();
}
void ParScanThreadStateSet::print_taskqueue_stats(outputStream* const st)
{
print_taskqueue_stats_hdr(st);
TaskQueueStats totals;
for (int i = 0; i < length(); ++i) {
const ParScanThreadState & pss = thread_state(i);
const TaskQueueStats & stats = pss.taskqueue_stats();
st->print("%3d ", i); stats.print(st); st->cr();
totals += stats;
if (pss.overflow_refills() > 0) {
st->print_cr(" " SIZE_FORMAT_W(10) " overflow refills "
SIZE_FORMAT_W(10) " overflow objects",
pss.overflow_refills(), pss.overflow_refill_objs());
}
}
st->print("tot "); totals.print(st); st->cr();
DEBUG_ONLY(totals.verify());
}
#endif // TASKQUEUE_STATS
void ParScanThreadStateSet::flush() void ParScanThreadStateSet::flush()
{ {
// Work in this loop should be kept as lightweight as // Work in this loop should be kept as lightweight as
...@@ -346,42 +432,8 @@ void ParScanThreadStateSet::flush() ...@@ -346,42 +432,8 @@ void ParScanThreadStateSet::flush()
// Inform old gen that we're done. // Inform old gen that we're done.
_next_gen.par_promote_alloc_done(i); _next_gen.par_promote_alloc_done(i);
_next_gen.par_oop_since_save_marks_iterate_done(i); _next_gen.par_oop_since_save_marks_iterate_done(i);
// Flush stats related to work queue activity (push/pop/steal)
// This could conceivably become a bottleneck; if so, we'll put the
// stat's gathering under the flag.
if (PAR_STATS_ENABLED) {
_pushes += par_scan_state.pushes();
_pops += par_scan_state.pops();
_steals += par_scan_state.steals();
if (ParallelGCVerbose) {
gclog_or_tty->print("Thread %d complete:\n"
" Pushes: %7d Pops: %7d Steals %7d (in %d attempts)\n",
i, par_scan_state.pushes(), par_scan_state.pops(),
par_scan_state.steals(), par_scan_state.steal_attempts());
if (par_scan_state.overflow_pushes() > 0 ||
par_scan_state.overflow_refills() > 0) {
gclog_or_tty->print(" Overflow pushes: %7d "
"Overflow refills: %7d for %d objs.\n",
par_scan_state.overflow_pushes(),
par_scan_state.overflow_refills(),
par_scan_state.overflow_refill_objs());
}
double elapsed = par_scan_state.elapsed();
double strong_roots = par_scan_state.strong_roots_time();
double term = par_scan_state.term_time();
gclog_or_tty->print(
" Elapsed: %7.2f ms.\n"
" Strong roots: %7.2f ms (%6.2f%%)\n"
" Termination: %7.2f ms (%6.2f%%) (in %d entries)\n",
elapsed * 1000.0,
strong_roots * 1000.0, (strong_roots*100.0/elapsed),
term * 1000.0, (term*100.0/elapsed),
par_scan_state.term_attempts());
}
}
} }
if (UseConcMarkSweepGC && ParallelGCThreads > 0) { if (UseConcMarkSweepGC && ParallelGCThreads > 0) {
// We need to call this even when ResizeOldPLAB is disabled // We need to call this even when ResizeOldPLAB is disabled
// so as to avoid breaking some asserts. While we may be able // so as to avoid breaking some asserts. While we may be able
...@@ -456,15 +508,12 @@ void ParEvacuateFollowersClosure::do_void() { ...@@ -456,15 +508,12 @@ void ParEvacuateFollowersClosure::do_void() {
// We have no local work, attempt to steal from other threads. // We have no local work, attempt to steal from other threads.
// attempt to steal work from promoted. // attempt to steal work from promoted.
par_scan_state()->note_steal_attempt();
if (task_queues()->steal(par_scan_state()->thread_num(), if (task_queues()->steal(par_scan_state()->thread_num(),
par_scan_state()->hash_seed(), par_scan_state()->hash_seed(),
obj_to_scan)) { obj_to_scan)) {
par_scan_state()->note_steal();
bool res = work_q->push(obj_to_scan); bool res = work_q->push(obj_to_scan);
assert(res, "Empty queue should have room for a push."); assert(res, "Empty queue should have room for a push.");
par_scan_state()->note_push();
// if successful, goto Start. // if successful, goto Start.
continue; continue;
...@@ -842,17 +891,6 @@ void ParNewGeneration::collect(bool full, ...@@ -842,17 +891,6 @@ void ParNewGeneration::collect(bool full,
} }
thread_state_set.reset(promotion_failed()); thread_state_set.reset(promotion_failed());
if (PAR_STATS_ENABLED && ParallelGCVerbose) {
gclog_or_tty->print("Thread totals:\n"
" Pushes: %7d Pops: %7d Steals %7d (sum = %7d).\n",
thread_state_set.pushes(), thread_state_set.pops(),
thread_state_set.steals(),
thread_state_set.pops()+thread_state_set.steals());
}
assert(thread_state_set.pushes() == thread_state_set.pops()
+ thread_state_set.steals(),
"Or else the queues are leaky.");
// Process (weak) reference objects found during scavenge. // Process (weak) reference objects found during scavenge.
ReferenceProcessor* rp = ref_processor(); ReferenceProcessor* rp = ref_processor();
IsAliveClosure is_alive(this); IsAliveClosure is_alive(this);
...@@ -932,6 +970,9 @@ void ParNewGeneration::collect(bool full, ...@@ -932,6 +970,9 @@ void ParNewGeneration::collect(bool full,
gch->print_heap_change(gch_prev_used); gch->print_heap_change(gch_prev_used);
} }
TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats());
TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats());
if (UseAdaptiveSizePolicy) { if (UseAdaptiveSizePolicy) {
size_policy->minor_collection_end(gch->gc_cause()); size_policy->minor_collection_end(gch->gc_cause());
size_policy->avg_survived()->sample(from()->used()); size_policy->avg_survived()->sample(from()->used());
...@@ -1104,9 +1145,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo( ...@@ -1104,9 +1145,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo(
gclog_or_tty->print("queue overflow!\n"); gclog_or_tty->print("queue overflow!\n");
} }
push_on_overflow_list(old, par_scan_state); push_on_overflow_list(old, par_scan_state);
par_scan_state->note_overflow_push(); TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0));
} }
par_scan_state->note_push();
return new_obj; return new_obj;
} }
...@@ -1227,9 +1267,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo( ...@@ -1227,9 +1267,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo(
if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) { if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) {
// Add stats for overflow pushes. // Add stats for overflow pushes.
push_on_overflow_list(old, par_scan_state); push_on_overflow_list(old, par_scan_state);
par_scan_state->note_overflow_push(); TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0));
} }
par_scan_state->note_push();
return new_obj; return new_obj;
} }
...@@ -1466,7 +1505,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan ...@@ -1466,7 +1505,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
cur = next; cur = next;
n++; n++;
} }
par_scan_state->note_overflow_refill(n); TASKQUEUE_STATS_ONLY(par_scan_state->note_overflow_refill(n));
#ifndef PRODUCT #ifndef PRODUCT
assert(_num_par_pushes >= n, "Too many pops?"); assert(_num_par_pushes >= n, "Too many pops?");
Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes); Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes);
......
...@@ -36,9 +36,6 @@ class ParEvacuateFollowersClosure; ...@@ -36,9 +36,6 @@ class ParEvacuateFollowersClosure;
typedef Padded<OopTaskQueue> ObjToScanQueue; typedef Padded<OopTaskQueue> ObjToScanQueue;
typedef GenericTaskQueueSet<ObjToScanQueue> ObjToScanQueueSet; typedef GenericTaskQueueSet<ObjToScanQueue> ObjToScanQueueSet;
// Enable this to get push/pop/steal stats.
const int PAR_STATS_ENABLED = 0;
class ParKeepAliveClosure: public DefNewGeneration::KeepAliveClosure { class ParKeepAliveClosure: public DefNewGeneration::KeepAliveClosure {
private: private:
ParScanWeakRefClosure* _par_cl; ParScanWeakRefClosure* _par_cl;
...@@ -94,8 +91,11 @@ class ParScanThreadState { ...@@ -94,8 +91,11 @@ class ParScanThreadState {
bool _to_space_full; bool _to_space_full;
int _pushes, _pops, _steals, _steal_attempts, _term_attempts; #if TASKQUEUE_STATS
int _overflow_pushes, _overflow_refills, _overflow_refill_objs; size_t _term_attempts;
size_t _overflow_refills;
size_t _overflow_refill_objs;
#endif // TASKQUEUE_STATS
// Stats for promotion failure // Stats for promotion failure
size_t _promotion_failure_size; size_t _promotion_failure_size;
...@@ -181,45 +181,38 @@ class ParScanThreadState { ...@@ -181,45 +181,38 @@ class ParScanThreadState {
} }
void print_and_clear_promotion_failure_size(); void print_and_clear_promotion_failure_size();
int pushes() { return _pushes; } #if TASKQUEUE_STATS
int pops() { return _pops; } TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; }
int steals() { return _steals; }
int steal_attempts() { return _steal_attempts; } size_t term_attempts() const { return _term_attempts; }
int term_attempts() { return _term_attempts; } size_t overflow_refills() const { return _overflow_refills; }
int overflow_pushes() { return _overflow_pushes; } size_t overflow_refill_objs() const { return _overflow_refill_objs; }
int overflow_refills() { return _overflow_refills; }
int overflow_refill_objs() { return _overflow_refill_objs; } void note_term_attempt() { ++_term_attempts; }
void note_overflow_refill(size_t objs) {
void note_push() { if (PAR_STATS_ENABLED) _pushes++; } ++_overflow_refills; _overflow_refill_objs += objs;
void note_pop() { if (PAR_STATS_ENABLED) _pops++; }
void note_steal() { if (PAR_STATS_ENABLED) _steals++; }
void note_steal_attempt() { if (PAR_STATS_ENABLED) _steal_attempts++; }
void note_term_attempt() { if (PAR_STATS_ENABLED) _term_attempts++; }
void note_overflow_push() { if (PAR_STATS_ENABLED) _overflow_pushes++; }
void note_overflow_refill(int objs) {
if (PAR_STATS_ENABLED) {
_overflow_refills++;
_overflow_refill_objs += objs;
}
} }
void reset_stats();
#endif // TASKQUEUE_STATS
void start_strong_roots() { void start_strong_roots() {
_start_strong_roots = os::elapsedTime(); _start_strong_roots = os::elapsedTime();
} }
void end_strong_roots() { void end_strong_roots() {
_strong_roots_time += (os::elapsedTime() - _start_strong_roots); _strong_roots_time += (os::elapsedTime() - _start_strong_roots);
} }
double strong_roots_time() { return _strong_roots_time; } double strong_roots_time() const { return _strong_roots_time; }
void start_term_time() { void start_term_time() {
note_term_attempt(); TASKQUEUE_STATS_ONLY(note_term_attempt());
_start_term = os::elapsedTime(); _start_term = os::elapsedTime();
} }
void end_term_time() { void end_term_time() {
_term_time += (os::elapsedTime() - _start_term); _term_time += (os::elapsedTime() - _start_term);
} }
double term_time() { return _term_time; } double term_time() const { return _term_time; }
double elapsed() { double elapsed_time() const {
return os::elapsedTime() - _start; return os::elapsedTime() - _start;
} }
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册