Line data Source code
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 : #include "mozilla/ThreadLocal.h"
15 :
16 : #include <stdio.h>
17 :
18 : #include "jstypes.h"
19 :
20 : #include "vm/HelperThreads.h"
21 :
22 : #ifdef WIN32
23 : # include "jswin.h"
24 : #endif
25 :
26 : #include "js/Utility.h"
27 :
28 : using namespace js;
29 :
30 : using mozilla::CeilingLog2Size;
31 : using mozilla::PodArrayZero;
32 :
33 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
34 : /* For OOM testing functionality in Utility.h. */
35 : namespace js {
36 :
37 : mozilla::Atomic<AutoEnterOOMUnsafeRegion*> AutoEnterOOMUnsafeRegion::owner_;
38 :
39 : namespace oom {
40 :
41 : JS_PUBLIC_DATA(uint32_t) targetThread = 0;
42 : MOZ_THREAD_LOCAL(uint32_t) threadType;
43 : JS_PUBLIC_DATA(uint64_t) maxAllocations = UINT64_MAX;
44 : JS_PUBLIC_DATA(uint64_t) counter = 0;
45 : JS_PUBLIC_DATA(bool) failAlways = true;
46 :
47 : bool
48 3 : InitThreadType(void) {
49 3 : return threadType.init();
50 : }
51 :
52 : void
53 58 : SetThreadType(ThreadType type) {
54 58 : threadType.set(type);
55 58 : }
56 :
57 : uint32_t
58 0 : GetThreadType(void) {
59 0 : return threadType.get();
60 : }
61 :
62 : void
63 0 : SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always) {
64 0 : MOZ_ASSERT(counter + allocations > counter);
65 0 : MOZ_ASSERT(thread > js::oom::THREAD_TYPE_NONE && thread < js::oom::THREAD_TYPE_MAX);
66 0 : targetThread = thread;
67 0 : maxAllocations = counter + allocations;
68 0 : failAlways = always;
69 0 : }
70 :
71 : void
72 0 : ResetSimulatedOOM() {
73 0 : if (targetThread != THREAD_TYPE_NONE && targetThread != THREAD_TYPE_COOPERATING)
74 0 : HelperThreadState().waitForAllThreads();
75 0 : targetThread = THREAD_TYPE_NONE;
76 0 : maxAllocations = UINT64_MAX;
77 0 : failAlways = false;
78 0 : }
79 :
80 :
81 : } // namespace oom
82 : } // namespace js
83 : #endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
84 :
85 : JS_PUBLIC_API(void)
86 0 : JS_Assert(const char* s, const char* file, int ln)
87 : {
88 0 : MOZ_ReportAssertionFailure(s, file, ln);
89 0 : MOZ_CRASH();
90 : }
91 :
92 : #ifdef __linux__
93 :
94 : #include <malloc.h>
95 : #include <stdlib.h>
96 :
97 : namespace js {
98 :
99 : // This function calls all the vanilla heap allocation functions. It is never
100 : // called, and exists purely to help config/check_vanilla_allocations.py. See
101 : // that script for more details.
102 : extern MOZ_COLD void
103 0 : AllTheNonBasicVanillaNewAllocations()
104 : {
105 : // posix_memalign and aligned_alloc aren't available on all Linux
106 : // configurations.
107 : // valloc was deprecated in Android 5.0
108 : //char* q;
109 : //posix_memalign((void**)&q, 16, 16);
110 :
111 : intptr_t p =
112 0 : intptr_t(malloc(16)) +
113 0 : intptr_t(calloc(1, 16)) +
114 0 : intptr_t(realloc(nullptr, 16)) +
115 0 : intptr_t(new char) +
116 0 : intptr_t(new char) +
117 0 : intptr_t(new char) +
118 0 : intptr_t(new char[16]) +
119 0 : intptr_t(memalign(16, 16)) +
120 : //intptr_t(q) +
121 : //intptr_t(aligned_alloc(16, 16)) +
122 : //intptr_t(valloc(4096)) +
123 0 : intptr_t(strdup("dummy"));
124 :
125 0 : printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away
126 :
127 0 : free((int*)p); // this would crash if ever actually called
128 :
129 0 : MOZ_CRASH();
130 : }
131 :
132 : } // namespace js
133 :
134 : #endif // __linux__
135 :
136 : #ifdef JS_BASIC_STATS
137 :
138 : #include <math.h>
139 :
140 : /*
141 : * Histogram bins count occurrences of values <= the bin label, as follows:
142 : *
143 : * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more
144 : * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more
145 : * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more
146 : *
147 : * We wish to count occurrences of 0 and 1 values separately, always.
148 : */
149 : static uint32_t
150 0 : BinToVal(unsigned logscale, unsigned bin)
151 : {
152 0 : MOZ_ASSERT(bin <= 10);
153 0 : if (bin <= 1 || logscale == 0)
154 0 : return bin;
155 0 : --bin;
156 0 : if (logscale == 2)
157 0 : return JS_BIT(bin);
158 0 : MOZ_ASSERT(logscale == 10);
159 0 : return uint32_t(pow(10.0, (double) bin));
160 : }
161 :
162 : static unsigned
163 0 : ValToBin(unsigned logscale, uint32_t val)
164 : {
165 : unsigned bin;
166 :
167 0 : if (val <= 1)
168 0 : return val;
169 0 : bin = (logscale == 10)
170 0 : ? (unsigned) ceil(log10((double) val))
171 : : (logscale == 2)
172 0 : ? (unsigned) CeilingLog2Size(val)
173 : : val;
174 0 : return Min(bin, 10U);
175 : }
176 :
177 : void
178 0 : JS_BasicStatsAccum(JSBasicStats* bs, uint32_t val)
179 : {
180 : unsigned oldscale, newscale, bin;
181 : double mean;
182 :
183 0 : ++bs->num;
184 0 : if (bs->max < val)
185 0 : bs->max = val;
186 0 : bs->sum += val;
187 0 : bs->sqsum += (double)val * val;
188 :
189 0 : oldscale = bs->logscale;
190 0 : if (oldscale != 10) {
191 0 : mean = bs->sum / bs->num;
192 0 : if (bs->max > 16 && mean > 8) {
193 0 : newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2;
194 0 : if (newscale != oldscale) {
195 : uint32_t newhist[11], newbin;
196 :
197 0 : PodArrayZero(newhist);
198 0 : for (bin = 0; bin <= 10; bin++) {
199 0 : newbin = ValToBin(newscale, BinToVal(oldscale, bin));
200 0 : newhist[newbin] += bs->hist[bin];
201 : }
202 0 : js_memcpy(bs->hist, newhist, sizeof bs->hist);
203 0 : bs->logscale = newscale;
204 : }
205 : }
206 : }
207 :
208 0 : bin = ValToBin(bs->logscale, val);
209 0 : ++bs->hist[bin];
210 0 : }
211 :
212 : double
213 0 : JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double* sigma)
214 : {
215 : double var;
216 :
217 0 : if (num == 0 || sum == 0) {
218 0 : *sigma = 0;
219 0 : return 0;
220 : }
221 :
222 0 : var = num * sqsum - sum * sum;
223 0 : if (var < 0 || num == 1)
224 0 : var = 0;
225 : else
226 0 : var /= (double)num * (num - 1);
227 :
228 : /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
229 0 : *sigma = (var != 0) ? sqrt(var) : 0;
230 0 : return sum / num;
231 : }
232 :
233 : void
234 0 : JS_DumpBasicStats(JSBasicStats* bs, const char* title, FILE* fp)
235 : {
236 : double mean, sigma;
237 :
238 0 : mean = JS_MeanAndStdDevBS(bs, &sigma);
239 0 : fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n",
240 0 : title, mean, sigma, (unsigned long) bs->max);
241 0 : JS_DumpHistogram(bs, fp);
242 0 : }
243 :
244 : void
245 0 : JS_DumpHistogram(JSBasicStats* bs, FILE* fp)
246 : {
247 : unsigned bin;
248 : uint32_t cnt, max;
249 : double sum, mean;
250 :
251 0 : for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) {
252 0 : cnt = bs->hist[bin];
253 0 : if (max < cnt)
254 0 : max = cnt;
255 0 : sum += cnt;
256 : }
257 0 : mean = sum / cnt;
258 0 : for (bin = 0; bin <= 10; bin++) {
259 0 : unsigned val = BinToVal(bs->logscale, bin);
260 0 : unsigned end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1);
261 0 : cnt = bs->hist[bin];
262 0 : if (val + 1 == end)
263 0 : fprintf(fp, " [%6u]", val);
264 0 : else if (end != 0)
265 0 : fprintf(fp, "[%6u, %6u]", val, end - 1);
266 : else
267 0 : fprintf(fp, "[%6u, +inf]", val);
268 0 : fprintf(fp, ": %8u ", cnt);
269 0 : if (cnt != 0) {
270 0 : if (max > 1e6 && mean > 1e3)
271 0 : cnt = uint32_t(ceil(log10((double) cnt)));
272 0 : else if (max > 16 && mean > 8)
273 0 : cnt = CeilingLog2Size(cnt);
274 0 : for (unsigned i = 0; i < cnt; i++)
275 0 : putc('*', fp);
276 : }
277 0 : putc('\n', fp);
278 : }
279 0 : }
280 :
281 : #endif /* JS_BASIC_STATS */
|