35 size_t holes_size = 0;
38 space = spaces.
Next()) {
39 DCHECK_GE(holes_size + space->Waste() + space->Available(), holes_size);
40 holes_size += space->Waste() + space->Available();
47std::atomic<CollectionEpoch> global_epoch{0};
50 return global_epoch.fetch_add(1, std::memory_order_relaxed) + 1;
55std::optional<double> BoundedAverageSpeed(
56 const base::RingBuffer<BytesAndDuration>& buffer) {
57 constexpr size_t kMinNonEmptySpeedInBytesPerMs = 1;
58 constexpr size_t kMaxSpeedInBytesPerMs =
GB;
59 return ::heap::base::AverageSpeed(buffer, BytesAndDuration(), std::nullopt,
60 kMinNonEmptySpeedInBytesPerMs,
61 kMaxSpeedInBytesPerMs);
64double BoundedThroughput(const ::heap::base::SmoothedBytesAndDuration& buffer) {
65 constexpr double kMaxSpeedInBytesPerMs =
static_cast<double>(
GB);
66 return std::min(buffer.GetThroughput(), kMaxSpeedInBytesPerMs);
73 const char* collector_reason,
78 collector_reason(collector_reason),
84 return (short_name) ?
"s" :
"Scavenge";
87 return (short_name) ?
"mc" :
"Mark-Compact";
90 return (short_name) ?
"mms" :
"Minor Mark-Sweep";
92 return (short_name) ?
"st" :
"Start";
98 if (Heap::IsYoungGenerationCollector(collector)) {
99 type_timer_ =
nullptr;
100 type_priority_timer_ =
nullptr;
102 mode_ = Mode::Scavenger;
103 trace_event_name_ =
"V8.GCScavenger";
106 trace_event_name_ =
"V8.GCMinorMS";
111 const bool in_background =
heap->isolate()->is_backgrounded();
112 const bool is_incremental = !
heap->incremental_marking()->IsStopped();
120 if (is_incremental) {
121 if (
heap->ShouldReduceMemory()) {
122 type_timer_ = counters->gc_finalize_incremental_memory_reducing();
123 type_priority_timer_ =
125 ? counters->gc_finalize_incremental_memory_reducing_background()
127 ->gc_finalize_incremental_memory_reducing_foreground();
128 trace_event_name_ =
"V8.GCFinalizeMCReduceMemory";
130 type_timer_ = counters->gc_finalize_incremental_memory_measure();
131 type_priority_timer_ =
133 ? counters->gc_finalize_incremental_memory_measure_background()
134 : counters->gc_finalize_incremental_memory_measure_foreground();
135 trace_event_name_ =
"V8.GCFinalizeMCMeasureMemory";
137 type_timer_ = counters->gc_finalize_incremental_regular();
138 type_priority_timer_ =
140 ? counters->gc_finalize_incremental_regular_background()
141 : counters->gc_finalize_incremental_regular_foreground();
142 trace_event_name_ =
"V8.GCFinalizeMC";
143 mode_ = Mode::Finalize;
146 trace_event_name_ =
"V8.GCCompactor";
147 if (
heap->ShouldReduceMemory()) {
148 type_timer_ = counters->gc_finalize_non_incremental_memory_reducing();
149 type_priority_timer_ =
152 ->gc_finalize_non_incremental_memory_reducing_background()
154 ->gc_finalize_non_incremental_memory_reducing_foreground();
156 type_timer_ = counters->gc_finalize_non_incremental_memory_measure();
157 type_priority_timer_ =
160 ->gc_finalize_non_incremental_memory_measure_background()
162 ->gc_finalize_non_incremental_memory_measure_foreground();
164 type_timer_ = counters->gc_finalize_non_incremental_regular();
165 type_priority_timer_ =
167 ? counters->gc_finalize_non_incremental_regular_background()
168 : counters->gc_finalize_non_incremental_regular_foreground();
184 parent_track_(
perfetto::ThreadTrack::Current())
192 static_assert(0 == Scope::MC_INCREMENTAL);
207 DCHECK(!IsInObservablePause());
212 const char* collector_reason) {
218 DCHECK(IsInObservablePause());
230 const char* collector_reason,
MarkingType marking) {
248 Heap::IsYoungGenerationCollector(collector));
279 DCHECK(IsInObservablePause());
291 DCHECK(!IsInObservablePause());
295 if (Heap::IsYoungGenerationCollector(collector)) {
316 size_t new_lo_space_size =
340 DCHECK(IsConsistentWithCollector(collector));
341 DCHECK(IsInObservablePause());
353 const bool is_young = Heap::IsYoungGenerationCollector(collector);
357 long_task_stats->gc_young_wall_clock_duration_us +=
377 long_task_stats->gc_full_atomic_wall_clock_duration_us +=
385 if (
v8_flags.trace_gc_ignore_scavenger && is_young)
return;
407 std::stringstream heap_stats;
433 blocked_time_taken + concurrent_gc_time;
439 heap_->
mb_->UpdateGCSpeed(major_gc_bytes, major_gc_duration);
455 event.scopes[GCTracer::Scope::SCAVENGER] +
456 event.scopes[GCTracer::Scope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL] +
458 event.scopes[GCTracer::Scope::MINOR_MS] +
459 event.scopes[GCTracer::Scope::MINOR_MS_BACKGROUND_MARKING];
468 DCHECK(IsConsistentWithCollector(collector));
472 if (Heap::IsYoungGenerationCollector(collector)) {
500 "FreeLists statistics before collection:\n");
531 if (was_young_gc_while_full_gc_) {
551 if (!was_young_gc_while_full_gc || was_full_sweeping_notified)
return;
564 "FreeLists statistics after sweeping completed:\n");
599 const auto* metric_recorder =
601 USE(metric_recorder);
602 DCHECK(metric_recorder->FullGCMetricsReportPending());
620 const auto* metric_recorder =
622 USE(metric_recorder);
623 DCHECK(metric_recorder->YoungGCMetricsReportPending());
635 size_t new_space_counter_bytes,
636 size_t old_generation_counter_bytes,
637 size_t embedder_counter_bytes) {
638 int64_t new_space_allocated_bytes = std::max<int64_t>(
640 int64_t old_generation_allocated_bytes = std::max<int64_t>(
643 int64_t embedder_allocated_bytes = std::max<int64_t>(
653 BytesAndDuration(new_space_allocated_bytes, allocation_duration));
655 BytesAndDuration(old_generation_allocated_bytes, allocation_duration));
657 BytesAndDuration(embedder_allocated_bytes, allocation_duration));
660 heap_->
mb_->UpdateAllocationRate(old_generation_allocated_bytes,
661 allocation_duration);
664#if defined(V8_USE_PERFETTO)
666 perfetto::CounterTrack(
"OldGenerationAllocationThroughput",
671 perfetto::CounterTrack(
"EmbedderAllocationThroughput", parent_track_),
675 perfetto::CounterTrack(
"NewSpaceAllocationThroughput", parent_track_),
699 static constexpr auto kMaxDeltaForSFIAge =
701 SFIAgeType code_flushing_increase_s = 0;
705 if (diff > kMaxDeltaForSFIAge) {
706 code_flushing_increase_s = std::numeric_limits<SFIAgeType>::max();
708 code_flushing_increase_s =
static_cast<SFIAgeType
>(diff.InSeconds());
711 DCHECK_LE(code_flushing_increase_s, std::numeric_limits<SFIAgeType>::max());
714 code_flushing_increase_s > 0) {
728 size_t live_bytes_compacted) {
750void GCTracer::Output(
const char* format, ...)
const {
753 va_start(arguments, format);
754 base::OS::VPrint(format, arguments);
758 const int kBufferSize = 256;
759 char raw_buffer[kBufferSize];
762 va_start(arguments2, format);
771 const size_t kIncrementalStatsSize = 128;
772 char incremental_buffer[kIncrementalStatsSize] = {0};
776 incremental_buffer, kIncrementalStatsSize,
777 " (+ %.1f ms in %d steps since start of marking, "
778 "biggest step %.1f ms, walltime since start of marking %.f ms)",
786 const double total_external_time =
800 "%s%s%s %.1f (%.1f) -> %.1f (%.1f) MB, "
802 "%.2f / %.2f ms%s (average mu = %.3f, current mu = %.3f) %s; %s\n",
825 size_t allocated_since_last_gc =
830 incremental_walltime_duration =
844 "during_sweeping=%d "
845 "time_to_safepoint=%.2f "
846 "heap.prologue=%.2f "
847 "heap.epilogue=%.2f "
848 "heap.external.prologue=%.2f "
849 "heap.external.epilogue=%.2f "
850 "heap.external_weak_global_handles=%.2f "
851 "complete.sweep_array_buffers=%.2f "
853 "scavenge.free_remembered_set=%.2f "
854 "scavenge.roots=%.2f "
855 "scavenge.weak=%.2f "
856 "scavenge.weak_global_handles.identify=%.2f "
857 "scavenge.weak_global_handles.process=%.2f "
858 "scavenge.parallel=%.2f "
859 "scavenge.update_refs=%.2f "
860 "scavenge.pin_objects=%.2f "
861 "scavenge.restore_pinned=%.2f "
862 "scavenge.sweep_array_buffers=%.2f "
863 "scavenge.resize_new_space=%.2f "
864 "background.scavenge.parallel=%.2f "
865 "incremental.steps_count=%d "
866 "incremental.steps_took=%.1f "
867 "scavenge_throughput=%.f "
868 "start_object_size=%zu "
869 "end_object_size=%zu "
870 "start_memory_size=%zu "
871 "end_memory_size=%zu "
872 "start_holes_size=%zu "
873 "end_holes_size=%zu "
876 "quarantined_size=%zu "
877 "quarantined_pages=%zu "
878 "new_space_survived=%zu "
879 "nodes_died_in_new=%d "
880 "nodes_copied_in_new=%d "
882 "promotion_ratio=%.1f%% "
883 "average_survival_ratio=%.1f%% "
884 "promotion_rate=%.1f%% "
885 "new_space_survive_rate_=%.1f%% "
886 "new_space_allocation_throughput=%.1f "
887 "new_space_capacity=%zu "
888 "old_gen_allocation_limit=%zu "
889 "global_allocation_limit=%zu "
890 "allocation_throughput=%.1f "
891 "pool_local_chunks=%zu "
892 "pool_shared_chunks=%zu "
893 "pool_total_chunks=%zu\n",
903 current_scope(Scope::SCAVENGER_COMPLETE_SWEEP_ARRAY_BUFFERS),
908 current_scope(Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_IDENTIFY),
909 current_scope(Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_PROCESS),
914 Scope::SCAVENGER_SCAVENGE_RESTORE_AND_QUARANTINE_PINNED),
917 current_scope(Scope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL),
951 "time_to_safepoint=%.2f "
953 "mark.incremental_seed=%.2f "
954 "mark.finish_incremental=%.2f "
956 "mark.traced_handles=%.2f "
957 "mark.closure_parallel=%.2f "
959 "mark.conservative_stack=%.2f "
961 "clear.string_forwarding_table=%.2f "
962 "clear.string_table=%.2f "
963 "clear.global_handles=%.2f "
964 "complete.sweep_array_buffers=%.2f "
965 "complete.sweeping=%.2f "
969 "sweep.update_string_table=%.2f "
970 "sweep.start_jobs=%.2f "
971 "sweep.array_buffers=%.2f "
973 "finish.ensure_capacity=%.2f "
974 "finish.sweep_array_buffers=%.2f "
975 "background.mark=%.2f "
976 "background.sweep=%.2f "
977 "background.sweep.array_buffers=%.2f "
978 "conservative_stack_scanning=%.2f "
979 "start_object_size=%zu "
980 "end_object_size=%zu "
981 "start_memory_size=%zu "
982 "end_memory_size=%zu "
983 "start_holes_size=%zu "
984 "end_holes_size=%zu "
987 "new_space_survived=%zu "
988 "nodes_died_in_new=%d "
989 "nodes_copied_in_new=%d "
991 "promotion_ratio=%.1f%% "
992 "average_survival_ratio=%.1f%% "
993 "promotion_rate=%.1f%% "
994 "new_space_survive_rate_=%.1f%% "
995 "new_space_capacity=%zu "
996 "old_gen_allocation_limit=%zu "
997 "global_allocation_limit=%zu "
998 "new_space_allocation_throughput=%.1f "
999 "allocation_throughput=%.1f\n",
1012 current_scope(Scope::MINOR_MS_CLEAR_STRING_FORWARDING_TABLE),
1015 current_scope(Scope::MINOR_MS_COMPLETE_SWEEP_ARRAY_BUFFERS),
1052 "time_to_safepoint=%.2f "
1053 "heap.prologue=%.2f "
1054 "heap.embedder_tracing_epilogue=%.2f "
1055 "heap.epilogue=%.2f "
1056 "heap.external.prologue=%.1f "
1057 "heap.external.epilogue=%.1f "
1058 "heap.external.weak_global_handles=%.1f "
1060 "clear.external_string_table=%.1f "
1061 "clear.string_forwarding_table=%.1f "
1062 "clear.weak_global_handles=%.1f "
1063 "clear.dependent_code=%.1f "
1065 "clear.slots_buffer=%.1f "
1066 "clear.weak_collections=%.1f "
1067 "clear.weak_lists=%.1f "
1068 "clear.weak_references_trivial=%.1f "
1069 "clear.weak_references_non_trivial=%.1f "
1070 "clear.weak_references_filter_non_trivial=%.1f "
1071 "clear.js_weak_references=%.1f "
1072 "clear.join_filter_job=%.1f"
1073 "clear.join_job=%.1f "
1074 "weakness_handling=%.1f "
1075 "complete.sweep_array_buffers=%.1f "
1076 "complete.sweeping=%.1f "
1079 "evacuate.pin_pages=%.1f "
1080 "evacuate.candidates=%.1f "
1081 "evacuate.clean_up=%.1f "
1082 "evacuate.copy=%.1f "
1083 "evacuate.prologue=%.1f "
1084 "evacuate.epilogue=%.1f "
1085 "evacuate.rebalance=%.1f "
1086 "evacuate.update_pointers=%.1f "
1087 "evacuate.update_pointers.to_new_roots=%.1f "
1088 "evacuate.update_pointers.slots.main=%.1f "
1089 "evacuate.update_pointers.weak=%.1f "
1091 "finish.sweep_array_buffers=%.1f "
1093 "mark.finish_incremental=%.1f "
1095 "mark.full_closure_parallel=%.1f "
1096 "mark.full_closure=%.1f "
1097 "mark.ephemeron.marking=%.1f "
1098 "mark.ephemeron.linear=%.1f "
1099 "mark.embedder_prologue=%.1f "
1100 "mark.embedder_tracing=%.1f "
1106 "sweep.new_lo=%.1f "
1108 "sweep.start_jobs=%.1f "
1110 "incremental.finalize.external.prologue=%.1f "
1111 "incremental.finalize.external.epilogue=%.1f "
1112 "incremental.layout_change=%.1f "
1113 "incremental.sweep_array_buffers=%.1f "
1114 "incremental.sweeping=%.1f "
1115 "incremental.embedder_tracing=%.1f "
1116 "incremental_wrapper_tracing_longest_step=%.1f "
1117 "incremental_longest_step=%.1f "
1118 "incremental_steps_count=%d "
1119 "incremental_marking_throughput=%.f "
1120 "incremental_walltime_duration=%.f "
1121 "background.mark=%.1f "
1122 "background.sweep=%.1f "
1123 "background.evacuate.copy=%.1f "
1124 "background.evacuate.update_pointers=%.1f "
1125 "conservative_stack_scanning=%.2f "
1126 "start_object_size=%zu "
1127 "end_object_size=%zu "
1128 "start_memory_size=%zu "
1129 "end_memory_size=%zu "
1130 "start_holes_size=%zu "
1131 "end_holes_size=%zu "
1134 "new_space_survived=%zu "
1135 "nodes_died_in_new=%d "
1136 "nodes_copied_in_new=%d "
1137 "nodes_promoted=%d "
1138 "promotion_ratio=%.1f%% "
1139 "average_survival_ratio=%.1f%% "
1140 "promotion_rate=%.1f%% "
1141 "new_space_survive_rate=%.1f%% "
1142 "new_space_allocation_throughput=%.1f "
1143 "new_space_capacity=%zu "
1144 "old_gen_allocation_limit=%zu "
1145 "global_allocation_limit=%zu "
1146 "allocation_throughput=%.1f "
1147 "pool_local_chunks=%zu "
1148 "pool_shared_chunks=%zu "
1149 "pool_total_chunks=%zu "
1150 "compaction_speed=%.1f\n",
1171 current_scope(Scope::MC_CLEAR_WEAK_REFERENCES_FILTER_NON_TRIVIAL),
1173 current_scope(Scope::MC_CLEAR_WEAK_REFERENCES_JOIN_FILTER_JOB),
1187 current_scope(Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW_ROOTS),
1188 current_scope(Scope::MC_EVACUATE_UPDATE_POINTERS_SLOTS_MAIN),
1197 current_scope(Scope::MC_MARK_WEAK_CLOSURE_EPHEMERON_MARKING),
1198 current_scope(Scope::MC_MARK_WEAK_CLOSURE_EPHEMERON_LINEAR),
1216 .longest_step.InMillisecondsF(),
1218 .longest_step.InMillisecondsF(),
1225 current_scope(Scope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS),
1254 if (duration.
IsZero() || bytes == 0)
return;
1255 double current_speed =
1313 double average_total_duration =
1315 if (average_total_duration == 0)
return 1.0;
1357std::optional<double>
1363 if (
v8_flags.gc_speed_uses_counters) {
1367 const double kMinimumMarkingSpeed = 0.5;
1379 if (speed1 < kMinimumMarkingSpeed || speed2 < kMinimumMarkingSpeed) {
1413 [](
double a,
double b) {
return a + b; }, 0.0);
1448 counters->gc_finalize_clear()->AddSample(
1450 counters->gc_finalize_epilogue()->AddSample(
1452 counters->gc_finalize_evacuate()->AddSample(
1454 counters->gc_finalize_finish()->AddSample(
1456 counters->gc_finalize_mark()->AddSample(
1458 counters->gc_finalize_prologue()->AddSample(
1460 counters->gc_finalize_sweep()->AddSample(
1468 counters->gc_scavenger_scavenge_main()->AddSample(
1469 TruncateToMs(
current_.
scopes[Scope::SCAVENGER_SCAVENGE_PARALLEL]));
1470 counters->gc_scavenger_scavenge_roots()->AddSample(
1485 atomic_pause_duration + incremental_marking + incremental_sweeping;
1489 atomic_marking_duration + incremental_marking;
1494 background_duration =
1499 marking_background_duration =
1514 "background_duration", marking_background_duration.
InMillisecondsF());
1523#if defined(V8_USE_PERFETTO)
1526 perfetto::CounterTrack(
"OldGenerationConsumedBytes", parent_track_),
1529 perfetto::CounterTrack(
"GlobalConsumedBytes", parent_track_),
1532 perfetto::CounterTrack(
"ExternalMemoryBytes", parent_track_),
1539void CopyTimeMetrics(
1556void CopyTimeMetrics(
1574void CopySizeMetrics(
1588 if (isolate->context().is_null())
1590 HandleScope scope(isolate);
1591 return isolate->GetOrRegisterRecorderContextId(isolate->native_context());
1594template <
typename EventType>
1595void FlushBatchedEvents(
1600 isolate->metrics_recorder()->AddMainThreadEvent(std::move(batched_events),
1602 batched_events = {};
1612 cpp_heap->GetMetricRecorder()->FullGCMetricsReportPending());
1613 const std::shared_ptr<metrics::Recorder>& recorder =
1616 if (!recorder->HasEmbedderRecorder()) {
1620 cpp_heap->GetMetricRecorder()->ClearCachedEvents();
1637 cpp_heap->GetMetricRecorder()->FlushBatchedIncrementalEvents();
1638 const std::optional<cppgc::internal::MetricRecorder::GCCycle>
1639 optional_cppgc_event =
1640 cpp_heap->GetMetricRecorder()->ExtractLastFullGcEvent();
1641 DCHECK(optional_cppgc_event.has_value());
1642 DCHECK(!cpp_heap->GetMetricRecorder()->FullGCMetricsReportPending());
1644 optional_cppgc_event.value();
1656 event.collection_rate_cpp_in_percent =
1659 event.efficiency_cpp_in_bytes_per_us =
1662 event.main_thread_efficiency_cpp_in_bytes_per_us =
1666 event.collection_weight_cpp_in_percent = 0;
1667 event.main_thread_collection_weight_cpp_in_percent = 0;
1669 event.collection_weight_cpp_in_percent =
1670 static_cast<double>(
event.total_cpp.total_wall_clock_duration_in_us) /
1672 event.main_thread_collection_weight_cpp_in_percent =
1673 static_cast<double>(
1674 event.main_thread_cpp.total_wall_clock_duration_in_us) /
1690 atomic_pause_duration + incremental_marking + incremental_sweeping;
1698 const base::TimeDelta background_duration = marking_background_duration +
1699 sweeping_background_duration +
1700 compact_background_duration;
1704 atomic_marking_duration + incremental_marking;
1712 atomic_sweeping_duration + incremental_sweeping;
1714 event.main_thread_atomic.total_wall_clock_duration_in_us =
1716 event.main_thread.total_wall_clock_duration_in_us =
1718 event.total.total_wall_clock_duration_in_us =
1719 (overall_duration + background_duration).InMicroseconds();
1720 event.main_thread_atomic.mark_wall_clock_duration_in_us =
1722 event.main_thread.mark_wall_clock_duration_in_us =
1724 event.total.mark_wall_clock_duration_in_us =
1725 (marking_duration + marking_background_duration).InMicroseconds();
1726 event.main_thread_atomic.weak_wall_clock_duration_in_us =
1727 event.main_thread.weak_wall_clock_duration_in_us =
1728 event.total.weak_wall_clock_duration_in_us =
1730 event.main_thread_atomic.compact_wall_clock_duration_in_us =
1731 event.main_thread.compact_wall_clock_duration_in_us =
1733 event.total.compact_wall_clock_duration_in_us =
1734 (compact_duration + compact_background_duration).InMicroseconds();
1735 event.main_thread_atomic.sweep_wall_clock_duration_in_us =
1737 event.main_thread.sweep_wall_clock_duration_in_us =
1739 event.total.sweep_wall_clock_duration_in_us =
1740 (sweeping_duration + sweeping_background_duration).InMicroseconds();
1742 event.main_thread_incremental.mark_wall_clock_duration_in_us =
1744 event.incremental_marking_start_stop_wall_clock_duration_in_us =
1749 event.main_thread_incremental.mark_wall_clock_duration_in_us = -1;
1753 event.main_thread_incremental.sweep_wall_clock_duration_in_us =
1759 event.objects.bytes_freed =
1764 event.memory.bytes_freed =
1770 event.collection_rate_in_percent = 0;
1772 event.collection_rate_in_percent =
1773 static_cast<double>(
event.objects.bytes_freed) /
1778 event.efficiency_in_bytes_per_us = 0;
1779 event.main_thread_efficiency_in_bytes_per_us = 0;
1787 event.efficiency_in_bytes_per_us =
1788 static_cast<double>(
event.objects.bytes_freed) /
1790 event.main_thread_efficiency_in_bytes_per_us =
1791 static_cast<double>(
event.objects.bytes_freed) /
1795 event.collection_weight_in_percent = 0;
1796 event.main_thread_collection_weight_in_percent = 0;
1798 event.collection_weight_in_percent =
1799 static_cast<double>(
event.total.total_wall_clock_duration_in_us) /
1801 event.main_thread_collection_weight_in_percent =
1802 static_cast<double>(
event.main_thread.total_wall_clock_duration_in_us) /
1806 recorder->AddMainThreadEvent(event, GetContextId(
heap_->
isolate()));
1811 static constexpr int kMaxBatchedEvents =
1813 const std::shared_ptr<metrics::Recorder>& recorder =
1816 if (!recorder->HasEmbedderRecorder())
return;
1819 const std::optional<
1824 if (cppgc_event.has_value()) {
1825 DCHECK_NE(-1, cppgc_event.value().duration_us);
1827 .cpp_wall_clock_duration_in_us = cppgc_event.value().duration_us;
1831 static_cast<int64_t
>(v8_duration *
1839 static constexpr int kMaxBatchedEvents =
1841 const std::shared_ptr<metrics::Recorder>& recorder =
1844 if (!recorder->HasEmbedderRecorder())
return;
1847 static_cast<int64_t
>(v8_duration *
1857 const std::shared_ptr<metrics::Recorder>& recorder =
1860 if (!recorder->HasEmbedderRecorder())
return;
1866#if defined(CPPGC_YOUNG_GENERATION)
1869 if (cpp_heap && cpp_heap->generational_gc_supported()) {
1870 auto* metric_recorder = cpp_heap->GetMetricRecorder();
1871 const std::optional<cppgc::internal::MetricRecorder::GCCycle>
1872 optional_cppgc_event = metric_recorder->ExtractLastYoungGcEvent();
1875 if (optional_cppgc_event) {
1876 DCHECK(!metric_recorder->YoungGCMetricsReportPending());
1878 optional_cppgc_event.value();
1881 CopyTimeMetrics(event.total_cpp, cppgc_event.
total);
1882 CopySizeMetrics(event.objects_cpp, cppgc_event.
objects);
1883 CopySizeMetrics(event.memory_cpp, cppgc_event.
memory);
1885 event.collection_rate_cpp_in_percent =
1888 event.efficiency_cpp_in_bytes_per_us =
1891 event.main_thread_efficiency_cpp_in_bytes_per_us =
1903 event.total_wall_clock_duration_in_us =
1909 event.main_thread_wall_clock_duration_in_us =
1913 event.collection_rate_in_percent = 0;
1915 event.collection_rate_in_percent =
1923 const double freed_bytes =
static_cast<double>(
1925 event.efficiency_in_bytes_per_us =
1926 total_wall_clock_duration.
IsZero()
1927 ? std::numeric_limits<double>::infinity()
1929 event.main_thread_efficiency_in_bytes_per_us =
1930 main_thread_wall_clock_duration.
IsZero()
1931 ? std::numeric_limits<double>::infinity()
1932 : freed_bytes / main_thread_wall_clock_duration.
InMicroseconds();
1933 recorder->AddMainThreadEvent(event, GetContextId(
heap_->
isolate()));
1961bool GCTracer::IsInObservablePause()
const {
1965bool GCTracer::IsInAtomicPause()
const {
1969bool GCTracer::IsConsistentWithCollector(
GarbageCollector collector)
const {
1970 switch (collector) {
1982bool GCTracer::IsSweepingInProgress()
const {
void Update(BytesAndDuration bytes_and_duration)
static int GetCurrentProcessId()
constexpr bool Empty() const
constexpr T Reduce(Callback callback, const T &initial) const
constexpr uint8_t Size() const
constexpr void Push(const T &value)
static constexpr int64_t kMicrosecondsPerMillisecond
static constexpr TimeDelta FromMillisecondsD(double milliseconds)
static constexpr TimeDelta FromSeconds(int64_t seconds)
double InMillisecondsF() const
constexpr bool IsZero() const
int64_t InMilliseconds() const
int64_t InMicroseconds() const
const std::optional< cppgc::internal::MetricRecorder::MainThreadIncrementalMark > ExtractLastIncrementalMarkEvent()
static constexpr int kMaxBatchedEvents
static CppHeap * From(v8::CppHeap *heap)
MetricRecorderAdapter * GetMetricRecorder() const
static V8_INLINE constexpr bool IsYoungGenerationEvent(Type type)
@ INCREMENTAL_MINOR_MARK_SWEEPER
@ INCREMENTAL_MARK_COMPACTOR
size_t survived_young_object_size
const char * collector_reason
base::TimeTicks incremental_marking_start_time
base::TimeTicks end_atomic_pause_time
Event(Type type, State state, GarbageCollectionReason gc_reason, const char *collector_reason, Priority priority)
size_t incremental_marking_bytes
base::TimeTicks start_time
base::TimeTicks start_atomic_pause_time
base::TimeDelta scopes[Scope::NUMBER_OF_SCOPES]
GarbageCollectionReason gc_reason
size_t concurrency_estimate
std::optional< Priority > priority
base::TimeDelta incremental_marking_duration
IncrementalInfos incremental_scopes[Scope::NUMBER_OF_INCREMENTAL_SCOPES]
RecordGCPhasesInfo(Heap *heap, GarbageCollector collector, GarbageCollectionReason reason)
@ FIRST_INCREMENTAL_SCOPE
@ NUMBER_OF_INCREMENTAL_SCOPES
std::optional< double > EmbedderSpeedInBytesPerMillisecond() const
void NotifyFullCppGCCompleted()
BytesAndDurationBuffer recorded_incremental_mark_compacts_
void UpdateCurrentEventPriority(Priority priority)
GCTracer(Heap *heap, base::TimeTicks startup_time, GarbageCollectionReason initial_gc_reason=GarbageCollectionReason::kUnknown)
size_t new_space_allocation_counter_bytes_
void UpdateMemoryBalancerGCSpeed()
base::TimeTicks allocation_time_
void FetchBackgroundCounters()
bool notified_full_cppgc_completed_
void AddSurvivalRatio(double survival_ratio)
double AverageSurvivalRatio() const
double AverageMarkCompactMutatorUtilization() const
void ReportYoungCycleToRecorder()
void ReportIncrementalSweepingStepToRecorder(double v8_duration)
SmoothedBytesAndDuration new_generation_allocations_
SmoothedBytesAndDuration embedder_generation_allocations_
void StopInSafepoint(base::TimeTicks time)
base::TimeDelta total_duration_since_last_mark_compact_
double CurrentMarkCompactMutatorUtilization() const
void RecordGCSizeCounters() const
base::TimeDelta background_scopes_[Scope::NUMBER_OF_SCOPES]
void StopCycle(GarbageCollector collector)
uint16_t CodeFlushingIncrease() const
bool notified_full_sweeping_completed_
void ReportIncrementalMarkingStepToRecorder(double v8_duration)
void NotifyYoungCppGCCompleted()
std::optional< double > YoungGenerationSpeedInBytesPerMillisecond(YoungGenerationSpeedMode mode) const
SmoothedBytesAndDuration old_generation_allocations_
void RecordEmbedderMarkingSpeed(size_t bytes, base::TimeDelta duration)
BytesAndDurationBuffer recorded_compactions_
void UpdateCurrentEvent(GarbageCollectionReason gc_reason, const char *collector_reason)
std::optional< double > combined_mark_compact_speed_cache_
void RecordIncrementalMarkingSpeed(size_t bytes, base::TimeDelta duration)
bool notified_young_cppgc_running_
void StopObservablePause(GarbageCollector collector, base::TimeTicks time)
double AllocationThroughputInBytesPerMillisecond() const
double recorded_major_incremental_marking_speed_
base::RingBuffer< double > recorded_survival_ratios_
static constexpr double kConservativeSpeedInBytesPerMillisecond
std::optional< double > MarkCompactSpeedInBytesPerMillisecond() const
uint16_t code_flushing_increase_s_
BytesAndDurationBuffer recorded_minor_gc_atomic_pause_
std::optional< double > FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() const
std::optional< base::TimeTicks > start_of_observable_pause_
double NewSpaceAllocationThroughputInBytesPerMillisecond() const
double average_mark_compact_duration_
void StartInSafepoint(base::TimeTicks time)
void StopFullCycleIfFinished()
void SampleConcurrencyEsimate(size_t concurrency)
V8_INLINE double current_scope(Scope::ScopeId id) const
std::optional< double > OldGenerationSpeedInBytesPerMillisecond()
BytesAndDurationBuffer recorded_minor_gc_per_thread_
size_t embedder_allocation_counter_bytes_
void NotifyYoungSweepingCompleted()
void RecordTimeToIncrementalMarkingTask(base::TimeDelta time_to_task)
bool young_gc_while_full_gc_
void StartObservablePause(base::TimeTicks time)
std::optional< base::TimeDelta > average_time_to_incremental_marking_task_
void AddCompactionEvent(double duration, size_t live_bytes_compacted)
void RecordMutatorUtilization(base::TimeTicks mark_compactor_end_time, base::TimeDelta mark_compactor_duration)
void RecordGCPhasesHistograms(RecordGCPhasesInfo::Mode mode)
void NotifyMarkingStart()
CollectionEpoch epoch_full_
void AddIncrementalMarkingStep(double duration, size_t bytes)
double IncrementalMarkingSpeedInBytesPerMillisecond() const
bool notified_young_sweeping_completed_
BytesAndDurationBuffer recorded_embedder_marking_
base::TimeTicks previous_mark_compact_end_time_
std::optional< base::TimeTicks > last_marking_start_time_for_code_flushing_
bool SurvivalEventsRecorded() const
void AddIncrementalSweepingStep(double duration)
void NotifyYoungSweepingCompletedAndStopCycleIfFinished()
void SampleAllocation(base::TimeTicks current, size_t new_space_counter_bytes, size_t old_generation_counter_bytes, size_t embedder_counter_bytes)
void ResetSurvivalEvents()
double current_mark_compact_mutator_utilization_
double OldGenerationAllocationThroughputInBytesPerMillisecond() const
v8::metrics::GarbageCollectionFullMainThreadBatchedIncrementalMark incremental_mark_batched_events_
bool notified_young_cppgc_completed_
V8_INLINE constexpr const IncrementalInfos & incremental_scope(Scope::ScopeId id) const
void NotifyIncrementalMarkingStart()
bool full_cppgc_completed_during_minor_gc_
base::Mutex background_scopes_mutex_
std::optional< base::TimeDelta > AverageTimeToIncrementalMarkingTask() const
void StartCycle(GarbageCollector collector, GarbageCollectionReason gc_reason, const char *collector_reason, MarkingType marking)
std::optional< double > CompactionSpeedInBytesPerMillisecond() const
void StopYoungCycleIfFinished()
double average_mutator_duration_
CollectionEpoch epoch_young_
void NotifyFullSweepingCompletedAndStopCycleIfFinished()
void ReportFullCycleToRecorder()
void NotifyYoungCppGCRunning()
IncrementalInfos incremental_scopes_[Scope::NUMBER_OF_INCREMENTAL_SCOPES]
BytesAndDurationBuffer recorded_major_totals_
BytesAndDurationBuffer recorded_mark_compacts_
void RecordGCSumCounters()
size_t old_generation_allocation_counter_bytes_
v8::metrics::GarbageCollectionFullMainThreadBatchedIncrementalSweep incremental_sweep_batched_events_
double EmbedderAllocationThroughputInBytesPerMillisecond() const
GarbageCollector GetCurrentCollector() const
size_t promoted_objects_size()
int nodes_copied_in_new_space_
V8_INLINE uint64_t external_memory() const
void PrintFreeListsStats()
NewSpace * new_space() const
size_t OldGenerationAllocationCounter()
NewLargeObjectSpace * new_lo_space() const
void DumpJSONHeapStatistics(std::stringstream &stream)
size_t old_generation_allocation_limit() const
size_t new_space_surviving_object_size()
size_t EmbedderAllocationCounter() const
double new_space_surviving_rate_
std::unique_ptr< MemoryBalancer > mb_
int nodes_died_in_new_space_
MemoryAllocator * memory_allocator()
V8_EXPORT_PRIVATE size_t OldGenerationConsumedBytes() const
SemiSpaceNewSpace * semi_space_new_space() const
size_t global_allocation_limit() const
void AddToRingBuffer(const char *string)
void PrintShortHeapStatistics()
V8_EXPORT_PRIVATE size_t GlobalConsumedBytes() const
void UpdateTotalGCTime(base::TimeDelta duration)
v8::CppHeap * cpp_heap() const
Isolate * isolate() const
size_t SurvivedYoungObjectSize()
V8_EXPORT_PRIVATE size_t NewSpaceAllocationCounter() const
bool ShouldReduceMemory() const
V8_EXPORT_PRIVATE size_t SizeOfObjects()
v8::metrics::LongTaskStats * GetCurrentLongTaskStats()
double time_millis_since_init() const
const std::shared_ptr< metrics::Recorder > & metrics_recorder()
v8::Isolate::Priority priority()
size_t SizeOfObjects() const override
V8_EXPORT_PRIVATE size_t GetSharedPooledChunksCount()
V8_EXPORT_PRIVATE size_t GetPooledChunksCount()
V8_EXPORT_PRIVATE size_t GetTotalPooledChunksCount()
static const int kPageSize
virtual size_t TotalCapacity() const =0
size_t QuarantinedSize() const
size_t QuarantinedPageCount() const
static constexpr int kAgeSize
static const ContextId Empty()
RecordWriteMode const mode_
#define TRACE_GC_NOTE(note)
int VSNPrintF(Vector< char > str, const char *format, va_list args)
int GetContextId(Local< Context > context)
constexpr const char * ToString(DeoptimizeKind kind)
@ kUpToAndIncludingAtomicPause
static size_t CountTotalHolesSize(Heap *heap)
V8_EXPORT_PRIVATE FlagValues v8_flags
void PrintIsolate(void *isolate, const char *format,...)
#define DCHECK_LE(v1, v2)
#define CHECK_GE(lhs, rhs)
#define CHECK_IMPLIES(lhs, rhs)
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
int64_t sweep_duration_us
int64_t compact_duration_us
Phases main_thread_atomic
double collection_rate_in_percent
double efficiency_in_bytes_per_us
IncrementalPhases main_thread_incremental
double main_thread_efficiency_in_bytes_per_us
static V8_EXPORT_PRIVATE std::atomic_uint gc
std::vector< EventType > events
GarbageCollectionSizes memory_cpp
GarbageCollectionPhases main_thread_cpp
GarbageCollectionPhases main_thread_incremental_cpp
GarbageCollectionSizes objects
GarbageCollectionPhases main_thread_atomic_cpp
GarbageCollectionPhases main_thread
GarbageCollectionPhases total_cpp
GarbageCollectionPhases total
GarbageCollectionSizes objects_cpp
int64_t sweep_wall_clock_duration_in_us
int64_t weak_wall_clock_duration_in_us
int64_t total_wall_clock_duration_in_us
int64_t mark_wall_clock_duration_in_us
int64_t compact_wall_clock_duration_in_us
#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val)
#define TRACE_EVENT_SCOPE_THREAD
#define TRACE_DISABLED_BY_DEFAULT(name)
#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_STR_COPY(str)
#define V8_UNLIKELY(condition)