Mercurial > hg > graal-compiler
comparison src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @ 1837:c99c53f07c14
6692906: CMS: parallel concurrent marking may be prone to hanging or stalling mutators for periods of time
Summary: Inserted missing yield(check)s in closures used during the work-stealing phase of parallel concurrent marking, a missing synchronous yield-request in the cms perm gen allocation path, and a terminator-terminator for the offer_termination invocation that monitors the yield status of the concurrent marking task. Elaborated some documentation comments and made some task queue termination loop flags configurable at start-up to aid debugging in the field.
Reviewed-by: jmasa, johnc, poonam
author | ysr |
---|---|
date | Wed, 29 Sep 2010 16:17:02 -0700 |
parents | 894b1d7c7e01 |
children | a7214d79fcf1 |
comparison
equal
deleted
inserted
replaced
1836:894b1d7c7e01 | 1837:c99c53f07c14 |
---|---|
3262 | 3262 |
3263 HeapWord* | 3263 HeapWord* |
3264 ConcurrentMarkSweepGeneration::expand_and_allocate(size_t word_size, | 3264 ConcurrentMarkSweepGeneration::expand_and_allocate(size_t word_size, |
3265 bool tlab, | 3265 bool tlab, |
3266 bool parallel) { | 3266 bool parallel) { |
3267 CMSSynchronousYieldRequest yr; | |
3267 assert(!tlab, "Can't deal with TLAB allocation"); | 3268 assert(!tlab, "Can't deal with TLAB allocation"); |
3268 MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag); | 3269 MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag); |
3269 expand(word_size*HeapWordSize, MinHeapDeltaBytes, | 3270 expand(word_size*HeapWordSize, MinHeapDeltaBytes, |
3270 CMSExpansionCause::_satisfy_allocation); | 3271 CMSExpansionCause::_satisfy_allocation); |
3271 if (GCExpandToAllocateDelayMillis > 0) { | 3272 if (GCExpandToAllocateDelayMillis > 0) { |
3708 class CMSConcMarkingTask; | 3709 class CMSConcMarkingTask; |
3709 | 3710 |
3710 class CMSConcMarkingTerminator: public ParallelTaskTerminator { | 3711 class CMSConcMarkingTerminator: public ParallelTaskTerminator { |
3711 CMSCollector* _collector; | 3712 CMSCollector* _collector; |
3712 CMSConcMarkingTask* _task; | 3713 CMSConcMarkingTask* _task; |
3713 bool _yield; | 3714 public: |
3714 protected: | |
3715 virtual void yield(); | 3715 virtual void yield(); |
3716 public: | 3716 |
3717 // "n_threads" is the number of threads to be terminated. | 3717 // "n_threads" is the number of threads to be terminated. |
3718 // "queue_set" is a set of work queues of other threads. | 3718 // "queue_set" is a set of work queues of other threads. |
3719 // "collector" is the CMS collector associated with this task terminator. | 3719 // "collector" is the CMS collector associated with this task terminator. |
3720 // "yield" indicates whether we need the gang as a whole to yield. | 3720 // "yield" indicates whether we need the gang as a whole to yield. |
3721 CMSConcMarkingTerminator(int n_threads, TaskQueueSetSuper* queue_set, | 3721 CMSConcMarkingTerminator(int n_threads, TaskQueueSetSuper* queue_set, CMSCollector* collector) : |
3722 CMSCollector* collector, bool yield) : | |
3723 ParallelTaskTerminator(n_threads, queue_set), | 3722 ParallelTaskTerminator(n_threads, queue_set), |
3724 _collector(collector), | 3723 _collector(collector) { } |
3725 _yield(yield) { } | 3724 |
3726 | 3725 void set_task(CMSConcMarkingTask* task) { |
3726 _task = task; | |
3727 } | |
3728 }; | |
3729 | |
3730 class CMSConcMarkingTerminatorTerminator: public TerminatorTerminator { | |
3731 CMSConcMarkingTask* _task; | |
3732 public: | |
3733 bool should_exit_termination(); | |
3727 void set_task(CMSConcMarkingTask* task) { | 3734 void set_task(CMSConcMarkingTask* task) { |
3728 _task = task; | 3735 _task = task; |
3729 } | 3736 } |
3730 }; | 3737 }; |
3731 | 3738 |
3735 int _n_workers; // requested/desired # workers | 3742 int _n_workers; // requested/desired # workers |
3736 bool _asynch; | 3743 bool _asynch; |
3737 bool _result; | 3744 bool _result; |
3738 CompactibleFreeListSpace* _cms_space; | 3745 CompactibleFreeListSpace* _cms_space; |
3739 CompactibleFreeListSpace* _perm_space; | 3746 CompactibleFreeListSpace* _perm_space; |
3740 HeapWord* _global_finger; | 3747 char _pad_front[64]; // padding to ... |
3748 HeapWord* _global_finger; // ... avoid sharing cache line | |
3749 char _pad_back[64]; | |
3741 HeapWord* _restart_addr; | 3750 HeapWord* _restart_addr; |
3742 | 3751 |
3743 // Exposed here for yielding support | 3752 // Exposed here for yielding support |
3744 Mutex* const _bit_map_lock; | 3753 Mutex* const _bit_map_lock; |
3745 | 3754 |
3746 // The per thread work queues, available here for stealing | 3755 // The per thread work queues, available here for stealing |
3747 OopTaskQueueSet* _task_queues; | 3756 OopTaskQueueSet* _task_queues; |
3757 | |
3758 // Termination (and yielding) support | |
3748 CMSConcMarkingTerminator _term; | 3759 CMSConcMarkingTerminator _term; |
3760 CMSConcMarkingTerminatorTerminator _term_term; | |
3749 | 3761 |
3750 public: | 3762 public: |
3751 CMSConcMarkingTask(CMSCollector* collector, | 3763 CMSConcMarkingTask(CMSCollector* collector, |
3752 CompactibleFreeListSpace* cms_space, | 3764 CompactibleFreeListSpace* cms_space, |
3753 CompactibleFreeListSpace* perm_space, | 3765 CompactibleFreeListSpace* perm_space, |
3758 _collector(collector), | 3770 _collector(collector), |
3759 _cms_space(cms_space), | 3771 _cms_space(cms_space), |
3760 _perm_space(perm_space), | 3772 _perm_space(perm_space), |
3761 _asynch(asynch), _n_workers(0), _result(true), | 3773 _asynch(asynch), _n_workers(0), _result(true), |
3762 _task_queues(task_queues), | 3774 _task_queues(task_queues), |
3763 _term(_n_workers, task_queues, _collector, asynch), | 3775 _term(_n_workers, task_queues, _collector), |
3764 _bit_map_lock(collector->bitMapLock()) | 3776 _bit_map_lock(collector->bitMapLock()) |
3765 { | 3777 { |
3766 _requested_size = _n_workers; | 3778 _requested_size = _n_workers; |
3767 _term.set_task(this); | 3779 _term.set_task(this); |
3780 _term_term.set_task(this); | |
3768 assert(_cms_space->bottom() < _perm_space->bottom(), | 3781 assert(_cms_space->bottom() < _perm_space->bottom(), |
3769 "Finger incorrectly initialized below"); | 3782 "Finger incorrectly initialized below"); |
3770 _restart_addr = _global_finger = _cms_space->bottom(); | 3783 _restart_addr = _global_finger = _cms_space->bottom(); |
3771 } | 3784 } |
3772 | 3785 |
3782 virtual void set_for_termination(int active_workers) { | 3795 virtual void set_for_termination(int active_workers) { |
3783 terminator()->reset_for_reuse(active_workers); | 3796 terminator()->reset_for_reuse(active_workers); |
3784 } | 3797 } |
3785 | 3798 |
3786 void work(int i); | 3799 void work(int i); |
3800 bool should_yield() { | |
3801 return ConcurrentMarkSweepThread::should_yield() | |
3802 && !_collector->foregroundGCIsActive() | |
3803 && _asynch; | |
3804 } | |
3787 | 3805 |
3788 virtual void coordinator_yield(); // stuff done by coordinator | 3806 virtual void coordinator_yield(); // stuff done by coordinator |
3789 bool result() { return _result; } | 3807 bool result() { return _result; } |
3790 | 3808 |
3791 void reset(HeapWord* ra) { | 3809 void reset(HeapWord* ra) { |
3803 void do_scan_and_mark(int i, CompactibleFreeListSpace* sp); | 3821 void do_scan_and_mark(int i, CompactibleFreeListSpace* sp); |
3804 void do_work_steal(int i); | 3822 void do_work_steal(int i); |
3805 void bump_global_finger(HeapWord* f); | 3823 void bump_global_finger(HeapWord* f); |
3806 }; | 3824 }; |
3807 | 3825 |
3826 bool CMSConcMarkingTerminatorTerminator::should_exit_termination() { | |
3827 assert(_task != NULL, "Error"); | |
3828 return _task->yielding(); | |
3829 // Note that we do not need the disjunct || _task->should_yield() above | |
3830 // because we want terminating threads to yield only if the task | |
3831 // is already in the midst of yielding, which happens only after at least one | |
3832 // thread has yielded. | |
3833 } | |
3834 | |
3808 void CMSConcMarkingTerminator::yield() { | 3835 void CMSConcMarkingTerminator::yield() { |
3809 if (ConcurrentMarkSweepThread::should_yield() && | 3836 if (_task->should_yield()) { |
3810 !_collector->foregroundGCIsActive() && | |
3811 _yield) { | |
3812 _task->yield(); | 3837 _task->yield(); |
3813 } else { | 3838 } else { |
3814 ParallelTaskTerminator::yield(); | 3839 ParallelTaskTerminator::yield(); |
3815 } | 3840 } |
3816 } | 3841 } |
4031 pst->all_tasks_completed(); | 4056 pst->all_tasks_completed(); |
4032 } | 4057 } |
4033 | 4058 |
4034 class Par_ConcMarkingClosure: public Par_KlassRememberingOopClosure { | 4059 class Par_ConcMarkingClosure: public Par_KlassRememberingOopClosure { |
4035 private: | 4060 private: |
4061 CMSConcMarkingTask* _task; | |
4036 MemRegion _span; | 4062 MemRegion _span; |
4037 CMSBitMap* _bit_map; | 4063 CMSBitMap* _bit_map; |
4038 CMSMarkStack* _overflow_stack; | 4064 CMSMarkStack* _overflow_stack; |
4039 OopTaskQueue* _work_queue; | 4065 OopTaskQueue* _work_queue; |
4040 protected: | 4066 protected: |
4041 DO_OOP_WORK_DEFN | 4067 DO_OOP_WORK_DEFN |
4042 public: | 4068 public: |
4043 Par_ConcMarkingClosure(CMSCollector* collector, OopTaskQueue* work_queue, | 4069 Par_ConcMarkingClosure(CMSCollector* collector, CMSConcMarkingTask* task, OopTaskQueue* work_queue, |
4044 CMSBitMap* bit_map, CMSMarkStack* overflow_stack, | 4070 CMSBitMap* bit_map, CMSMarkStack* overflow_stack, |
4045 CMSMarkStack* revisit_stack): | 4071 CMSMarkStack* revisit_stack): |
4046 Par_KlassRememberingOopClosure(collector, NULL, revisit_stack), | 4072 Par_KlassRememberingOopClosure(collector, NULL, revisit_stack), |
4047 _span(_collector->_span), | 4073 _task(task), |
4074 _span(collector->_span), | |
4048 _work_queue(work_queue), | 4075 _work_queue(work_queue), |
4049 _bit_map(bit_map), | 4076 _bit_map(bit_map), |
4050 _overflow_stack(overflow_stack) | 4077 _overflow_stack(overflow_stack) |
4051 { } | 4078 { } |
4052 virtual void do_oop(oop* p); | 4079 virtual void do_oop(oop* p); |
4053 virtual void do_oop(narrowOop* p); | 4080 virtual void do_oop(narrowOop* p); |
4054 void trim_queue(size_t max); | 4081 void trim_queue(size_t max); |
4055 void handle_stack_overflow(HeapWord* lost); | 4082 void handle_stack_overflow(HeapWord* lost); |
4083 void do_yield_check() { | |
4084 if (_task->should_yield()) { | |
4085 _task->yield(); | |
4086 } | |
4087 } | |
4056 }; | 4088 }; |
4057 | 4089 |
4058 // Grey object scanning during work stealing phase -- | 4090 // Grey object scanning during work stealing phase -- |
4059 // the salient assumption here is that any references | 4091 // the salient assumption here is that any references |
4060 // that are in these stolen objects being scanned must | 4092 // that are in these stolen objects being scanned must |
4094 _work_queue->size() == _work_queue->max_elems(), | 4126 _work_queue->size() == _work_queue->max_elems(), |
4095 "Else push should have succeeded"); | 4127 "Else push should have succeeded"); |
4096 handle_stack_overflow(addr); | 4128 handle_stack_overflow(addr); |
4097 } | 4129 } |
4098 } // Else, some other thread got there first | 4130 } // Else, some other thread got there first |
4131 do_yield_check(); | |
4099 } | 4132 } |
4100 } | 4133 } |
4101 | 4134 |
4102 void Par_ConcMarkingClosure::do_oop(oop* p) { Par_ConcMarkingClosure::do_oop_work(p); } | 4135 void Par_ConcMarkingClosure::do_oop(oop* p) { Par_ConcMarkingClosure::do_oop_work(p); } |
4103 void Par_ConcMarkingClosure::do_oop(narrowOop* p) { Par_ConcMarkingClosure::do_oop_work(p); } | 4136 void Par_ConcMarkingClosure::do_oop(narrowOop* p) { Par_ConcMarkingClosure::do_oop_work(p); } |
4109 assert(new_oop->is_oop(), "Should be an oop"); | 4142 assert(new_oop->is_oop(), "Should be an oop"); |
4110 assert(_bit_map->isMarked((HeapWord*)new_oop), "Grey object"); | 4143 assert(_bit_map->isMarked((HeapWord*)new_oop), "Grey object"); |
4111 assert(_span.contains((HeapWord*)new_oop), "Not in span"); | 4144 assert(_span.contains((HeapWord*)new_oop), "Not in span"); |
4112 assert(new_oop->is_parsable(), "Should be parsable"); | 4145 assert(new_oop->is_parsable(), "Should be parsable"); |
4113 new_oop->oop_iterate(this); // do_oop() above | 4146 new_oop->oop_iterate(this); // do_oop() above |
4147 do_yield_check(); | |
4114 } | 4148 } |
4115 } | 4149 } |
4116 } | 4150 } |
4117 | 4151 |
4118 // Upon stack overflow, we discard (part of) the stack, | 4152 // Upon stack overflow, we discard (part of) the stack, |
4136 oop obj_to_scan; | 4170 oop obj_to_scan; |
4137 CMSBitMap* bm = &(_collector->_markBitMap); | 4171 CMSBitMap* bm = &(_collector->_markBitMap); |
4138 CMSMarkStack* ovflw = &(_collector->_markStack); | 4172 CMSMarkStack* ovflw = &(_collector->_markStack); |
4139 CMSMarkStack* revisit = &(_collector->_revisitStack); | 4173 CMSMarkStack* revisit = &(_collector->_revisitStack); |
4140 int* seed = _collector->hash_seed(i); | 4174 int* seed = _collector->hash_seed(i); |
4141 Par_ConcMarkingClosure cl(_collector, work_q, bm, ovflw, revisit); | 4175 Par_ConcMarkingClosure cl(_collector, this, work_q, bm, ovflw, revisit); |
4142 while (true) { | 4176 while (true) { |
4143 cl.trim_queue(0); | 4177 cl.trim_queue(0); |
4144 assert(work_q->size() == 0, "Should have been emptied above"); | 4178 assert(work_q->size() == 0, "Should have been emptied above"); |
4145 if (get_work_from_overflow_stack(ovflw, work_q)) { | 4179 if (get_work_from_overflow_stack(ovflw, work_q)) { |
4146 // Can't assert below because the work obtained from the | 4180 // Can't assert below because the work obtained from the |
4149 continue; | 4183 continue; |
4150 } else if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) { | 4184 } else if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) { |
4151 assert(obj_to_scan->is_oop(), "Should be an oop"); | 4185 assert(obj_to_scan->is_oop(), "Should be an oop"); |
4152 assert(bm->isMarked((HeapWord*)obj_to_scan), "Grey object"); | 4186 assert(bm->isMarked((HeapWord*)obj_to_scan), "Grey object"); |
4153 obj_to_scan->oop_iterate(&cl); | 4187 obj_to_scan->oop_iterate(&cl); |
4154 } else if (terminator()->offer_termination()) { | 4188 } else if (terminator()->offer_termination(&_term_term)) { |
4155 assert(work_q->size() == 0, "Impossible!"); | 4189 assert(work_q->size() == 0, "Impossible!"); |
4156 break; | 4190 break; |
4191 } else if (yielding() || should_yield()) { | |
4192 yield(); | |
4157 } | 4193 } |
4158 } | 4194 } |
4159 } | 4195 } |
4160 | 4196 |
4161 // This is run by the CMS (coordinator) thread. | 4197 // This is run by the CMS (coordinator) thread. |