Mercurial > hg > truffle
comparison src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @ 5986:500023bd0818
7143511: G1: Another instance of high GC Worker Other time (50ms)
Summary: Tiered compilation has increased the number of nmethods in the code cache. This has, in turn, significantly increased the number of marked nmethods processed during the StrongRootsScope destructor. Create a specialized version of CodeBlobToOopClosure for G1 which places only those nmethods that contain pointers into the collection set on to the marked nmethods list.
Reviewed-by: iveresov, tonyp
author | johnc |
---|---|
date | Tue, 13 Mar 2012 11:05:32 -0700 |
parents | 64bf7c8270cb |
children | 748051fd24ce |
comparison
equal
deleted
inserted
replaced
5972:9a9bb0010c91 | 5986:500023bd0818 |
---|---|
4673 if (worker_id >= _n_workers) return; // no work needed this round | 4673 if (worker_id >= _n_workers) return; // no work needed this round |
4674 | 4674 |
4675 double start_time_ms = os::elapsedTime() * 1000.0; | 4675 double start_time_ms = os::elapsedTime() * 1000.0; |
4676 _g1h->g1_policy()->record_gc_worker_start_time(worker_id, start_time_ms); | 4676 _g1h->g1_policy()->record_gc_worker_start_time(worker_id, start_time_ms); |
4677 | 4677 |
4678 ResourceMark rm; | |
4679 HandleMark hm; | |
4680 | |
4681 ReferenceProcessor* rp = _g1h->ref_processor_stw(); | |
4682 | |
4683 G1ParScanThreadState pss(_g1h, worker_id); | |
4684 G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, rp); | |
4685 G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp); | |
4686 G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, rp); | |
4687 | |
4688 pss.set_evac_closure(&scan_evac_cl); | |
4689 pss.set_evac_failure_closure(&evac_failure_cl); | |
4690 pss.set_partial_scan_closure(&partial_scan_cl); | |
4691 | |
4692 G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss, rp); | |
4693 G1ParScanPermClosure only_scan_perm_cl(_g1h, &pss, rp); | |
4694 | |
4695 G1ParScanAndMarkExtRootClosure scan_mark_root_cl(_g1h, &pss, rp); | |
4696 G1ParScanAndMarkPermClosure scan_mark_perm_cl(_g1h, &pss, rp); | |
4697 | |
4698 OopClosure* scan_root_cl = &only_scan_root_cl; | |
4699 OopsInHeapRegionClosure* scan_perm_cl = &only_scan_perm_cl; | |
4700 | |
4701 if (_g1h->g1_policy()->during_initial_mark_pause()) { | |
4702 // We also need to mark copied objects. | |
4703 scan_root_cl = &scan_mark_root_cl; | |
4704 scan_perm_cl = &scan_mark_perm_cl; | |
4705 } | |
4706 | |
4707 G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss); | |
4708 | |
4709 pss.start_strong_roots(); | |
4710 _g1h->g1_process_strong_roots(/* not collecting perm */ false, | |
4711 SharedHeap::SO_AllClasses, | |
4712 scan_root_cl, | |
4713 &push_heap_rs_cl, | |
4714 scan_perm_cl, | |
4715 worker_id); | |
4716 pss.end_strong_roots(); | |
4717 | |
4718 { | 4678 { |
4719 double start = os::elapsedTime(); | 4679 ResourceMark rm; |
4720 G1ParEvacuateFollowersClosure evac(_g1h, &pss, _queues, &_terminator); | 4680 HandleMark hm; |
4721 evac.do_void(); | 4681 |
4722 double elapsed_ms = (os::elapsedTime()-start)*1000.0; | 4682 ReferenceProcessor* rp = _g1h->ref_processor_stw(); |
4723 double term_ms = pss.term_time()*1000.0; | 4683 |
4724 _g1h->g1_policy()->record_obj_copy_time(worker_id, elapsed_ms-term_ms); | 4684 G1ParScanThreadState pss(_g1h, worker_id); |
4725 _g1h->g1_policy()->record_termination(worker_id, term_ms, pss.term_attempts()); | 4685 G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, rp); |
4726 } | 4686 G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp); |
4727 _g1h->g1_policy()->record_thread_age_table(pss.age_table()); | 4687 G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, rp); |
4728 _g1h->update_surviving_young_words(pss.surviving_young_words()+1); | 4688 |
4729 | 4689 pss.set_evac_closure(&scan_evac_cl); |
4730 // Clean up any par-expanded rem sets. | 4690 pss.set_evac_failure_closure(&evac_failure_cl); |
4731 HeapRegionRemSet::par_cleanup(); | 4691 pss.set_partial_scan_closure(&partial_scan_cl); |
4732 | 4692 |
4733 if (ParallelGCVerbose) { | 4693 G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss, rp); |
4734 MutexLocker x(stats_lock()); | 4694 G1ParScanPermClosure only_scan_perm_cl(_g1h, &pss, rp); |
4735 pss.print_termination_stats(worker_id); | 4695 |
4736 } | 4696 G1ParScanAndMarkExtRootClosure scan_mark_root_cl(_g1h, &pss, rp); |
4737 | 4697 G1ParScanAndMarkPermClosure scan_mark_perm_cl(_g1h, &pss, rp); |
4738 assert(pss.refs()->is_empty(), "should be empty"); | 4698 |
4699 OopClosure* scan_root_cl = &only_scan_root_cl; | |
4700 OopsInHeapRegionClosure* scan_perm_cl = &only_scan_perm_cl; | |
4701 | |
4702 if (_g1h->g1_policy()->during_initial_mark_pause()) { | |
4703 // We also need to mark copied objects. | |
4704 scan_root_cl = &scan_mark_root_cl; | |
4705 scan_perm_cl = &scan_mark_perm_cl; | |
4706 } | |
4707 | |
4708 G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss); | |
4709 | |
4710 pss.start_strong_roots(); | |
4711 _g1h->g1_process_strong_roots(/* not collecting perm */ false, | |
4712 SharedHeap::SO_AllClasses, | |
4713 scan_root_cl, | |
4714 &push_heap_rs_cl, | |
4715 scan_perm_cl, | |
4716 worker_id); | |
4717 pss.end_strong_roots(); | |
4718 | |
4719 { | |
4720 double start = os::elapsedTime(); | |
4721 G1ParEvacuateFollowersClosure evac(_g1h, &pss, _queues, &_terminator); | |
4722 evac.do_void(); | |
4723 double elapsed_ms = (os::elapsedTime()-start)*1000.0; | |
4724 double term_ms = pss.term_time()*1000.0; | |
4725 _g1h->g1_policy()->record_obj_copy_time(worker_id, elapsed_ms-term_ms); | |
4726 _g1h->g1_policy()->record_termination(worker_id, term_ms, pss.term_attempts()); | |
4727 } | |
4728 _g1h->g1_policy()->record_thread_age_table(pss.age_table()); | |
4729 _g1h->update_surviving_young_words(pss.surviving_young_words()+1); | |
4730 | |
4731 // Clean up any par-expanded rem sets. | |
4732 HeapRegionRemSet::par_cleanup(); | |
4733 | |
4734 if (ParallelGCVerbose) { | |
4735 MutexLocker x(stats_lock()); | |
4736 pss.print_termination_stats(worker_id); | |
4737 } | |
4738 | |
4739 assert(pss.refs()->is_empty(), "should be empty"); | |
4740 | |
4741 // Close the inner scope so that the ResourceMark and HandleMark | |
4742 // destructors are executed here and are included as part of the | |
4743 // "GC Worker Time". | |
4744 } | |
4745 | |
4739 double end_time_ms = os::elapsedTime() * 1000.0; | 4746 double end_time_ms = os::elapsedTime() * 1000.0; |
4740 _g1h->g1_policy()->record_gc_worker_end_time(worker_id, end_time_ms); | 4747 _g1h->g1_policy()->record_gc_worker_end_time(worker_id, end_time_ms); |
4741 } | 4748 } |
4742 }; | 4749 }; |
4743 | 4750 |
4744 // *** Common G1 Evacuation Stuff | 4751 // *** Common G1 Evacuation Stuff |
4752 | |
4753 // Closures that support the filtering of CodeBlobs scanned during | |
4754 // external root scanning. | |
4755 | |
4756 // Closure applied to reference fields in code blobs (specifically nmethods) | |
4757 // to determine whether an nmethod contains references that point into | |
4758 // the collection set. Used as a predicate when walking code roots so | |
4759 // that only nmethods that point into the collection set are added to the | |
4760 // 'marked' list. | |
4761 | |
4762 class G1FilteredCodeBlobToOopClosure : public CodeBlobToOopClosure { | |
4763 | |
4764 class G1PointsIntoCSOopClosure : public OopClosure { | |
4765 G1CollectedHeap* _g1; | |
4766 bool _points_into_cs; | |
4767 public: | |
4768 G1PointsIntoCSOopClosure(G1CollectedHeap* g1) : | |
4769 _g1(g1), _points_into_cs(false) { } | |
4770 | |
4771 bool points_into_cs() const { return _points_into_cs; } | |
4772 | |
4773 template <class T> | |
4774 void do_oop_nv(T* p) { | |
4775 if (!_points_into_cs) { | |
4776 T heap_oop = oopDesc::load_heap_oop(p); | |
4777 if (!oopDesc::is_null(heap_oop) && | |
4778 _g1->in_cset_fast_test(oopDesc::decode_heap_oop_not_null(heap_oop))) { | |
4779 _points_into_cs = true; | |
4780 } | |
4781 } | |
4782 } | |
4783 | |
4784 virtual void do_oop(oop* p) { do_oop_nv(p); } | |
4785 virtual void do_oop(narrowOop* p) { do_oop_nv(p); } | |
4786 }; | |
4787 | |
4788 G1CollectedHeap* _g1; | |
4789 | |
4790 public: | |
4791 G1FilteredCodeBlobToOopClosure(G1CollectedHeap* g1, OopClosure* cl) : | |
4792 CodeBlobToOopClosure(cl, true), _g1(g1) { } | |
4793 | |
4794 virtual void do_code_blob(CodeBlob* cb) { | |
4795 nmethod* nm = cb->as_nmethod_or_null(); | |
4796 if (nm != NULL && !(nm->test_oops_do_mark())) { | |
4797 G1PointsIntoCSOopClosure predicate_cl(_g1); | |
4798 nm->oops_do(&predicate_cl); | |
4799 | |
4800 if (predicate_cl.points_into_cs()) { | |
4801 // At least one of the reference fields or the oop relocations | |
4802 // in the nmethod points into the collection set. We have to | |
4803 // 'mark' this nmethod. | |
4804 // Note: Revisit the following if CodeBlobToOopClosure::do_code_blob() | |
4805 // or MarkingCodeBlobClosure::do_code_blob() change. | |
4806 if (!nm->test_set_oops_do_mark()) { | |
4807 do_newly_marked_nmethod(nm); | |
4808 } | |
4809 } | |
4810 } | |
4811 } | |
4812 }; | |
4745 | 4813 |
4746 // This method is run in a GC worker. | 4814 // This method is run in a GC worker. |
4747 | 4815 |
4748 void | 4816 void |
4749 G1CollectedHeap:: | 4817 G1CollectedHeap:: |
4762 BufferingOopsInGenClosure buf_scan_perm(scan_perm); | 4830 BufferingOopsInGenClosure buf_scan_perm(scan_perm); |
4763 buf_scan_perm.set_generation(perm_gen()); | 4831 buf_scan_perm.set_generation(perm_gen()); |
4764 | 4832 |
4765 // Walk the code cache w/o buffering, because StarTask cannot handle | 4833 // Walk the code cache w/o buffering, because StarTask cannot handle |
4766 // unaligned oop locations. | 4834 // unaligned oop locations. |
4767 CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, /*do_marking=*/ true); | 4835 G1FilteredCodeBlobToOopClosure eager_scan_code_roots(this, scan_non_heap_roots); |
4768 | 4836 |
4769 process_strong_roots(false, // no scoping; this is parallel code | 4837 process_strong_roots(false, // no scoping; this is parallel code |
4770 collecting_perm_gen, so, | 4838 collecting_perm_gen, so, |
4771 &buf_scan_non_heap_roots, | 4839 &buf_scan_non_heap_roots, |
4772 &eager_scan_code_roots, | 4840 &eager_scan_code_roots, |
5376 init_for_evac_failure(NULL); | 5444 init_for_evac_failure(NULL); |
5377 | 5445 |
5378 rem_set()->prepare_for_younger_refs_iterate(true); | 5446 rem_set()->prepare_for_younger_refs_iterate(true); |
5379 | 5447 |
5380 assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty"); | 5448 assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty"); |
5381 double start_par = os::elapsedTime(); | 5449 double start_par_time_sec = os::elapsedTime(); |
5382 | 5450 double end_par_time_sec; |
5383 if (G1CollectedHeap::use_parallel_gc_threads()) { | 5451 |
5384 // The individual threads will set their evac-failure closures. | 5452 { |
5385 StrongRootsScope srs(this); | 5453 StrongRootsScope srs(this); |
5386 if (ParallelGCVerbose) G1ParScanThreadState::print_termination_stats_hdr(); | 5454 |
5387 // These tasks use ShareHeap::_process_strong_tasks | 5455 if (G1CollectedHeap::use_parallel_gc_threads()) { |
5388 assert(UseDynamicNumberOfGCThreads || | 5456 // The individual threads will set their evac-failure closures. |
5389 workers()->active_workers() == workers()->total_workers(), | 5457 if (ParallelGCVerbose) G1ParScanThreadState::print_termination_stats_hdr(); |
5390 "If not dynamic should be using all the workers"); | 5458 // These tasks use ShareHeap::_process_strong_tasks |
5391 workers()->run_task(&g1_par_task); | 5459 assert(UseDynamicNumberOfGCThreads || |
5392 } else { | 5460 workers()->active_workers() == workers()->total_workers(), |
5393 StrongRootsScope srs(this); | 5461 "If not dynamic should be using all the workers"); |
5394 g1_par_task.set_for_termination(n_workers); | 5462 workers()->run_task(&g1_par_task); |
5395 g1_par_task.work(0); | 5463 } else { |
5396 } | 5464 g1_par_task.set_for_termination(n_workers); |
5397 | 5465 g1_par_task.work(0); |
5398 double par_time = (os::elapsedTime() - start_par) * 1000.0; | 5466 } |
5399 g1_policy()->record_par_time(par_time); | 5467 end_par_time_sec = os::elapsedTime(); |
5468 | |
5469 // Closing the inner scope will execute the destructor | |
5470 // for the StrongRootsScope object. We record the current | |
5471 // elapsed time before closing the scope so that time | |
5472 // taken for the SRS destructor is NOT included in the | |
5473 // reported parallel time. | |
5474 } | |
5475 | |
5476 double par_time_ms = (end_par_time_sec - start_par_time_sec) * 1000.0; | |
5477 g1_policy()->record_par_time(par_time_ms); | |
5478 | |
5479 double code_root_fixup_time_ms = | |
5480 (os::elapsedTime() - end_par_time_sec) * 1000.0; | |
5481 g1_policy()->record_code_root_fixup_time(code_root_fixup_time_ms); | |
5400 | 5482 |
5401 set_par_threads(0); | 5483 set_par_threads(0); |
5402 | 5484 |
5403 // Process any discovered reference objects - we have | 5485 // Process any discovered reference objects - we have |
5404 // to do this _before_ we retire the GC alloc regions | 5486 // to do this _before_ we retire the GC alloc regions |