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 #include "precompiled.hpp" 26 27 #include "gc/shenandoah/shenandoahGeneration.hpp" 28 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 29 #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" 30 #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" 31 #include "gc/shenandoah/shenandoahHeapRegionCounters.hpp" 32 #include "logging/logStream.hpp" 33 #include "memory/resourceArea.hpp" 34 #include "runtime/atomic.hpp" 35 #include "runtime/perfData.inline.hpp" 36 #include "utilities/defaultStream.hpp" 37 38 ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : 39 _last_sample_millis(0) 40 { 41 if (UsePerfData && ShenandoahRegionSampling) { 42 EXCEPTION_MARK; 43 ResourceMark rm; 44 ShenandoahHeap* heap = ShenandoahHeap::heap(); 45 size_t num_regions = heap->num_regions(); 46 const char* cns = PerfDataManager::name_space("shenandoah", "regions"); 47 _name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtGC); 48 strcpy(_name_space, cns); // copy cns into _name_space 49 50 const char* cname = PerfDataManager::counter_name(_name_space, "timestamp"); 51 _timestamp = PerfDataManager::create_long_variable(SUN_GC, cname, PerfData::U_None, CHECK); 52 53 cname = PerfDataManager::counter_name(_name_space, "max_regions"); 54 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, num_regions, CHECK); 55 56 cname = PerfDataManager::counter_name(_name_space, "protocol_version"); //creating new protocol_version 57 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, VERSION_NUMBER, CHECK); 58 59 cname = PerfDataManager::counter_name(_name_space, "region_size"); 60 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, ShenandoahHeapRegion::region_size_bytes() >> 10, CHECK); 61 62 cname = PerfDataManager::counter_name(_name_space, "status"); 63 _status = PerfDataManager::create_long_variable(SUN_GC, cname, 64 PerfData::U_None, CHECK); 65 66 _regions_data = NEW_C_HEAP_ARRAY(PerfVariable*, num_regions, mtGC); 67 // Initializing performance data resources for each region 68 for (uint i = 0; i < num_regions; i++) { 69 const char* reg_name = PerfDataManager::name_space(_name_space, "region", i); 70 const char* data_name = PerfDataManager::counter_name(reg_name, "data"); 71 const char* ns = PerfDataManager::ns_to_string(SUN_GC); 72 const char* fullname = PerfDataManager::counter_name(ns, data_name); 73 assert(!PerfDataManager::exists(fullname), "must not exist"); 74 _regions_data[i] = PerfDataManager::create_long_variable(SUN_GC, data_name, 75 PerfData::U_None, CHECK); 76 } 77 78 } 79 } 80 81 ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { 82 if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); 83 } 84 85 void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions, 86 PerfLongVariable* ts, 87 PerfLongVariable* status, 88 size_t num_regions, 89 size_t region_size, size_t protocol_version) { 90 LogTarget(Trace, gc, region) lt; 91 if (lt.is_enabled()) { 92 ResourceMark rm; 93 LogStream ls(lt); 94 95 ls.print_cr(JLONG_FORMAT " " JLONG_FORMAT " " SIZE_FORMAT " " SIZE_FORMAT " " SIZE_FORMAT, 96 ts->get_value(), status->get_value(), num_regions, region_size, protocol_version); 97 if (num_regions > 0) { 98 ls.print(JLONG_FORMAT, regions[0]->get_value()); 99 } 100 for (uint i = 1; i < num_regions; ++i) { 101 ls.print(" " JLONG_FORMAT, regions[i]->get_value()); 102 } 103 ls.cr(); 104 } 105 } 106 107 void ShenandoahHeapRegionCounters::update() { 108 if (ShenandoahRegionSampling) { 109 jlong current = nanos_to_millis(os::javaTimeNanos()); 110 jlong last = _last_sample_millis; 111 if (current - last > ShenandoahRegionSamplingRate && Atomic::cmpxchg(&_last_sample_millis, last, current) == last) { 112 113 ShenandoahHeap* heap = ShenandoahHeap::heap(); 114 _status->set_value(encode_heap_status(heap)); 115 _timestamp->set_value(os::elapsed_counter()); 116 117 { 118 ShenandoahHeapLocker locker(heap->lock()); 119 size_t rs = ShenandoahHeapRegion::region_size_bytes(); 120 size_t num_regions = heap->num_regions(); 121 for (uint i = 0; i < num_regions; i++) { 122 ShenandoahHeapRegion* r = heap->get_region(i); 123 jlong data = 0; 124 data |= ((100 * r->used() / rs) & PERCENT_MASK) << USED_SHIFT; 125 data |= ((100 * r->get_live_data_bytes() / rs) & PERCENT_MASK) << LIVE_SHIFT; 126 data |= ((100 * r->get_tlab_allocs() / rs) & PERCENT_MASK) << TLAB_SHIFT; 127 data |= ((100 * r->get_gclab_allocs() / rs) & PERCENT_MASK) << GCLAB_SHIFT; 128 data |= ((100 * r->get_plab_allocs() / rs) & PERCENT_MASK) << PLAB_SHIFT; 129 data |= ((100 * r->get_shared_allocs() / rs) & PERCENT_MASK) << SHARED_SHIFT; 130 131 data |= (r->age() & AGE_MASK) << AGE_SHIFT; 132 data |= (r->affiliation() & AFFILIATION_MASK) << AFFILIATION_SHIFT; 133 data |= (r->state_ordinal() & STATUS_MASK) << STATUS_SHIFT; 134 _regions_data[i]->set_value(data); 135 } 136 137 // If logging enabled, dump current region snapshot to log file 138 write_snapshot(_regions_data, _timestamp, _status, num_regions, rs >> 10, VERSION_NUMBER); 139 } 140 } 141 } 142 } 143 144 static int encode_phase(ShenandoahHeap* heap) { 145 if (heap->is_evacuation_in_progress() || heap->is_full_gc_move_in_progress()) { 146 return 2; 147 } 148 if (heap->is_update_refs_in_progress() || heap->is_full_gc_move_in_progress()) { 149 return 3; 150 } 151 if (heap->is_concurrent_mark_in_progress() || heap->is_full_gc_in_progress()) { 152 return 1; 153 } 154 assert(heap->is_idle(), "What is it doing?"); 155 return 0; 156 } 157 158 static int get_generation_shift(ShenandoahGeneration* generation) { 159 switch (generation->type()) { 160 case NON_GEN: 161 case GLOBAL: 162 return 0; 163 case OLD: 164 return 2; 165 case YOUNG: 166 return 4; 167 default: 168 ShouldNotReachHere(); 169 return -1; 170 } 171 } 172 173 jlong ShenandoahHeapRegionCounters::encode_heap_status(ShenandoahHeap* heap) { 174 175 if (heap->is_idle() && !heap->is_full_gc_in_progress()) { 176 return 0; 177 } 178 179 jlong status = 0; 180 if (!heap->mode()->is_generational()) { 181 status = encode_phase(heap); 182 } else { 183 int phase = encode_phase(heap); 184 ShenandoahGeneration* generation = heap->active_generation(); 185 assert(generation != nullptr, "Expected active generation in this mode."); 186 int shift = get_generation_shift(generation); 187 status |= ((phase & 0x3) << shift); 188 if (heap->is_concurrent_old_mark_in_progress()) { 189 status |= (1 << 2); 190 } 191 log_develop_trace(gc)("%s, phase=%u, old_mark=%s, status=" JLONG_FORMAT, 192 generation->name(), phase, BOOL_TO_STR(heap->is_concurrent_old_mark_in_progress()), status); 193 } 194 195 if (heap->is_degenerated_gc_in_progress()) { 196 status |= (1 << 6); 197 } 198 if (heap->is_full_gc_in_progress()) { 199 status |= (1 << 7); 200 } 201 202 return status; 203 }