Mercurial > hg > graal-jvmci-8
comparison src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @ 4095:bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
Summary: Select number of GC threads dynamically based on heap usage and number of Java threads
Reviewed-by: johnc, ysr, jcoomes
author | jmasa |
---|---|
date | Tue, 09 Aug 2011 10:16:01 -0700 |
parents | 92da084fefc9 |
children | 441e946dc1af |
comparison
equal
deleted
inserted
replaced
4094:3a298e04d914 | 4095:bca17e38de00 |
---|---|
303 | 303 |
304 ~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); } | 304 ~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); } |
305 | 305 |
306 inline ParScanThreadState& thread_state(int i); | 306 inline ParScanThreadState& thread_state(int i); |
307 | 307 |
308 void reset(bool promotion_failed); | 308 void reset(int active_workers, bool promotion_failed); |
309 void flush(); | 309 void flush(); |
310 | 310 |
311 #if TASKQUEUE_STATS | 311 #if TASKQUEUE_STATS |
312 static void | 312 static void |
313 print_termination_stats_hdr(outputStream* const st = gclog_or_tty); | 313 print_termination_stats_hdr(outputStream* const st = gclog_or_tty); |
320 | 320 |
321 private: | 321 private: |
322 ParallelTaskTerminator& _term; | 322 ParallelTaskTerminator& _term; |
323 ParNewGeneration& _gen; | 323 ParNewGeneration& _gen; |
324 Generation& _next_gen; | 324 Generation& _next_gen; |
325 public: | |
326 bool is_valid(int id) const { return id < length(); } | |
327 ParallelTaskTerminator* terminator() { return &_term; } | |
325 }; | 328 }; |
326 | 329 |
327 | 330 |
328 ParScanThreadStateSet::ParScanThreadStateSet( | 331 ParScanThreadStateSet::ParScanThreadStateSet( |
329 int num_threads, Space& to_space, ParNewGeneration& gen, | 332 int num_threads, Space& to_space, ParNewGeneration& gen, |
349 assert(i >= 0 && i < length(), "sanity check!"); | 352 assert(i >= 0 && i < length(), "sanity check!"); |
350 return ((ParScanThreadState*)_data)[i]; | 353 return ((ParScanThreadState*)_data)[i]; |
351 } | 354 } |
352 | 355 |
353 | 356 |
354 void ParScanThreadStateSet::reset(bool promotion_failed) | 357 void ParScanThreadStateSet::reset(int active_threads, bool promotion_failed) |
355 { | 358 { |
356 _term.reset_for_reuse(); | 359 _term.reset_for_reuse(active_threads); |
357 if (promotion_failed) { | 360 if (promotion_failed) { |
358 for (int i = 0; i < length(); ++i) { | 361 for (int i = 0; i < length(); ++i) { |
359 thread_state(i).print_and_clear_promotion_failure_size(); | 362 thread_state(i).print_and_clear_promotion_failure_size(); |
360 } | 363 } |
361 } | 364 } |
567 _gen(gen), _next_gen(next_gen), | 570 _gen(gen), _next_gen(next_gen), |
568 _young_old_boundary(young_old_boundary), | 571 _young_old_boundary(young_old_boundary), |
569 _state_set(state_set) | 572 _state_set(state_set) |
570 {} | 573 {} |
571 | 574 |
575 // Reset the terminator for the given number of | |
576 // active threads. | |
577 void ParNewGenTask::set_for_termination(int active_workers) { | |
578 _state_set->reset(active_workers, _gen->promotion_failed()); | |
579 // Should the heap be passed in? There's only 1 for now so | |
580 // grab it instead. | |
581 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
582 gch->set_n_termination(active_workers); | |
583 } | |
584 | |
585 // The "i" passed to this method is the part of the work for | |
586 // this thread. It is not the worker ID. The "i" is derived | |
587 // from _started_workers which is incremented in internal_note_start() | |
588 // called in GangWorker loop() and which is called under the | |
589 // which is called under the protection of the gang monitor and is | |
590 // called after a task is started. So "i" is based on | |
591 // first-come-first-served. | |
592 | |
572 void ParNewGenTask::work(int i) { | 593 void ParNewGenTask::work(int i) { |
573 GenCollectedHeap* gch = GenCollectedHeap::heap(); | 594 GenCollectedHeap* gch = GenCollectedHeap::heap(); |
574 // Since this is being done in a separate thread, need new resource | 595 // Since this is being done in a separate thread, need new resource |
575 // and handle marks. | 596 // and handle marks. |
576 ResourceMark rm; | 597 ResourceMark rm; |
579 assert(gch->n_gens() == 2, "Par young collection currently only works with one older gen."); | 600 assert(gch->n_gens() == 2, "Par young collection currently only works with one older gen."); |
580 | 601 |
581 Generation* old_gen = gch->next_gen(_gen); | 602 Generation* old_gen = gch->next_gen(_gen); |
582 | 603 |
583 ParScanThreadState& par_scan_state = _state_set->thread_state(i); | 604 ParScanThreadState& par_scan_state = _state_set->thread_state(i); |
605 assert(_state_set->is_valid(i), "Should not have been called"); | |
606 | |
584 par_scan_state.set_young_old_boundary(_young_old_boundary); | 607 par_scan_state.set_young_old_boundary(_young_old_boundary); |
585 | 608 |
586 par_scan_state.start_strong_roots(); | 609 par_scan_state.start_strong_roots(); |
587 gch->gen_process_strong_roots(_gen->level(), | 610 gch->gen_process_strong_roots(_gen->level(), |
588 true, // Process younger gens, if any, | 611 true, // Process younger gens, if any, |
731 HeapWord* young_old_boundary, | 754 HeapWord* young_old_boundary, |
732 ParScanThreadStateSet& state_set); | 755 ParScanThreadStateSet& state_set); |
733 | 756 |
734 private: | 757 private: |
735 virtual void work(int i); | 758 virtual void work(int i); |
736 | 759 virtual void set_for_termination(int active_workers) { |
760 _state_set.terminator()->reset_for_reuse(active_workers); | |
761 } | |
737 private: | 762 private: |
738 ParNewGeneration& _gen; | 763 ParNewGeneration& _gen; |
739 ProcessTask& _task; | 764 ProcessTask& _task; |
740 Generation& _next_gen; | 765 Generation& _next_gen; |
741 HeapWord* _young_old_boundary; | 766 HeapWord* _young_old_boundary; |
787 void ParNewRefProcTaskExecutor::execute(ProcessTask& task) | 812 void ParNewRefProcTaskExecutor::execute(ProcessTask& task) |
788 { | 813 { |
789 GenCollectedHeap* gch = GenCollectedHeap::heap(); | 814 GenCollectedHeap* gch = GenCollectedHeap::heap(); |
790 assert(gch->kind() == CollectedHeap::GenCollectedHeap, | 815 assert(gch->kind() == CollectedHeap::GenCollectedHeap, |
791 "not a generational heap"); | 816 "not a generational heap"); |
792 WorkGang* workers = gch->workers(); | 817 FlexibleWorkGang* workers = gch->workers(); |
793 assert(workers != NULL, "Need parallel worker threads."); | 818 assert(workers != NULL, "Need parallel worker threads."); |
819 _state_set.reset(workers->active_workers(), _generation.promotion_failed()); | |
794 ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(), | 820 ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(), |
795 _generation.reserved().end(), _state_set); | 821 _generation.reserved().end(), _state_set); |
796 workers->run_task(&rp_task); | 822 workers->run_task(&rp_task); |
797 _state_set.reset(_generation.promotion_failed()); | 823 _state_set.reset(0 /* bad value in debug if not reset */, |
824 _generation.promotion_failed()); | |
798 } | 825 } |
799 | 826 |
800 void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) | 827 void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) |
801 { | 828 { |
802 GenCollectedHeap* gch = GenCollectedHeap::heap(); | 829 GenCollectedHeap* gch = GenCollectedHeap::heap(); |
803 WorkGang* workers = gch->workers(); | 830 FlexibleWorkGang* workers = gch->workers(); |
804 assert(workers != NULL, "Need parallel worker threads."); | 831 assert(workers != NULL, "Need parallel worker threads."); |
805 ParNewRefEnqueueTaskProxy enq_task(task); | 832 ParNewRefEnqueueTaskProxy enq_task(task); |
806 workers->run_task(&enq_task); | 833 workers->run_task(&enq_task); |
807 } | 834 } |
808 | 835 |
854 assert(full || size > 0, "otherwise we don't want to collect"); | 881 assert(full || size > 0, "otherwise we don't want to collect"); |
855 GenCollectedHeap* gch = GenCollectedHeap::heap(); | 882 GenCollectedHeap* gch = GenCollectedHeap::heap(); |
856 assert(gch->kind() == CollectedHeap::GenCollectedHeap, | 883 assert(gch->kind() == CollectedHeap::GenCollectedHeap, |
857 "not a CMS generational heap"); | 884 "not a CMS generational heap"); |
858 AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy(); | 885 AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy(); |
859 WorkGang* workers = gch->workers(); | 886 FlexibleWorkGang* workers = gch->workers(); |
887 assert(workers != NULL, "Need workgang for parallel work"); | |
888 int active_workers = | |
889 AdaptiveSizePolicy::calc_active_workers(workers->total_workers(), | |
890 workers->active_workers(), | |
891 Threads::number_of_non_daemon_threads()); | |
892 workers->set_active_workers(active_workers); | |
860 _next_gen = gch->next_gen(this); | 893 _next_gen = gch->next_gen(this); |
861 assert(_next_gen != NULL, | 894 assert(_next_gen != NULL, |
862 "This must be the youngest gen, and not the only gen"); | 895 "This must be the youngest gen, and not the only gen"); |
863 assert(gch->n_gens() == 2, | 896 assert(gch->n_gens() == 2, |
864 "Par collection currently only works with single older gen."); | 897 "Par collection currently only works with single older gen."); |
892 age_table()->clear(); | 925 age_table()->clear(); |
893 to()->clear(SpaceDecorator::Mangle); | 926 to()->clear(SpaceDecorator::Mangle); |
894 | 927 |
895 gch->save_marks(); | 928 gch->save_marks(); |
896 assert(workers != NULL, "Need parallel worker threads."); | 929 assert(workers != NULL, "Need parallel worker threads."); |
897 ParallelTaskTerminator _term(workers->total_workers(), task_queues()); | 930 int n_workers = active_workers; |
898 ParScanThreadStateSet thread_state_set(workers->total_workers(), | 931 |
932 // Set the correct parallelism (number of queues) in the reference processor | |
933 ref_processor()->set_active_mt_degree(n_workers); | |
934 | |
935 // Always set the terminator for the active number of workers | |
936 // because only those workers go through the termination protocol. | |
937 ParallelTaskTerminator _term(n_workers, task_queues()); | |
938 ParScanThreadStateSet thread_state_set(workers->active_workers(), | |
899 *to(), *this, *_next_gen, *task_queues(), | 939 *to(), *this, *_next_gen, *task_queues(), |
900 _overflow_stacks, desired_plab_sz(), _term); | 940 _overflow_stacks, desired_plab_sz(), _term); |
901 | 941 |
902 ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); | 942 ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); |
903 int n_workers = workers->total_workers(); | |
904 gch->set_par_threads(n_workers); | 943 gch->set_par_threads(n_workers); |
905 gch->rem_set()->prepare_for_younger_refs_iterate(true); | 944 gch->rem_set()->prepare_for_younger_refs_iterate(true); |
906 // It turns out that even when we're using 1 thread, doing the work in a | 945 // It turns out that even when we're using 1 thread, doing the work in a |
907 // separate thread causes wide variance in run times. We can't help this | 946 // separate thread causes wide variance in run times. We can't help this |
908 // in the multi-threaded case, but we special-case n=1 here to get | 947 // in the multi-threaded case, but we special-case n=1 here to get |
912 workers->run_task(&tsk); | 951 workers->run_task(&tsk); |
913 } else { | 952 } else { |
914 GenCollectedHeap::StrongRootsScope srs(gch); | 953 GenCollectedHeap::StrongRootsScope srs(gch); |
915 tsk.work(0); | 954 tsk.work(0); |
916 } | 955 } |
917 thread_state_set.reset(promotion_failed()); | 956 thread_state_set.reset(0 /* Bad value in debug if not reset */, |
957 promotion_failed()); | |
918 | 958 |
919 // Process (weak) reference objects found during scavenge. | 959 // Process (weak) reference objects found during scavenge. |
920 ReferenceProcessor* rp = ref_processor(); | 960 ReferenceProcessor* rp = ref_processor(); |
921 IsAliveClosure is_alive(this); | 961 IsAliveClosure is_alive(this); |
922 ScanWeakRefClosure scan_weak_ref(this); | 962 ScanWeakRefClosure scan_weak_ref(this); |
925 ScanClosureWithParBarrier scan_with_gc_barrier(this, true); | 965 ScanClosureWithParBarrier scan_with_gc_barrier(this, true); |
926 set_promo_failure_scan_stack_closure(&scan_without_gc_barrier); | 966 set_promo_failure_scan_stack_closure(&scan_without_gc_barrier); |
927 EvacuateFollowersClosureGeneral evacuate_followers(gch, _level, | 967 EvacuateFollowersClosureGeneral evacuate_followers(gch, _level, |
928 &scan_without_gc_barrier, &scan_with_gc_barrier); | 968 &scan_without_gc_barrier, &scan_with_gc_barrier); |
929 rp->setup_policy(clear_all_soft_refs); | 969 rp->setup_policy(clear_all_soft_refs); |
970 // Can the mt_degree be set later (at run_task() time would be best)? | |
971 rp->set_active_mt_degree(active_workers); | |
930 if (rp->processing_is_mt()) { | 972 if (rp->processing_is_mt()) { |
931 ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); | 973 ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); |
932 rp->process_discovered_references(&is_alive, &keep_alive, | 974 rp->process_discovered_references(&is_alive, &keep_alive, |
933 &evacuate_followers, &task_executor); | 975 &evacuate_followers, &task_executor); |
934 } else { | 976 } else { |