1 /* 2 * Copyright (c) 2016, 2020, Red Hat, Inc. All rights reserved. 3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 28 #include "gc/shenandoah/shenandoahGeneration.hpp" 29 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 30 #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" 31 #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" 32 #include "gc/shenandoah/shenandoahHeapRegionCounters.hpp" 33 #include "logging/logStream.hpp" 34 #include "memory/resourceArea.hpp" 35 #include "runtime/atomic.hpp" 36 #include "runtime/perfData.inline.hpp" 37 #include "utilities/defaultStream.hpp" 38 39 ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : 40 _last_sample_millis(0) 41 { 42 if (UsePerfData && ShenandoahRegionSampling) { 43 EXCEPTION_MARK; 44 ResourceMark rm; 45 ShenandoahHeap* heap = ShenandoahHeap::heap(); 46 size_t num_regions = heap->num_regions(); 47 const char* cns = PerfDataManager::name_space("shenandoah", "regions"); 48 _name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtGC); 49 strcpy(_name_space, cns); 50 51 const char* cname = PerfDataManager::counter_name(_name_space, "timestamp"); 52 _timestamp = PerfDataManager::create_long_variable(SUN_GC, cname, PerfData::U_None, CHECK); 53 54 cname = PerfDataManager::counter_name(_name_space, "max_regions"); 55 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, num_regions, CHECK); 56 57 cname = PerfDataManager::counter_name(_name_space, "protocol_version"); 58 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, VERSION_NUMBER, CHECK); 59 60 cname = PerfDataManager::counter_name(_name_space, "region_size"); 61 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, ShenandoahHeapRegion::region_size_bytes() >> 10, CHECK); 62 63 cname = PerfDataManager::counter_name(_name_space, "status"); 64 _status = PerfDataManager::create_long_variable(SUN_GC, cname, 65 PerfData::U_None, CHECK); 66 67 _regions_data = NEW_C_HEAP_ARRAY(PerfVariable*, num_regions, mtGC); 68 // Initializing performance data resources for each region 69 for (uint i = 0; i < num_regions; i++) { 70 const char* reg_name = PerfDataManager::name_space(_name_space, "region", i); 71 const char* data_name = PerfDataManager::counter_name(reg_name, "data"); 72 const char* ns = PerfDataManager::ns_to_string(SUN_GC); 73 const char* fullname = PerfDataManager::counter_name(ns, data_name); 74 assert(!PerfDataManager::exists(fullname), "must not exist"); 75 _regions_data[i] = PerfDataManager::create_long_variable(SUN_GC, data_name, PerfData::U_None, CHECK); 76 } 77 } 78 } 79 80 ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { 81 if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); 82 } 83 84 void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions, 85 PerfLongVariable* ts, 86 PerfLongVariable* status, 87 size_t num_regions, 88 size_t region_size, size_t protocol_version) { 89 LogTarget(Trace, gc, region) lt; 90 if (lt.is_enabled()) { 91 ResourceMark rm; 92 LogStream ls(lt); 93 94 ls.print_cr(JLONG_FORMAT " " JLONG_FORMAT " " SIZE_FORMAT " " SIZE_FORMAT " " SIZE_FORMAT, 95 ts->get_value(), status->get_value(), num_regions, region_size, protocol_version); 96 if (num_regions > 0) { 97 ls.print(JLONG_FORMAT, regions[0]->get_value()); 98 } 99 for (uint i = 1; i < num_regions; ++i) { 100 ls.print(" " JLONG_FORMAT, regions[i]->get_value()); 101 } 102 ls.cr(); 103 } 104 } 105 106 void ShenandoahHeapRegionCounters::update() { 107 if (ShenandoahRegionSampling) { 108 jlong current = nanos_to_millis(os::javaTimeNanos()); 109 jlong last = _last_sample_millis; 110 if (current - last > ShenandoahRegionSamplingRate && Atomic::cmpxchg(&_last_sample_millis, last, current) == last) { 111 112 ShenandoahHeap* heap = ShenandoahHeap::heap(); 113 _status->set_value(encode_heap_status(heap)); 114 _timestamp->set_value(os::elapsed_counter()); 115 116 { 117 ShenandoahHeapLocker locker(heap->lock()); 118 size_t rs = ShenandoahHeapRegion::region_size_bytes(); 119 size_t num_regions = heap->num_regions(); 120 for (uint i = 0; i < num_regions; i++) { 121 ShenandoahHeapRegion* r = heap->get_region(i); 122 jlong data = 0; 123 data |= ((100 * r->used() / rs) & PERCENT_MASK) << USED_SHIFT; 124 data |= ((100 * r->get_live_data_bytes() / rs) & PERCENT_MASK) << LIVE_SHIFT; 125 data |= ((100 * r->get_tlab_allocs() / rs) & PERCENT_MASK) << TLAB_SHIFT; 126 data |= ((100 * r->get_gclab_allocs() / rs) & PERCENT_MASK) << GCLAB_SHIFT; 127 data |= ((100 * r->get_plab_allocs() / rs) & PERCENT_MASK) << PLAB_SHIFT; 128 data |= ((100 * r->get_shared_allocs() / rs) & PERCENT_MASK) << SHARED_SHIFT; 129 130 data |= (r->age() & AGE_MASK) << AGE_SHIFT; 131 data |= (r->affiliation() & AFFILIATION_MASK) << AFFILIATION_SHIFT; 132 data |= (r->state_ordinal() & STATUS_MASK) << STATUS_SHIFT; 133 _regions_data[i]->set_value(data); 134 } 135 136 // If logging enabled, dump current region snapshot to log file 137 write_snapshot(_regions_data, _timestamp, _status, num_regions, rs >> 10, VERSION_NUMBER); 138 } 139 } 140 } 141 } 142 143 static int encode_phase(ShenandoahHeap* heap) { 144 if (heap->is_evacuation_in_progress() || heap->is_full_gc_move_in_progress()) { 145 return 2; 146 } 147 if (heap->is_update_refs_in_progress() || heap->is_full_gc_move_in_progress()) { 148 return 3; 149 } 150 if (heap->is_concurrent_mark_in_progress() || heap->is_full_gc_in_progress()) { 151 return 1; 152 } 153 assert(heap->is_idle(), "What is it doing?"); 154 return 0; 155 } 156 157 static int get_generation_shift(ShenandoahGeneration* generation) { 158 switch (generation->type()) { 159 case NON_GEN: 160 case GLOBAL: 161 return 0; 162 case OLD: 163 return 2; 164 case YOUNG: 165 return 4; 166 default: 167 ShouldNotReachHere(); 168 return -1; 169 } 170 } 171 172 jlong ShenandoahHeapRegionCounters::encode_heap_status(ShenandoahHeap* heap) { 173 174 if (heap->is_idle() && !heap->is_full_gc_in_progress()) { 175 return 0; 176 } 177 178 jlong status = 0; 179 if (!heap->mode()->is_generational()) { 180 status = encode_phase(heap); 181 } else { 182 int phase = encode_phase(heap); 183 ShenandoahGeneration* generation = heap->active_generation(); 184 assert(generation != nullptr, "Expected active generation in this mode."); 185 int shift = get_generation_shift(generation); 186 status |= ((phase & 0x3) << shift); 187 if (heap->is_concurrent_old_mark_in_progress()) { 188 status |= (1 << 2); 189 } 190 log_develop_trace(gc)("%s, phase=%u, old_mark=%s, status=" JLONG_FORMAT, 191 generation->name(), phase, BOOL_TO_STR(heap->is_concurrent_old_mark_in_progress()), status); 192 } 193 194 if (heap->is_degenerated_gc_in_progress()) { 195 status |= (1 << 6); 196 } 197 if (heap->is_full_gc_in_progress()) { 198 status |= (1 << 7); 199 } 200 201 return status; 202 }