1 /*
2  * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #include "precompiled.hpp"
26 
27 #include "gc/shenandoah/shenandoahNumberSeq.hpp"
28 #include "runtime/atomic.hpp"
29 
HdrSeq()30 HdrSeq::HdrSeq() {
31   _hdr = NEW_C_HEAP_ARRAY(int*, MagBuckets, mtInternal);
32   for (int c = 0; c < MagBuckets; c++) {
33     _hdr[c] = NULL;
34   }
35 }
36 
~HdrSeq()37 HdrSeq::~HdrSeq() {
38   for (int c = 0; c < MagBuckets; c++) {
39     int* sub = _hdr[c];
40     if (sub != NULL) {
41       FREE_C_HEAP_ARRAY(int, sub);
42     }
43   }
44   FREE_C_HEAP_ARRAY(int*, _hdr);
45 }
46 
add(double val)47 void HdrSeq::add(double val) {
48   if (val < 0) {
49     assert (false, "value (%8.2f) is not negative", val);
50     val = 0;
51   }
52 
53   NumberSeq::add(val);
54 
55   double v = val;
56   int mag;
57   if (v > 0) {
58     mag = 0;
59     while (v > 1) {
60       mag++;
61       v /= 10;
62     }
63     while (v < 0.1) {
64       mag--;
65       v *= 10;
66     }
67   } else {
68     mag = MagMinimum;
69   }
70 
71   int bucket = -MagMinimum + mag;
72   int sub_bucket = (int) (v * ValBuckets);
73 
74   // Defensively saturate for product bits:
75   if (bucket < 0) {
76     assert (false, "bucket index (%d) underflow for value (%8.2f)", bucket, val);
77     bucket = 0;
78   }
79 
80   if (bucket >= MagBuckets) {
81     assert (false, "bucket index (%d) overflow for value (%8.2f)", bucket, val);
82     bucket = MagBuckets - 1;
83   }
84 
85   if (sub_bucket < 0) {
86     assert (false, "sub-bucket index (%d) underflow for value (%8.2f)", sub_bucket, val);
87     sub_bucket = 0;
88   }
89 
90   if (sub_bucket >= ValBuckets) {
91     assert (false, "sub-bucket index (%d) overflow for value (%8.2f)", sub_bucket, val);
92     sub_bucket = ValBuckets - 1;
93   }
94 
95   int* b = _hdr[bucket];
96   if (b == NULL) {
97     b = NEW_C_HEAP_ARRAY(int, ValBuckets, mtInternal);
98     for (int c = 0; c < ValBuckets; c++) {
99       b[c] = 0;
100     }
101     _hdr[bucket] = b;
102   }
103   b[sub_bucket]++;
104 }
105 
percentile(double level) const106 double HdrSeq::percentile(double level) const {
107   // target should be non-zero to find the first sample
108   int target = MAX2(1, (int) (level * num() / 100));
109   int cnt = 0;
110   for (int mag = 0; mag < MagBuckets; mag++) {
111     if (_hdr[mag] != NULL) {
112       for (int val = 0; val < ValBuckets; val++) {
113         cnt += _hdr[mag][val];
114         if (cnt >= target) {
115           return pow(10.0, MagMinimum + mag) * val / ValBuckets;
116         }
117       }
118     }
119   }
120   return maximum();
121 }
122 
BinaryMagnitudeSeq()123 BinaryMagnitudeSeq::BinaryMagnitudeSeq() {
124   _mags = NEW_C_HEAP_ARRAY(size_t, BitsPerSize_t, mtInternal);
125   clear();
126 }
127 
~BinaryMagnitudeSeq()128 BinaryMagnitudeSeq::~BinaryMagnitudeSeq() {
129   FREE_C_HEAP_ARRAY(size_t, _mags);
130 }
131 
clear()132 void BinaryMagnitudeSeq::clear() {
133   for (int c = 0; c < BitsPerSize_t; c++) {
134     _mags[c] = 0;
135   }
136   _sum = 0;
137 }
138 
add(size_t val)139 void BinaryMagnitudeSeq::add(size_t val) {
140   Atomic::add(&_sum, val);
141 
142   int mag = log2_intptr(val) + 1;
143 
144   // Defensively saturate for product bits:
145   if (mag < 0) {
146     assert (false, "bucket index (%d) underflow for value (" SIZE_FORMAT ")", mag, val);
147     mag = 0;
148   }
149 
150   if (mag >= BitsPerSize_t) {
151     assert (false, "bucket index (%d) overflow for value (" SIZE_FORMAT ")", mag, val);
152     mag = BitsPerSize_t - 1;
153   }
154 
155   Atomic::add(&_mags[mag], (size_t)1);
156 }
157 
level(int level) const158 size_t BinaryMagnitudeSeq::level(int level) const {
159   if (0 <= level && level < BitsPerSize_t) {
160     return _mags[level];
161   } else {
162     return 0;
163   }
164 }
165 
num() const166 size_t BinaryMagnitudeSeq::num() const {
167   size_t r = 0;
168   for (int c = 0; c < BitsPerSize_t; c++) {
169     r += _mags[c];
170   }
171   return r;
172 }
173 
sum() const174 size_t BinaryMagnitudeSeq::sum() const {
175   return _sum;
176 }
177 
min_level() const178 int BinaryMagnitudeSeq::min_level() const {
179   for (int c = 0; c < BitsPerSize_t; c++) {
180     if (_mags[c] != 0) {
181       return c;
182     }
183   }
184   return BitsPerSize_t - 1;
185 }
186 
max_level() const187 int BinaryMagnitudeSeq::max_level() const {
188   for (int c = BitsPerSize_t - 1; c > 0; c--) {
189     if (_mags[c] != 0) {
190       return c;
191     }
192   }
193   return 0;
194 }
195