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); // copy cns into _name_space 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"); //creating new 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, 76 PerfData::U_None, CHECK); 77 } 78 79 } 80 } 81 82 ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { 83 if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); 84 } 85 86 void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions, 87 PerfLongVariable* ts, 88 PerfLongVariable* status, 89 size_t num_regions, 90 size_t region_size, size_t protocol_version) { 91 LogTarget(Trace, gc, region) lt; 92 if (lt.is_enabled()) { 93 ResourceMark rm; 94 LogStream ls(lt); 95 96 ls.print_cr(JLONG_FORMAT " " JLONG_FORMAT " " SIZE_FORMAT " " SIZE_FORMAT " " SIZE_FORMAT, 97 ts->get_value(), status->get_value(), num_regions, region_size, protocol_version); 98 if (num_regions > 0) { 99 ls.print(JLONG_FORMAT, regions[0]->get_value()); 100 } 101 for (uint i = 1; i < num_regions; ++i) { 102 ls.print(" " JLONG_FORMAT, regions[i]->get_value()); 103 } 104 ls.cr(); 105 } 106 } 107 108 void ShenandoahHeapRegionCounters::update() { 109 if (ShenandoahRegionSampling) { 110 jlong current = nanos_to_millis(os::javaTimeNanos()); 111 jlong last = _last_sample_millis; 112 if (current - last > ShenandoahRegionSamplingRate && Atomic::cmpxchg(&_last_sample_millis, last, current) == last) { 113 114 ShenandoahHeap* heap = ShenandoahHeap::heap(); 115 _status->set_value(encode_heap_status(heap)); 116 _timestamp->set_value(os::elapsed_counter()); 117 118 { 119 ShenandoahHeapLocker locker(heap->lock()); 120 size_t rs = ShenandoahHeapRegion::region_size_bytes(); 121 size_t num_regions = heap->num_regions(); 122 for (uint i = 0; i < num_regions; i++) { 123 ShenandoahHeapRegion* r = heap->get_region(i); 124 jlong data = 0; 125 data |= ((100 * r->used() / rs) & PERCENT_MASK) << USED_SHIFT; 126 data |= ((100 * r->get_live_data_bytes() / rs) & PERCENT_MASK) << LIVE_SHIFT; 127 data |= ((100 * r->get_tlab_allocs() / rs) & PERCENT_MASK) << TLAB_SHIFT; 128 data |= ((100 * r->get_gclab_allocs() / rs) & PERCENT_MASK) << GCLAB_SHIFT; 129 data |= ((100 * r->get_plab_allocs() / rs) & PERCENT_MASK) << PLAB_SHIFT; 130 data |= ((100 * r->get_shared_allocs() / rs) & PERCENT_MASK) << SHARED_SHIFT; 131 132 data |= (r->age() & AGE_MASK) << AGE_SHIFT; 133 data |= (r->affiliation() & AFFILIATION_MASK) << AFFILIATION_SHIFT; 134 data |= (r->state_ordinal() & STATUS_MASK) << STATUS_SHIFT; 135 _regions_data[i]->set_value(data); 136 } 137 138 // If logging enabled, dump current region snapshot to log file 139 write_snapshot(_regions_data, _timestamp, _status, num_regions, rs >> 10, VERSION_NUMBER); 140 } 141 } 142 } 143 } 144 145 static int encode_phase(ShenandoahHeap* heap) { 146 if (heap->is_evacuation_in_progress() || heap->is_full_gc_move_in_progress()) { 147 return 2; 148 } 149 if (heap->is_update_refs_in_progress() || heap->is_full_gc_move_in_progress()) { 150 return 3; 151 } 152 if (heap->is_concurrent_mark_in_progress() || heap->is_full_gc_in_progress()) { 153 return 1; 154 } 155 assert(heap->is_idle(), "What is it doing?"); 156 return 0; 157 } 158 159 static int get_generation_shift(ShenandoahGeneration* generation) { 160 switch (generation->type()) { 161 case NON_GEN: 162 case GLOBAL: 163 return 0; 164 case OLD: 165 return 2; 166 case YOUNG: 167 return 4; 168 default: 169 ShouldNotReachHere(); 170 return -1; 171 } 172 } 173 174 jlong ShenandoahHeapRegionCounters::encode_heap_status(ShenandoahHeap* heap) { 175 176 if (heap->is_idle() && !heap->is_full_gc_in_progress()) { 177 return 0; 178 } 179 180 jlong status = 0; 181 if (!heap->mode()->is_generational()) { 182 status = encode_phase(heap); 183 } else { 184 int phase = encode_phase(heap); 185 ShenandoahGeneration* generation = heap->active_generation(); 186 assert(generation != nullptr, "Expected active generation in this mode."); 187 int shift = get_generation_shift(generation); 188 status |= ((phase & 0x3) << shift); 189 if (heap->is_concurrent_old_mark_in_progress()) { 190 status |= (1 << 2); 191 } 192 log_develop_trace(gc)("%s, phase=%u, old_mark=%s, status=" JLONG_FORMAT, 193 generation->name(), phase, BOOL_TO_STR(heap->is_concurrent_old_mark_in_progress()), status); 194 } 195 196 if (heap->is_degenerated_gc_in_progress()) { 197 status |= (1 << 6); 198 } 199 if (heap->is_full_gc_in_progress()) { 200 status |= (1 << 7); 201 } 202 203 return status; 204 }