OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/heap/incremental-marking.h" | 5 #include "src/heap/incremental-marking.h" |
6 | 6 |
7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
8 #include "src/compilation-cache.h" | 8 #include "src/compilation-cache.h" |
9 #include "src/conversions.h" | 9 #include "src/conversions.h" |
10 #include "src/heap/gc-idle-time-handler.h" | 10 #include "src/heap/gc-idle-time-handler.h" |
11 #include "src/heap/gc-tracer.h" | 11 #include "src/heap/gc-tracer.h" |
12 #include "src/heap/mark-compact-inl.h" | 12 #include "src/heap/mark-compact-inl.h" |
13 #include "src/heap/object-stats.h" | 13 #include "src/heap/object-stats.h" |
14 #include "src/heap/objects-visiting-inl.h" | 14 #include "src/heap/objects-visiting-inl.h" |
15 #include "src/heap/objects-visiting.h" | 15 #include "src/heap/objects-visiting.h" |
16 #include "src/tracing/trace-event.h" | 16 #include "src/tracing/trace-event.h" |
17 #include "src/v8.h" | 17 #include "src/v8.h" |
18 | 18 |
19 namespace v8 { | 19 namespace v8 { |
20 namespace internal { | 20 namespace internal { |
21 | 21 |
22 IncrementalMarking::IncrementalMarking(Heap* heap) | 22 IncrementalMarking::IncrementalMarking(Heap* heap) |
23 : heap_(heap), | 23 : heap_(heap), |
24 observer_(*this, kAllocatedThreshold), | |
25 state_(STOPPED), | 24 state_(STOPPED), |
| 25 initial_old_generation_size_(0), |
| 26 bytes_marked_ahead_of_schedule_(0), |
| 27 unscanned_bytes_of_large_object_(0), |
| 28 idle_marking_delay_counter_(0), |
| 29 incremental_marking_finalization_rounds_(0), |
26 is_compacting_(false), | 30 is_compacting_(false), |
27 steps_count_(0), | |
28 old_generation_space_available_at_start_of_incremental_(0), | |
29 old_generation_space_used_at_start_of_incremental_(0), | |
30 bytes_rescanned_(0), | |
31 should_hurry_(false), | 31 should_hurry_(false), |
32 marking_speed_(0), | |
33 bytes_scanned_(0), | |
34 allocated_(0), | |
35 write_barriers_invoked_since_last_step_(0), | |
36 bytes_marked_ahead_of_schedule_(0), | |
37 idle_marking_delay_counter_(0), | |
38 unscanned_bytes_of_large_object_(0), | |
39 was_activated_(false), | 32 was_activated_(false), |
40 black_allocation_(false), | 33 black_allocation_(false), |
41 finalize_marking_completed_(false), | 34 finalize_marking_completed_(false), |
42 incremental_marking_finalization_rounds_(0), | 35 request_type_(NONE), |
43 request_type_(NONE) {} | 36 new_generation_observer_(*this, kAllocatedThreshold), |
| 37 old_generation_observer_(*this, kAllocatedThreshold) {} |
44 | 38 |
45 bool IncrementalMarking::BaseRecordWrite(HeapObject* obj, Object* value) { | 39 bool IncrementalMarking::BaseRecordWrite(HeapObject* obj, Object* value) { |
46 HeapObject* value_heap_obj = HeapObject::cast(value); | 40 HeapObject* value_heap_obj = HeapObject::cast(value); |
47 MarkBit value_bit = ObjectMarking::MarkBitFrom(value_heap_obj); | 41 MarkBit value_bit = ObjectMarking::MarkBitFrom(value_heap_obj); |
48 DCHECK(!Marking::IsImpossible(value_bit)); | 42 DCHECK(!Marking::IsImpossible(value_bit)); |
49 | 43 |
50 MarkBit obj_bit = ObjectMarking::MarkBitFrom(obj); | 44 MarkBit obj_bit = ObjectMarking::MarkBitFrom(obj); |
51 DCHECK(!Marking::IsImpossible(obj_bit)); | 45 DCHECK(!Marking::IsImpossible(obj_bit)); |
52 bool is_black = Marking::IsBlack(obj_bit); | 46 bool is_black = Marking::IsBlack(obj_bit); |
53 | 47 |
(...skipping 10 matching lines...) Expand all Loading... |
64 if (BaseRecordWrite(obj, value) && slot != NULL) { | 58 if (BaseRecordWrite(obj, value) && slot != NULL) { |
65 // Object is not going to be rescanned we need to record the slot. | 59 // Object is not going to be rescanned we need to record the slot. |
66 heap_->mark_compact_collector()->RecordSlot(obj, slot, value); | 60 heap_->mark_compact_collector()->RecordSlot(obj, slot, value); |
67 } | 61 } |
68 } | 62 } |
69 | 63 |
70 | 64 |
71 void IncrementalMarking::RecordWriteFromCode(HeapObject* obj, Object** slot, | 65 void IncrementalMarking::RecordWriteFromCode(HeapObject* obj, Object** slot, |
72 Isolate* isolate) { | 66 Isolate* isolate) { |
73 DCHECK(obj->IsHeapObject()); | 67 DCHECK(obj->IsHeapObject()); |
74 IncrementalMarking* marking = isolate->heap()->incremental_marking(); | 68 isolate->heap()->incremental_marking()->RecordWrite(obj, slot, *slot); |
75 | |
76 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); | |
77 int counter = chunk->write_barrier_counter(); | |
78 if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) { | |
79 marking->write_barriers_invoked_since_last_step_ += | |
80 MemoryChunk::kWriteBarrierCounterGranularity - | |
81 chunk->write_barrier_counter(); | |
82 chunk->set_write_barrier_counter( | |
83 MemoryChunk::kWriteBarrierCounterGranularity); | |
84 } | |
85 | |
86 marking->RecordWrite(obj, slot, *slot); | |
87 } | 69 } |
88 | 70 |
89 // static | 71 // static |
90 void IncrementalMarking::RecordWriteOfCodeEntryFromCode(JSFunction* host, | 72 void IncrementalMarking::RecordWriteOfCodeEntryFromCode(JSFunction* host, |
91 Object** slot, | 73 Object** slot, |
92 Isolate* isolate) { | 74 Isolate* isolate) { |
93 DCHECK(host->IsJSFunction()); | 75 DCHECK(host->IsJSFunction()); |
94 IncrementalMarking* marking = isolate->heap()->incremental_marking(); | 76 IncrementalMarking* marking = isolate->heap()->incremental_marking(); |
95 Code* value = Code::cast( | 77 Code* value = Code::cast( |
96 Code::GetObjectFromEntryAddress(reinterpret_cast<Address>(slot))); | 78 Code::GetObjectFromEntryAddress(reinterpret_cast<Address>(slot))); |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 // we don't need to do anything if incremental marking is | 437 // we don't need to do anything if incremental marking is |
456 // not active. | 438 // not active. |
457 } else if (IsCompacting()) { | 439 } else if (IsCompacting()) { |
458 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL_COMPACTION); | 440 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL_COMPACTION); |
459 } else { | 441 } else { |
460 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL); | 442 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL); |
461 } | 443 } |
462 } | 444 } |
463 | 445 |
464 | 446 |
465 void IncrementalMarking::NotifyOfHighPromotionRate() { | |
466 if (IsMarking()) { | |
467 if (marking_speed_ < kFastMarking) { | |
468 if (FLAG_trace_gc) { | |
469 heap()->isolate()->PrintWithTimestamp( | |
470 "Increasing marking speed to %d " | |
471 "due to high promotion rate\n", | |
472 static_cast<int>(kFastMarking)); | |
473 } | |
474 marking_speed_ = kFastMarking; | |
475 } | |
476 } | |
477 } | |
478 | |
479 | |
480 static void PatchIncrementalMarkingRecordWriteStubs( | 447 static void PatchIncrementalMarkingRecordWriteStubs( |
481 Heap* heap, RecordWriteStub::Mode mode) { | 448 Heap* heap, RecordWriteStub::Mode mode) { |
482 UnseededNumberDictionary* stubs = heap->code_stubs(); | 449 UnseededNumberDictionary* stubs = heap->code_stubs(); |
483 | 450 |
484 int capacity = stubs->Capacity(); | 451 int capacity = stubs->Capacity(); |
485 Isolate* isolate = heap->isolate(); | 452 Isolate* isolate = heap->isolate(); |
486 for (int i = 0; i < capacity; i++) { | 453 for (int i = 0; i < capacity; i++) { |
487 Object* k = stubs->KeyAt(i); | 454 Object* k = stubs->KeyAt(i); |
488 if (stubs->IsKey(isolate, k)) { | 455 if (stubs->IsKey(isolate, k)) { |
489 uint32_t key = NumberToUint32(k); | 456 uint32_t key = NumberToUint32(k); |
(...skipping 26 matching lines...) Expand all Loading... |
516 DCHECK(heap_->gc_state() == Heap::NOT_IN_GC); | 483 DCHECK(heap_->gc_state() == Heap::NOT_IN_GC); |
517 DCHECK(!heap_->isolate()->serializer_enabled()); | 484 DCHECK(!heap_->isolate()->serializer_enabled()); |
518 | 485 |
519 Counters* counters = heap_->isolate()->counters(); | 486 Counters* counters = heap_->isolate()->counters(); |
520 | 487 |
521 counters->incremental_marking_reason()->AddSample( | 488 counters->incremental_marking_reason()->AddSample( |
522 static_cast<int>(gc_reason)); | 489 static_cast<int>(gc_reason)); |
523 HistogramTimerScope incremental_marking_scope( | 490 HistogramTimerScope incremental_marking_scope( |
524 counters->gc_incremental_marking_start()); | 491 counters->gc_incremental_marking_start()); |
525 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingStart"); | 492 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingStart"); |
526 ResetStepCounters(); | |
527 heap_->tracer()->NotifyIncrementalMarkingStart(); | 493 heap_->tracer()->NotifyIncrementalMarkingStart(); |
528 | 494 |
| 495 start_time_ms_ = heap()->MonotonicallyIncreasingTimeInMs(); |
| 496 initial_old_generation_size_ = heap_->PromotedSpaceSizeOfObjects(); |
| 497 old_generation_allocation_counter_ = heap_->OldGenerationAllocationCounter(); |
| 498 bytes_allocated_ = 0; |
| 499 bytes_marked_ahead_of_schedule_ = 0; |
| 500 should_hurry_ = false; |
529 was_activated_ = true; | 501 was_activated_ = true; |
530 | 502 |
531 if (!heap_->mark_compact_collector()->sweeping_in_progress()) { | 503 if (!heap_->mark_compact_collector()->sweeping_in_progress()) { |
532 StartMarking(); | 504 StartMarking(); |
533 } else { | 505 } else { |
534 if (FLAG_trace_incremental_marking) { | 506 if (FLAG_trace_incremental_marking) { |
535 heap()->isolate()->PrintWithTimestamp( | 507 heap()->isolate()->PrintWithTimestamp( |
536 "[IncrementalMarking] Start sweeping.\n"); | 508 "[IncrementalMarking] Start sweeping.\n"); |
537 } | 509 } |
538 state_ = SWEEPING; | 510 state_ = SWEEPING; |
539 } | 511 } |
540 | 512 |
541 heap_->new_space()->AddAllocationObserver(&observer_); | 513 SpaceIterator it(heap_); |
| 514 while (it.has_next()) { |
| 515 Space* space = it.next(); |
| 516 if (space == heap_->new_space()) { |
| 517 space->AddAllocationObserver(&new_generation_observer_); |
| 518 } else { |
| 519 space->AddAllocationObserver(&old_generation_observer_); |
| 520 } |
| 521 } |
542 | 522 |
543 incremental_marking_job()->Start(heap_); | 523 incremental_marking_job()->Start(heap_); |
544 } | 524 } |
545 | 525 |
546 | 526 |
547 void IncrementalMarking::StartMarking() { | 527 void IncrementalMarking::StartMarking() { |
548 if (heap_->isolate()->serializer_enabled()) { | 528 if (heap_->isolate()->serializer_enabled()) { |
549 // Black allocation currently starts when we start incremental marking, | 529 // Black allocation currently starts when we start incremental marking, |
550 // but we cannot enable black allocation while deserializing. Hence, we | 530 // but we cannot enable black allocation while deserializing. Hence, we |
551 // have to delay the start of incremental marking in that case. | 531 // have to delay the start of incremental marking in that case. |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
995 static_cast<int>(heap()->PromotedSpaceSizeOfObjects() / MB); | 975 static_cast<int>(heap()->PromotedSpaceSizeOfObjects() / MB); |
996 int old_generation_limit_mb = | 976 int old_generation_limit_mb = |
997 static_cast<int>(heap()->old_generation_allocation_limit() / MB); | 977 static_cast<int>(heap()->old_generation_allocation_limit() / MB); |
998 heap()->isolate()->PrintWithTimestamp( | 978 heap()->isolate()->PrintWithTimestamp( |
999 "[IncrementalMarking] Stopping: old generation %dMB, limit %dMB, " | 979 "[IncrementalMarking] Stopping: old generation %dMB, limit %dMB, " |
1000 "overshoot %dMB\n", | 980 "overshoot %dMB\n", |
1001 old_generation_size_mb, old_generation_limit_mb, | 981 old_generation_size_mb, old_generation_limit_mb, |
1002 Max(0, old_generation_size_mb - old_generation_limit_mb)); | 982 Max(0, old_generation_size_mb - old_generation_limit_mb)); |
1003 } | 983 } |
1004 | 984 |
1005 heap_->new_space()->RemoveAllocationObserver(&observer_); | 985 SpaceIterator it(heap_); |
| 986 while (it.has_next()) { |
| 987 Space* space = it.next(); |
| 988 if (space == heap_->new_space()) { |
| 989 space->RemoveAllocationObserver(&new_generation_observer_); |
| 990 } else { |
| 991 space->RemoveAllocationObserver(&old_generation_observer_); |
| 992 } |
| 993 } |
| 994 |
1006 IncrementalMarking::set_should_hurry(false); | 995 IncrementalMarking::set_should_hurry(false); |
1007 ResetStepCounters(); | |
1008 if (IsMarking()) { | 996 if (IsMarking()) { |
1009 PatchIncrementalMarkingRecordWriteStubs(heap_, | 997 PatchIncrementalMarkingRecordWriteStubs(heap_, |
1010 RecordWriteStub::STORE_BUFFER_ONLY); | 998 RecordWriteStub::STORE_BUFFER_ONLY); |
1011 DeactivateIncrementalWriteBarrier(); | 999 DeactivateIncrementalWriteBarrier(); |
1012 } | 1000 } |
1013 heap_->isolate()->stack_guard()->ClearGC(); | 1001 heap_->isolate()->stack_guard()->ClearGC(); |
1014 state_ = STOPPED; | 1002 state_ = STOPPED; |
1015 is_compacting_ = false; | 1003 is_compacting_ = false; |
1016 FinishBlackAllocation(); | 1004 FinishBlackAllocation(); |
1017 } | 1005 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1075 do { | 1063 do { |
1076 Step(step_size_in_bytes, completion_action, force_completion, step_origin); | 1064 Step(step_size_in_bytes, completion_action, force_completion, step_origin); |
1077 remaining_time_in_ms = | 1065 remaining_time_in_ms = |
1078 deadline_in_ms - heap()->MonotonicallyIncreasingTimeInMs(); | 1066 deadline_in_ms - heap()->MonotonicallyIncreasingTimeInMs(); |
1079 } while (remaining_time_in_ms >= kStepSizeInMs && !IsComplete() && | 1067 } while (remaining_time_in_ms >= kStepSizeInMs && !IsComplete() && |
1080 !heap()->mark_compact_collector()->marking_deque()->IsEmpty()); | 1068 !heap()->mark_compact_collector()->marking_deque()->IsEmpty()); |
1081 return remaining_time_in_ms; | 1069 return remaining_time_in_ms; |
1082 } | 1070 } |
1083 | 1071 |
1084 | 1072 |
1085 void IncrementalMarking::SpeedUp() { | |
1086 bool speed_up = false; | |
1087 | |
1088 if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) { | |
1089 if (FLAG_trace_incremental_marking) { | |
1090 heap()->isolate()->PrintWithTimestamp( | |
1091 "[IncrementalMarking] Speed up marking after %d steps\n", | |
1092 static_cast<int>(kMarkingSpeedAccellerationInterval)); | |
1093 } | |
1094 speed_up = true; | |
1095 } | |
1096 | |
1097 bool space_left_is_very_small = | |
1098 (old_generation_space_available_at_start_of_incremental_ < 10 * MB); | |
1099 | |
1100 bool only_1_nth_of_space_that_was_available_still_left = | |
1101 (SpaceLeftInOldSpace() * (marking_speed_ + 1) < | |
1102 old_generation_space_available_at_start_of_incremental_); | |
1103 | |
1104 if (space_left_is_very_small || | |
1105 only_1_nth_of_space_that_was_available_still_left) { | |
1106 if (FLAG_trace_incremental_marking) | |
1107 heap()->isolate()->PrintWithTimestamp( | |
1108 "[IncrementalMarking] Speed up marking because of low space left\n"); | |
1109 speed_up = true; | |
1110 } | |
1111 | |
1112 bool size_of_old_space_multiplied_by_n_during_marking = | |
1113 (heap_->PromotedTotalSize() > | |
1114 (marking_speed_ + 1) * | |
1115 old_generation_space_used_at_start_of_incremental_); | |
1116 if (size_of_old_space_multiplied_by_n_during_marking) { | |
1117 speed_up = true; | |
1118 if (FLAG_trace_incremental_marking) { | |
1119 heap()->isolate()->PrintWithTimestamp( | |
1120 "[IncrementalMarking] Speed up marking because of heap size " | |
1121 "increase\n"); | |
1122 } | |
1123 } | |
1124 | |
1125 int64_t promoted_during_marking = | |
1126 heap_->PromotedTotalSize() - | |
1127 old_generation_space_used_at_start_of_incremental_; | |
1128 intptr_t delay = marking_speed_ * MB; | |
1129 intptr_t scavenge_slack = heap_->MaxSemiSpaceSize(); | |
1130 | |
1131 // We try to scan at at least twice the speed that we are allocating. | |
1132 if (promoted_during_marking > bytes_scanned_ / 2 + scavenge_slack + delay) { | |
1133 if (FLAG_trace_incremental_marking) { | |
1134 heap()->isolate()->PrintWithTimestamp( | |
1135 "[IncrementalMarking] Speed up marking because marker was not " | |
1136 "keeping up\n"); | |
1137 } | |
1138 speed_up = true; | |
1139 } | |
1140 | |
1141 if (speed_up) { | |
1142 if (state_ != MARKING) { | |
1143 if (FLAG_trace_incremental_marking) { | |
1144 heap()->isolate()->PrintWithTimestamp( | |
1145 "[IncrementalMarking] Postponing speeding up marking until marking " | |
1146 "starts\n"); | |
1147 } | |
1148 } else { | |
1149 marking_speed_ += kMarkingSpeedAccelleration; | |
1150 marking_speed_ = static_cast<int>( | |
1151 Min(kMaxMarkingSpeed, static_cast<intptr_t>(marking_speed_ * 1.3))); | |
1152 if (FLAG_trace_incremental_marking) { | |
1153 heap()->isolate()->PrintWithTimestamp( | |
1154 "[IncrementalMarking] Marking speed increased to %d\n", | |
1155 marking_speed_); | |
1156 } | |
1157 } | |
1158 } | |
1159 } | |
1160 | |
1161 void IncrementalMarking::FinalizeSweeping() { | 1073 void IncrementalMarking::FinalizeSweeping() { |
1162 DCHECK(state_ == SWEEPING); | 1074 DCHECK(state_ == SWEEPING); |
1163 if (heap_->mark_compact_collector()->sweeping_in_progress() && | 1075 if (heap_->mark_compact_collector()->sweeping_in_progress() && |
1164 (!FLAG_concurrent_sweeping || | 1076 (!FLAG_concurrent_sweeping || |
1165 heap_->mark_compact_collector()->sweeper().IsSweepingCompleted())) { | 1077 heap_->mark_compact_collector()->sweeper().IsSweepingCompleted())) { |
1166 heap_->mark_compact_collector()->EnsureSweepingCompleted(); | 1078 heap_->mark_compact_collector()->EnsureSweepingCompleted(); |
1167 } | 1079 } |
1168 if (!heap_->mark_compact_collector()->sweeping_in_progress()) { | 1080 if (!heap_->mark_compact_collector()->sweeping_in_progress()) { |
1169 bytes_scanned_ = 0; | |
1170 StartMarking(); | 1081 StartMarking(); |
1171 } | 1082 } |
1172 } | 1083 } |
1173 | 1084 |
1174 void IncrementalMarking::NotifyAllocatedBytes(intptr_t allocated_bytes) { | 1085 size_t IncrementalMarking::StepSizeToKeepUpWithAllocations() { |
| 1086 // Update bytes_allocated_ based on the allocation counter. |
| 1087 size_t current_counter = heap_->OldGenerationAllocationCounter(); |
| 1088 bytes_allocated_ += current_counter - old_generation_allocation_counter_; |
| 1089 old_generation_allocation_counter_ = current_counter; |
| 1090 return bytes_allocated_; |
| 1091 } |
| 1092 |
| 1093 size_t IncrementalMarking::StepSizeToMakeProgress() { |
| 1094 // We increase step size gradually based on the time passed in order to |
| 1095 // leave marking work to standalone tasks. The ramp up duration and the |
| 1096 // target step count are chosen based on benchmarks. |
| 1097 const int kRampUpIntervalMs = 300; |
| 1098 const size_t kTargetStepCount = 128; |
| 1099 size_t step_size = Max(initial_old_generation_size_ / kTargetStepCount, |
| 1100 IncrementalMarking::kAllocatedThreshold); |
| 1101 double time_passed_ms = |
| 1102 heap_->MonotonicallyIncreasingTimeInMs() - start_time_ms_; |
| 1103 double factor = Min(time_passed_ms / kRampUpIntervalMs, 1.0); |
| 1104 return static_cast<size_t>(factor * step_size); |
| 1105 } |
| 1106 |
| 1107 void IncrementalMarking::AdvanceIncrementalMarkingOnAllocation() { |
1175 if (heap_->gc_state() != Heap::NOT_IN_GC || !FLAG_incremental_marking || | 1108 if (heap_->gc_state() != Heap::NOT_IN_GC || !FLAG_incremental_marking || |
1176 (state_ != SWEEPING && state_ != MARKING)) { | 1109 (state_ != SWEEPING && state_ != MARKING)) { |
1177 return; | 1110 return; |
1178 } | 1111 } |
1179 | 1112 |
1180 allocated_ += allocated_bytes; | 1113 size_t bytes_to_process = |
| 1114 StepSizeToKeepUpWithAllocations() + StepSizeToMakeProgress(); |
1181 | 1115 |
1182 if (allocated_ >= kAllocatedThreshold || | 1116 if (bytes_to_process >= IncrementalMarking::kAllocatedThreshold) { |
1183 write_barriers_invoked_since_last_step_ >= | 1117 // The first step after Scavenge will see many allocated bytes. |
1184 kWriteBarriersInvokedThreshold) { | 1118 // Cap the step size to distribute the marking work more uniformly. |
1185 // The marking speed is driven either by the allocation rate or by the rate | 1119 size_t max_step_size = GCIdleTimeHandler::EstimateMarkingStepSize( |
1186 // at which we are having to check the color of objects in the write | 1120 kMaxStepSizeInMs, |
1187 // barrier. | 1121 heap()->tracer()->IncrementalMarkingSpeedInBytesPerMillisecond()); |
1188 // It is possible for a tight non-allocating loop to run a lot of write | 1122 bytes_to_process = Min(bytes_to_process, max_step_size); |
1189 // barriers before we get here and check them (marking can only take place | 1123 |
1190 // on | 1124 intptr_t bytes_processed = 0; |
1191 // allocation), so to reduce the lumpiness we don't use the write barriers | 1125 if (bytes_marked_ahead_of_schedule_ >= bytes_to_process) { |
1192 // invoked since last step directly to determine the amount of work to do. | 1126 // Steps performed in tasks have put us ahead of schedule. |
1193 intptr_t bytes_to_process = | 1127 // We skip processing of marking dequeue here and thus |
1194 marking_speed_ * | 1128 // shift marking time from inside V8 to standalone tasks. |
1195 Max(allocated_, write_barriers_invoked_since_last_step_); | 1129 bytes_marked_ahead_of_schedule_ -= bytes_to_process; |
1196 Step(bytes_to_process, GC_VIA_STACK_GUARD, FORCE_COMPLETION, | 1130 bytes_processed = bytes_to_process; |
1197 StepOrigin::kV8); | 1131 } else { |
| 1132 bytes_processed = Step(bytes_to_process, GC_VIA_STACK_GUARD, |
| 1133 FORCE_COMPLETION, StepOrigin::kV8); |
| 1134 } |
| 1135 bytes_allocated_ -= Min(bytes_allocated_, bytes_to_process); |
1198 } | 1136 } |
1199 } | 1137 } |
1200 | 1138 |
1201 void IncrementalMarking::Step(intptr_t bytes_to_process, | 1139 size_t IncrementalMarking::Step(size_t bytes_to_process, |
1202 CompletionAction action, | 1140 CompletionAction action, |
1203 ForceCompletionAction completion, | 1141 ForceCompletionAction completion, |
1204 StepOrigin step_origin) { | 1142 StepOrigin step_origin) { |
1205 HistogramTimerScope incremental_marking_scope( | 1143 HistogramTimerScope incremental_marking_scope( |
1206 heap_->isolate()->counters()->gc_incremental_marking()); | 1144 heap_->isolate()->counters()->gc_incremental_marking()); |
1207 TRACE_EVENT0("v8", "V8.GCIncrementalMarking"); | 1145 TRACE_EVENT0("v8", "V8.GCIncrementalMarking"); |
1208 TRACE_GC(heap_->tracer(), GCTracer::Scope::MC_INCREMENTAL); | 1146 TRACE_GC(heap_->tracer(), GCTracer::Scope::MC_INCREMENTAL); |
1209 double start = heap_->MonotonicallyIncreasingTimeInMs(); | 1147 double start = heap_->MonotonicallyIncreasingTimeInMs(); |
1210 | 1148 |
1211 bytes_scanned_ += bytes_to_process; | |
1212 | |
1213 allocated_ = 0; | |
1214 write_barriers_invoked_since_last_step_ = 0; | |
1215 | |
1216 if (state_ == SWEEPING) { | 1149 if (state_ == SWEEPING) { |
1217 TRACE_GC(heap_->tracer(), GCTracer::Scope::MC_INCREMENTAL_SWEEPING); | 1150 TRACE_GC(heap_->tracer(), GCTracer::Scope::MC_INCREMENTAL_SWEEPING); |
1218 FinalizeSweeping(); | 1151 FinalizeSweeping(); |
1219 } | 1152 } |
1220 | 1153 |
1221 intptr_t bytes_processed = 0; | 1154 size_t bytes_processed = 0; |
1222 if (state_ == MARKING) { | 1155 if (state_ == MARKING) { |
1223 const bool incremental_wrapper_tracing = | 1156 const bool incremental_wrapper_tracing = |
1224 FLAG_incremental_marking_wrappers && heap_->UsingEmbedderHeapTracer(); | 1157 FLAG_incremental_marking_wrappers && heap_->UsingEmbedderHeapTracer(); |
1225 const bool process_wrappers = | 1158 const bool process_wrappers = |
1226 incremental_wrapper_tracing && | 1159 incremental_wrapper_tracing && |
1227 (heap_->mark_compact_collector() | 1160 (heap_->mark_compact_collector() |
1228 ->RequiresImmediateWrapperProcessing() || | 1161 ->RequiresImmediateWrapperProcessing() || |
1229 heap_->mark_compact_collector()->marking_deque()->IsEmpty()); | 1162 heap_->mark_compact_collector()->marking_deque()->IsEmpty()); |
1230 bool wrapper_work_left = incremental_wrapper_tracing; | 1163 bool wrapper_work_left = incremental_wrapper_tracing; |
1231 if (!process_wrappers) { | 1164 if (!process_wrappers) { |
1232 if (step_origin == StepOrigin::kV8 && | 1165 bytes_processed = ProcessMarkingDeque(bytes_to_process); |
1233 bytes_marked_ahead_of_schedule_ >= bytes_to_process) { | 1166 if (step_origin == StepOrigin::kTask) { |
1234 // Steps performed in tasks have put us ahead of schedule. | 1167 bytes_marked_ahead_of_schedule_ += bytes_processed; |
1235 // We skip processing of marking dequeue here and thus | |
1236 // shift marking time from inside V8 to standalone tasks. | |
1237 bytes_marked_ahead_of_schedule_ -= bytes_to_process; | |
1238 } else { | |
1239 bytes_processed = ProcessMarkingDeque(bytes_to_process); | |
1240 if (step_origin == StepOrigin::kTask) { | |
1241 bytes_marked_ahead_of_schedule_ += bytes_processed; | |
1242 } | |
1243 } | 1168 } |
1244 } else { | 1169 } else { |
1245 const double wrapper_deadline = | 1170 const double wrapper_deadline = |
1246 heap_->MonotonicallyIncreasingTimeInMs() + kStepSizeInMs; | 1171 heap_->MonotonicallyIncreasingTimeInMs() + kStepSizeInMs; |
1247 TRACE_GC(heap()->tracer(), | 1172 TRACE_GC(heap()->tracer(), |
1248 GCTracer::Scope::MC_INCREMENTAL_WRAPPER_TRACING); | 1173 GCTracer::Scope::MC_INCREMENTAL_WRAPPER_TRACING); |
1249 heap_->mark_compact_collector()->RegisterWrappersWithEmbedderHeapTracer(); | 1174 heap_->mark_compact_collector()->RegisterWrappersWithEmbedderHeapTracer(); |
1250 wrapper_work_left = | 1175 wrapper_work_left = |
1251 heap_->mark_compact_collector() | 1176 heap_->mark_compact_collector() |
1252 ->embedder_heap_tracer() | 1177 ->embedder_heap_tracer() |
(...skipping 11 matching lines...) Expand all Loading... |
1264 FinalizeMarking(action); | 1189 FinalizeMarking(action); |
1265 } else { | 1190 } else { |
1266 MarkingComplete(action); | 1191 MarkingComplete(action); |
1267 } | 1192 } |
1268 } else { | 1193 } else { |
1269 IncrementIdleMarkingDelayCounter(); | 1194 IncrementIdleMarkingDelayCounter(); |
1270 } | 1195 } |
1271 } | 1196 } |
1272 } | 1197 } |
1273 | 1198 |
1274 steps_count_++; | |
1275 | |
1276 // Speed up marking if we are marking too slow or if we are almost done | |
1277 // with marking. | |
1278 SpeedUp(); | |
1279 | |
1280 double end = heap_->MonotonicallyIncreasingTimeInMs(); | 1199 double end = heap_->MonotonicallyIncreasingTimeInMs(); |
1281 double duration = (end - start); | 1200 double duration = (end - start); |
1282 // Note that we report zero bytes here when sweeping was in progress or | 1201 // Note that we report zero bytes here when sweeping was in progress or |
1283 // when we just started incremental marking. In these cases we did not | 1202 // when we just started incremental marking. In these cases we did not |
1284 // process the marking deque. | 1203 // process the marking deque. |
1285 heap_->tracer()->AddIncrementalMarkingStep(duration, bytes_processed); | 1204 heap_->tracer()->AddIncrementalMarkingStep(duration, bytes_processed); |
1286 if (FLAG_trace_incremental_marking) { | 1205 if (FLAG_trace_incremental_marking) { |
1287 heap_->isolate()->PrintWithTimestamp( | 1206 heap_->isolate()->PrintWithTimestamp( |
1288 "[IncrementalMarking] Step %s %d bytes (%d) in %.1f\n", | 1207 "[IncrementalMarking] Step %s %zu bytes (%zu) in %.1f\n", |
1289 step_origin == StepOrigin::kV8 ? "in v8" : "in task", | 1208 step_origin == StepOrigin::kV8 ? "in v8" : "in task", bytes_processed, |
1290 static_cast<int>(bytes_processed), static_cast<int>(bytes_to_process), | 1209 bytes_to_process, duration); |
1291 duration); | |
1292 } | 1210 } |
| 1211 return bytes_processed; |
1293 } | 1212 } |
1294 | 1213 |
1295 | 1214 |
1296 void IncrementalMarking::ResetStepCounters() { | |
1297 steps_count_ = 0; | |
1298 old_generation_space_available_at_start_of_incremental_ = | |
1299 SpaceLeftInOldSpace(); | |
1300 old_generation_space_used_at_start_of_incremental_ = | |
1301 heap_->PromotedTotalSize(); | |
1302 bytes_rescanned_ = 0; | |
1303 marking_speed_ = kInitialMarkingSpeed; | |
1304 bytes_scanned_ = 0; | |
1305 write_barriers_invoked_since_last_step_ = 0; | |
1306 bytes_marked_ahead_of_schedule_ = 0; | |
1307 } | |
1308 | |
1309 | |
1310 int64_t IncrementalMarking::SpaceLeftInOldSpace() { | |
1311 return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects(); | |
1312 } | |
1313 | |
1314 | |
1315 bool IncrementalMarking::IsIdleMarkingDelayCounterLimitReached() { | 1215 bool IncrementalMarking::IsIdleMarkingDelayCounterLimitReached() { |
1316 return idle_marking_delay_counter_ > kMaxIdleMarkingDelayCounter; | 1216 return idle_marking_delay_counter_ > kMaxIdleMarkingDelayCounter; |
1317 } | 1217 } |
1318 | 1218 |
1319 | 1219 |
1320 void IncrementalMarking::IncrementIdleMarkingDelayCounter() { | 1220 void IncrementalMarking::IncrementIdleMarkingDelayCounter() { |
1321 idle_marking_delay_counter_++; | 1221 idle_marking_delay_counter_++; |
1322 } | 1222 } |
1323 | 1223 |
1324 | 1224 |
1325 void IncrementalMarking::ClearIdleMarkingDelayCounter() { | 1225 void IncrementalMarking::ClearIdleMarkingDelayCounter() { |
1326 idle_marking_delay_counter_ = 0; | 1226 idle_marking_delay_counter_ = 0; |
1327 } | 1227 } |
1328 | 1228 |
1329 } // namespace internal | 1229 } // namespace internal |
1330 } // namespace v8 | 1230 } // namespace v8 |
OLD | NEW |