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 }