1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "gc/g1/g1EvacuationInfo.hpp" 27 #include "gc/g1/g1HeapRegionTraceType.hpp" 28 #include "gc/g1/g1Trace.hpp" 29 #include "gc/g1/g1YCTypes.hpp" 30 #include "gc/shared/gcHeapSummary.hpp" 31 #include "jfr/jfrEvents.hpp" 32 #if INCLUDE_JFR 33 #include "jfr/metadata/jfrSerializer.hpp" 34 #endif 35 36 #if INCLUDE_JFR 37 class G1HeapRegionTypeConstant : public JfrSerializer { 38 public: 39 void serialize(JfrCheckpointWriter& writer) { 40 static const u4 nof_entries = G1HeapRegionTraceType::G1HeapRegionTypeEndSentinel; 41 writer.write_count(nof_entries); 42 for (u4 i = 0; i < nof_entries; ++i) { 43 writer.write_key(i); 44 writer.write(G1HeapRegionTraceType::to_string((G1HeapRegionTraceType::Type)i)); 45 } 46 } 47 }; 48 49 class G1YCTypeConstant : public JfrSerializer { 50 public: 51 void serialize(JfrCheckpointWriter& writer) { 52 static const u4 nof_entries = G1YCTypeEndSentinel; 53 writer.write_count(nof_entries); 54 for (u4 i = 0; i < nof_entries; ++i) { 55 writer.write_key(i); 56 writer.write(G1YCTypeHelper::to_string((G1YCType)i)); 57 } 58 } 59 }; 60 61 static void register_jfr_type_constants() { 62 JfrSerializer::register_serializer(TYPE_G1HEAPREGIONTYPE, true, 63 new G1HeapRegionTypeConstant()); 64 65 JfrSerializer::register_serializer(TYPE_G1YCTYPE, true, 66 new G1YCTypeConstant()); 67 } 68 69 #endif 70 71 void G1NewTracer::initialize() { 72 JFR_ONLY(register_jfr_type_constants()); 73 } 74 75 void G1NewTracer::report_yc_type(G1YCType type) { 76 _g1_young_gc_info.set_type(type); 77 } 78 79 void G1NewTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { 80 YoungGCTracer::report_gc_end_impl(timestamp, time_partitions); 81 send_g1_young_gc_event(); 82 } 83 84 void G1NewTracer::report_evacuation_info(G1EvacuationInfo* info) { 85 send_evacuation_info_event(info); 86 } 87 88 void G1NewTracer::report_evacuation_failed(EvacuationFailedInfo& ef_info) { 89 send_evacuation_failed_event(ef_info); 90 ef_info.reset(); 91 } 92 93 void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summary, const G1EvacSummary& old_summary) const { 94 send_young_evacuation_statistics(young_summary); 95 send_old_evacuation_statistics(old_summary); 96 } 97 98 void G1NewTracer::report_basic_ihop_statistics(size_t threshold, 99 size_t target_ccupancy, 100 size_t current_occupancy, 101 size_t last_allocation_size, 102 double last_allocation_duration, 103 double last_marking_length) { 104 send_basic_ihop_statistics(threshold, 105 target_ccupancy, 106 current_occupancy, 107 last_allocation_size, 108 last_allocation_duration, 109 last_marking_length); 110 } 111 112 void G1NewTracer::report_adaptive_ihop_statistics(size_t threshold, 113 size_t internal_target_occupancy, 114 size_t current_occupancy, 115 size_t additional_buffer_size, 116 double predicted_allocation_rate, 117 double predicted_marking_length, 118 bool prediction_active) { 119 send_adaptive_ihop_statistics(threshold, 120 internal_target_occupancy, 121 additional_buffer_size, 122 current_occupancy, 123 predicted_allocation_rate, 124 predicted_marking_length, 125 prediction_active); 126 } 127 128 void G1NewTracer::send_g1_young_gc_event() { 129 EventG1GarbageCollection e(UNTIMED); 130 if (e.should_commit()) { 131 e.set_gcId(GCId::current()); 132 e.set_type(_g1_young_gc_info.type()); 133 e.set_starttime(_shared_gc_info.start_timestamp()); 134 e.set_endtime(_shared_gc_info.end_timestamp()); 135 e.commit(); 136 } 137 } 138 139 void G1NewTracer::send_evacuation_info_event(G1EvacuationInfo* info) { 140 EventEvacuationInformation e; 141 if (e.should_commit()) { 142 e.set_gcId(GCId::current()); 143 e.set_cSetRegions(info->collectionset_regions()); 144 e.set_cSetUsedBefore(info->collectionset_used_before()); 145 e.set_cSetUsedAfter(info->collectionset_used_after()); 146 e.set_allocationRegions(info->allocation_regions()); 147 e.set_allocationRegionsUsedBefore(info->alloc_regions_used_before()); 148 e.set_allocationRegionsUsedAfter(info->alloc_regions_used_before() + info->bytes_used()); 149 e.set_bytesCopied(info->bytes_used()); 150 e.set_regionsFreed(info->regions_freed()); 151 e.commit(); 152 } 153 } 154 155 void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const { 156 EventEvacuationFailed e; 157 if (e.should_commit()) { 158 // Create JFR structured failure data 159 JfrStructCopyFailed evac_failed; 160 evac_failed.set_objectCount(ef_info.failed_count()); 161 evac_failed.set_firstSize(ef_info.first_size()); 162 evac_failed.set_smallestSize(ef_info.smallest_size()); 163 evac_failed.set_totalSize(ef_info.total_size()); 164 // Add to the event 165 e.set_gcId(GCId::current()); 166 e.set_evacuationFailed(evac_failed); 167 e.commit(); 168 } 169 } 170 171 static JfrStructG1EvacuationStatistics 172 create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) { 173 JfrStructG1EvacuationStatistics s; 174 s.set_gcId(gcid); 175 s.set_allocated(summary.allocated() * HeapWordSize); 176 s.set_wasted(summary.wasted() * HeapWordSize); 177 s.set_used(summary.used() * HeapWordSize); 178 s.set_undoWaste(summary.undo_wasted() * HeapWordSize); 179 s.set_regionEndWaste(summary.region_end_waste() * HeapWordSize); 180 s.set_regionsRefilled(summary.regions_filled()); 181 s.set_directAllocated(summary.direct_allocated() * HeapWordSize); 182 s.set_failureUsed(summary.failure_used() * HeapWordSize); 183 s.set_failureWaste(summary.failure_waste() * HeapWordSize); 184 return s; 185 } 186 187 void G1NewTracer::send_young_evacuation_statistics(const G1EvacSummary& summary) const { 188 EventG1EvacuationYoungStatistics surv_evt; 189 if (surv_evt.should_commit()) { 190 surv_evt.set_statistics(create_g1_evacstats(GCId::current(), summary)); 191 surv_evt.commit(); 192 } 193 } 194 195 void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) const { 196 EventG1EvacuationOldStatistics old_evt; 197 if (old_evt.should_commit()) { 198 old_evt.set_statistics(create_g1_evacstats(GCId::current(), summary)); 199 old_evt.commit(); 200 } 201 } 202 203 void G1NewTracer::send_basic_ihop_statistics(size_t threshold, 204 size_t target_occupancy, 205 size_t current_occupancy, 206 size_t last_allocation_size, 207 double last_allocation_duration, 208 double last_marking_length) { 209 EventG1BasicIHOP evt; 210 if (evt.should_commit()) { 211 evt.set_gcId(GCId::current()); 212 evt.set_threshold(threshold); 213 evt.set_targetOccupancy(target_occupancy); 214 evt.set_thresholdPercentage(target_occupancy > 0 ? ((double)threshold / target_occupancy) : 0.0); 215 evt.set_currentOccupancy(current_occupancy); 216 evt.set_recentMutatorAllocationSize(last_allocation_size); 217 evt.set_recentMutatorDuration(last_allocation_duration * MILLIUNITS); 218 evt.set_recentAllocationRate(last_allocation_duration != 0.0 ? last_allocation_size / last_allocation_duration : 0.0); 219 evt.set_lastMarkingDuration(last_marking_length * MILLIUNITS); 220 evt.commit(); 221 } 222 } 223 224 void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold, 225 size_t internal_target_occupancy, 226 size_t current_occupancy, 227 size_t additional_buffer_size, 228 double predicted_allocation_rate, 229 double predicted_marking_length, 230 bool prediction_active) { 231 EventG1AdaptiveIHOP evt; 232 if (evt.should_commit()) { 233 evt.set_gcId(GCId::current()); 234 evt.set_threshold(threshold); 235 evt.set_thresholdPercentage(internal_target_occupancy > 0 ? ((double)threshold / internal_target_occupancy) : 0.0); 236 evt.set_ihopTargetOccupancy(internal_target_occupancy); 237 evt.set_currentOccupancy(current_occupancy); 238 evt.set_additionalBufferSize(additional_buffer_size); 239 evt.set_predictedAllocationRate(predicted_allocation_rate); 240 evt.set_predictedMarkingDuration(predicted_marking_length * MILLIUNITS); 241 evt.set_predictionActive(prediction_active); 242 evt.commit(); 243 } 244 } 245 246 void G1OldTracer::report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp) { 247 _shared_gc_info.set_start_timestamp(timestamp); 248 } 249 250 void G1OldTracer::set_gc_cause(GCCause::Cause cause) { 251 _shared_gc_info.set_cause(cause); 252 } 253 254 void G1MMUTracer::report_mmu(double time_slice_sec, double gc_time_sec, double max_time_sec) { 255 send_g1_mmu_event(time_slice_sec * MILLIUNITS, 256 gc_time_sec * MILLIUNITS, 257 max_time_sec * MILLIUNITS); 258 } 259 260 void G1MMUTracer::send_g1_mmu_event(double time_slice_ms, double gc_time_ms, double max_time_ms) { 261 EventG1MMU e; 262 if (e.should_commit()) { 263 e.set_gcId(GCId::current()); 264 e.set_timeSlice(time_slice_ms); 265 e.set_gcTime(gc_time_ms); 266 e.set_pauseTarget(max_time_ms); 267 e.commit(); 268 } 269 }