1 /* 2 * Copyright (c) 2018, 2019, 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/shenandoahNumberSeq.hpp" 29 #include "runtime/atomic.hpp" 30 31 HdrSeq::HdrSeq() { 32 _hdr = NEW_C_HEAP_ARRAY(int*, MagBuckets, mtInternal); 33 for (int c = 0; c < MagBuckets; c++) { 34 _hdr[c] = nullptr; 35 } 36 } 37 38 HdrSeq::~HdrSeq() { 39 for (int c = 0; c < MagBuckets; c++) { 40 int* sub = _hdr[c]; 41 if (sub != nullptr) { 42 FREE_C_HEAP_ARRAY(int, sub); 43 } 44 } 45 FREE_C_HEAP_ARRAY(int*, _hdr); 46 } 47 48 void HdrSeq::add(double val) { 49 if (val < 0) { 50 assert (false, "value (%8.2f) is not negative", val); 51 val = 0; 52 } 53 54 NumberSeq::add(val); 55 56 double v = val; 57 int mag; 58 if (v > 0) { 59 mag = 0; 60 while (v >= 1) { 61 mag++; 62 v /= 10; 63 } 64 while (v < 0.1) { 65 mag--; 66 v *= 10; 67 } 68 } else { 69 mag = MagMinimum; 70 } 71 72 int bucket = -MagMinimum + mag; 73 int sub_bucket = (int) (v * ValBuckets); 74 75 // Defensively saturate for product bits 76 if (bucket < 0) { 77 assert (false, "bucket index (%d) underflow for value (%8.2f)", bucket, val); 78 bucket = 0; 79 } 80 81 if (bucket >= MagBuckets) { 82 assert (false, "bucket index (%d) overflow for value (%8.2f)", bucket, val); 83 bucket = MagBuckets - 1; 84 } 85 86 if (sub_bucket < 0) { 87 assert (false, "sub-bucket index (%d) underflow for value (%8.2f)", sub_bucket, val); 88 sub_bucket = 0; 89 } 90 91 if (sub_bucket >= ValBuckets) { 92 assert (false, "sub-bucket index (%d) overflow for value (%8.2f)", sub_bucket, val); 93 sub_bucket = ValBuckets - 1; 94 } 95 96 int* b = _hdr[bucket]; 97 if (b == nullptr) { 98 b = NEW_C_HEAP_ARRAY(int, ValBuckets, mtInternal); 99 for (int c = 0; c < ValBuckets; c++) { 100 b[c] = 0; 101 } 102 _hdr[bucket] = b; 103 } 104 b[sub_bucket]++; 105 } 106 107 double HdrSeq::percentile(double level) const { 108 // target should be non-zero to find the first sample 109 int target = MAX2(1, (int) (level * num() / 100)); 110 int cnt = 0; 111 for (int mag = 0; mag < MagBuckets; mag++) { 112 if (_hdr[mag] != nullptr) { 113 for (int val = 0; val < ValBuckets; val++) { 114 cnt += _hdr[mag][val]; 115 if (cnt >= target) { 116 return pow(10.0, MagMinimum + mag) * val / ValBuckets; 117 } 118 } 119 } 120 } 121 return maximum(); 122 } 123 124 void HdrSeq::add(const HdrSeq& other) { 125 if (other.num() == 0) { 126 // Other sequence is empty, return 127 return; 128 } 129 130 for (int mag = 0; mag < MagBuckets; mag++) { 131 int* other_bucket = other._hdr[mag]; 132 if (other_bucket == nullptr) { 133 // Nothing to do 134 continue; 135 } 136 int* bucket = _hdr[mag]; 137 if (bucket != nullptr) { 138 // Add into our bucket 139 for (int val = 0; val < ValBuckets; val++) { 140 bucket[val] += other_bucket[val]; 141 } 142 } else { 143 // Create our bucket and copy the contents over 144 bucket = NEW_C_HEAP_ARRAY(int, ValBuckets, mtInternal); 145 for (int val = 0; val < ValBuckets; val++) { 146 bucket[val] = other_bucket[val]; 147 } 148 _hdr[mag] = bucket; 149 } 150 } 151 152 // This is a hacky way to only update the fields we want. 153 // This inlines NumberSeq code without going into AbsSeq and 154 // dealing with decayed average/variance, which we do not 155 // know how to compute yet. 156 _last = other._last; 157 _maximum = MAX2(_maximum, other._maximum); 158 _sum += other._sum; 159 _sum_of_squares += other._sum_of_squares; 160 _num += other._num; 161 162 // Until JDK-8298902 is fixed, we taint the decaying statistics 163 _davg = NAN; 164 _dvariance = NAN; 165 } 166 167 void HdrSeq::clear() { 168 // Clear the storage 169 for (int mag = 0; mag < MagBuckets; mag++) { 170 int* bucket = _hdr[mag]; 171 if (bucket != nullptr) { 172 for (int c = 0; c < ValBuckets; c++) { 173 bucket[c] = 0; 174 } 175 } 176 } 177 178 // Clear other fields too 179 _last = 0; 180 _maximum = 0; 181 _sum = 0; 182 _sum_of_squares = 0; 183 _num = 0; 184 _davg = 0; 185 _dvariance = 0; 186 } 187 188 BinaryMagnitudeSeq::BinaryMagnitudeSeq() { 189 _mags = NEW_C_HEAP_ARRAY(size_t, BitsPerSize_t, mtInternal); 190 clear(); 191 } 192 193 BinaryMagnitudeSeq::~BinaryMagnitudeSeq() { 194 FREE_C_HEAP_ARRAY(size_t, _mags); 195 } 196 197 void BinaryMagnitudeSeq::clear() { 198 for (int c = 0; c < BitsPerSize_t; c++) { 199 _mags[c] = 0; 200 } 201 _sum = 0; 202 } 203 204 void BinaryMagnitudeSeq::add(size_t val) { 205 Atomic::add(&_sum, val); 206 207 int mag = log2i_graceful(val) + 1; 208 209 // Defensively saturate for product bits: 210 if (mag < 0) { 211 assert (false, "bucket index (%d) underflow for value (" SIZE_FORMAT ")", mag, val); 212 mag = 0; 213 } 214 215 if (mag >= BitsPerSize_t) { 216 assert (false, "bucket index (%d) overflow for value (" SIZE_FORMAT ")", mag, val); 217 mag = BitsPerSize_t - 1; 218 } 219 220 Atomic::add(&_mags[mag], (size_t)1); 221 } 222 223 size_t BinaryMagnitudeSeq::level(int level) const { 224 if (0 <= level && level < BitsPerSize_t) { 225 return _mags[level]; 226 } else { 227 return 0; 228 } 229 } 230 231 size_t BinaryMagnitudeSeq::num() const { 232 size_t r = 0; 233 for (int c = 0; c < BitsPerSize_t; c++) { 234 r += _mags[c]; 235 } 236 return r; 237 } 238 239 size_t BinaryMagnitudeSeq::sum() const { 240 return _sum; 241 } 242 243 int BinaryMagnitudeSeq::min_level() const { 244 for (int c = 0; c < BitsPerSize_t; c++) { 245 if (_mags[c] != 0) { 246 return c; 247 } 248 } 249 return BitsPerSize_t - 1; 250 } 251 252 int BinaryMagnitudeSeq::max_level() const { 253 for (int c = BitsPerSize_t - 1; c > 0; c--) { 254 if (_mags[c] != 0) { 255 return c; 256 } 257 } 258 return 0; 259 }