|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /* Various JS utility functions. */ |
|
8 |
|
9 #include "jsutil.h" |
|
10 |
|
11 #include "mozilla/Assertions.h" |
|
12 #include "mozilla/MathAlgorithms.h" |
|
13 #include "mozilla/PodOperations.h" |
|
14 |
|
15 #include <stdio.h> |
|
16 |
|
17 #include "jstypes.h" |
|
18 |
|
19 #ifdef WIN32 |
|
20 # include "jswin.h" |
|
21 #endif |
|
22 |
|
23 #include "js/Utility.h" |
|
24 |
|
25 using namespace js; |
|
26 |
|
27 using mozilla::CeilingLog2Size; |
|
28 using mozilla::PodArrayZero; |
|
29 |
|
30 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) |
|
31 /* For JS_OOM_POSSIBLY_FAIL in jsutil.h. */ |
|
32 JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations = UINT32_MAX; |
|
33 JS_PUBLIC_DATA(uint32_t) OOM_counter = 0; |
|
34 #endif |
|
35 |
|
36 /* |
|
37 * Checks the assumption that JS_FUNC_TO_DATA_PTR and JS_DATA_TO_FUNC_PTR |
|
38 * macros uses to implement casts between function and data pointers. |
|
39 */ |
|
40 JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)())); |
|
41 |
|
42 JS_PUBLIC_API(void) |
|
43 JS_Assert(const char *s, const char *file, int ln) |
|
44 { |
|
45 MOZ_ReportAssertionFailure(s, file, ln); |
|
46 MOZ_CRASH(); |
|
47 } |
|
48 |
|
49 #ifdef __linux__ |
|
50 |
|
51 #include <malloc.h> |
|
52 #include <stdlib.h> |
|
53 |
|
54 namespace js { |
|
55 |
|
56 // This function calls all the vanilla heap allocation functions. It is never |
|
57 // called, and exists purely to help config/check_vanilla_allocations.py. See |
|
58 // that script for more details. |
|
59 extern void |
|
60 AllTheNonBasicVanillaNewAllocations() |
|
61 { |
|
62 // posix_memalign and aligned_alloc aren't available on all Linux |
|
63 // configurations. |
|
64 //char *q; |
|
65 //posix_memalign((void**)&q, 16, 16); |
|
66 |
|
67 intptr_t p = |
|
68 intptr_t(malloc(16)) + |
|
69 intptr_t(calloc(1, 16)) + |
|
70 intptr_t(realloc(nullptr, 16)) + |
|
71 intptr_t(new char) + |
|
72 intptr_t(new char) + |
|
73 intptr_t(new char) + |
|
74 intptr_t(new char[16]) + |
|
75 intptr_t(memalign(16, 16)) + |
|
76 //intptr_t(q) + |
|
77 //intptr_t(aligned_alloc(16, 16)) + |
|
78 intptr_t(valloc(4096)) + |
|
79 intptr_t(strdup("dummy")); |
|
80 |
|
81 printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away |
|
82 |
|
83 free((int*)p); // this would crash if ever actually called |
|
84 |
|
85 MOZ_CRASH(); |
|
86 } |
|
87 |
|
88 } // namespace js |
|
89 |
|
90 #endif // __linux__ |
|
91 |
|
92 #ifdef JS_BASIC_STATS |
|
93 |
|
94 #include <math.h> |
|
95 |
|
96 /* |
|
97 * Histogram bins count occurrences of values <= the bin label, as follows: |
|
98 * |
|
99 * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more |
|
100 * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more |
|
101 * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more |
|
102 * |
|
103 * We wish to count occurrences of 0 and 1 values separately, always. |
|
104 */ |
|
105 static uint32_t |
|
106 BinToVal(unsigned logscale, unsigned bin) |
|
107 { |
|
108 JS_ASSERT(bin <= 10); |
|
109 if (bin <= 1 || logscale == 0) |
|
110 return bin; |
|
111 --bin; |
|
112 if (logscale == 2) |
|
113 return JS_BIT(bin); |
|
114 JS_ASSERT(logscale == 10); |
|
115 return uint32_t(pow(10.0, (double) bin)); |
|
116 } |
|
117 |
|
118 static unsigned |
|
119 ValToBin(unsigned logscale, uint32_t val) |
|
120 { |
|
121 unsigned bin; |
|
122 |
|
123 if (val <= 1) |
|
124 return val; |
|
125 bin = (logscale == 10) |
|
126 ? (unsigned) ceil(log10((double) val)) |
|
127 : (logscale == 2) |
|
128 ? (unsigned) CeilingLog2Size(val) |
|
129 : val; |
|
130 return Min(bin, 10U); |
|
131 } |
|
132 |
|
133 void |
|
134 JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val) |
|
135 { |
|
136 unsigned oldscale, newscale, bin; |
|
137 double mean; |
|
138 |
|
139 ++bs->num; |
|
140 if (bs->max < val) |
|
141 bs->max = val; |
|
142 bs->sum += val; |
|
143 bs->sqsum += (double)val * val; |
|
144 |
|
145 oldscale = bs->logscale; |
|
146 if (oldscale != 10) { |
|
147 mean = bs->sum / bs->num; |
|
148 if (bs->max > 16 && mean > 8) { |
|
149 newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2; |
|
150 if (newscale != oldscale) { |
|
151 uint32_t newhist[11], newbin; |
|
152 |
|
153 PodArrayZero(newhist); |
|
154 for (bin = 0; bin <= 10; bin++) { |
|
155 newbin = ValToBin(newscale, BinToVal(oldscale, bin)); |
|
156 newhist[newbin] += bs->hist[bin]; |
|
157 } |
|
158 js_memcpy(bs->hist, newhist, sizeof bs->hist); |
|
159 bs->logscale = newscale; |
|
160 } |
|
161 } |
|
162 } |
|
163 |
|
164 bin = ValToBin(bs->logscale, val); |
|
165 ++bs->hist[bin]; |
|
166 } |
|
167 |
|
168 double |
|
169 JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double *sigma) |
|
170 { |
|
171 double var; |
|
172 |
|
173 if (num == 0 || sum == 0) { |
|
174 *sigma = 0; |
|
175 return 0; |
|
176 } |
|
177 |
|
178 var = num * sqsum - sum * sum; |
|
179 if (var < 0 || num == 1) |
|
180 var = 0; |
|
181 else |
|
182 var /= (double)num * (num - 1); |
|
183 |
|
184 /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */ |
|
185 *sigma = (var != 0) ? sqrt(var) : 0; |
|
186 return sum / num; |
|
187 } |
|
188 |
|
189 void |
|
190 JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp) |
|
191 { |
|
192 double mean, sigma; |
|
193 |
|
194 mean = JS_MeanAndStdDevBS(bs, &sigma); |
|
195 fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n", |
|
196 title, mean, sigma, (unsigned long) bs->max); |
|
197 JS_DumpHistogram(bs, fp); |
|
198 } |
|
199 |
|
200 void |
|
201 JS_DumpHistogram(JSBasicStats *bs, FILE *fp) |
|
202 { |
|
203 unsigned bin; |
|
204 uint32_t cnt, max; |
|
205 double sum, mean; |
|
206 |
|
207 for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) { |
|
208 cnt = bs->hist[bin]; |
|
209 if (max < cnt) |
|
210 max = cnt; |
|
211 sum += cnt; |
|
212 } |
|
213 mean = sum / cnt; |
|
214 for (bin = 0; bin <= 10; bin++) { |
|
215 unsigned val = BinToVal(bs->logscale, bin); |
|
216 unsigned end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1); |
|
217 cnt = bs->hist[bin]; |
|
218 if (val + 1 == end) |
|
219 fprintf(fp, " [%6u]", val); |
|
220 else if (end != 0) |
|
221 fprintf(fp, "[%6u, %6u]", val, end - 1); |
|
222 else |
|
223 fprintf(fp, "[%6u, +inf]", val); |
|
224 fprintf(fp, ": %8u ", cnt); |
|
225 if (cnt != 0) { |
|
226 if (max > 1e6 && mean > 1e3) |
|
227 cnt = uint32_t(ceil(log10((double) cnt))); |
|
228 else if (max > 16 && mean > 8) |
|
229 cnt = CeilingLog2Size(cnt); |
|
230 for (unsigned i = 0; i < cnt; i++) |
|
231 putc('*', fp); |
|
232 } |
|
233 putc('\n', fp); |
|
234 } |
|
235 } |
|
236 |
|
237 #endif /* JS_BASIC_STATS */ |