bb9f33df969f1c492ce83a5621012af211fef9b0
[gecko.git] / jsutil.cpp
blobbb9f33df969f1c492ce83a5621012af211fef9b0
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/. */
7 /* Various JS utility functions. */
9 #include "jsutil.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/MathAlgorithms.h"
13 #include "mozilla/PodOperations.h"
14 #include "mozilla/ThreadLocal.h"
16 #include <stdio.h>
18 #include "jstypes.h"
20 #include "vm/HelperThreads.h"
22 #ifdef WIN32
23 # include "jswin.h"
24 #endif
26 #include "js/Utility.h"
28 using namespace js;
30 using mozilla::CeilingLog2Size;
31 using mozilla::PodArrayZero;
33 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
34 /* For OOM testing functionality in Utility.h. */
35 namespace js {
37 mozilla::Atomic<AutoEnterOOMUnsafeRegion*> AutoEnterOOMUnsafeRegion::owner_;
39 namespace oom {
41 JS_PUBLIC_DATA(uint32_t) targetThread = 0;
42 JS_PUBLIC_DATA(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;
47 bool
48 InitThreadType(void) {
49 return threadType.init();
52 void
53 SetThreadType(ThreadType type) {
54 threadType.set(type);
57 uint32_t
58 GetThreadType(void) {
59 return threadType.get();
62 void
63 SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always) {
64 MOZ_ASSERT(counter + allocations > counter);
65 MOZ_ASSERT(thread > js::oom::THREAD_TYPE_NONE && thread < js::oom::THREAD_TYPE_MAX);
66 targetThread = thread;
67 maxAllocations = counter + allocations;
68 failAlways = always;
71 void
72 ResetSimulatedOOM() {
73 if (targetThread != THREAD_TYPE_NONE && targetThread != THREAD_TYPE_MAIN)
74 HelperThreadState().waitForAllThreads();
75 targetThread = THREAD_TYPE_NONE;
76 maxAllocations = UINT64_MAX;
77 failAlways = false;
81 } // namespace oom
82 } // namespace js
83 #endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
85 JS_PUBLIC_API(void)
86 JS_Assert(const char* s, const char* file, int ln)
88 MOZ_ReportAssertionFailure(s, file, ln);
89 MOZ_CRASH();
92 #ifdef __linux__
94 #include <malloc.h>
95 #include <stdlib.h>
97 namespace js {
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 AllTheNonBasicVanillaNewAllocations()
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);
111 intptr_t p =
112 intptr_t(malloc(16)) +
113 intptr_t(calloc(1, 16)) +
114 intptr_t(realloc(nullptr, 16)) +
115 intptr_t(new char) +
116 intptr_t(new char) +
117 intptr_t(new char) +
118 intptr_t(new char[16]) +
119 intptr_t(memalign(16, 16)) +
120 //intptr_t(q) +
121 //intptr_t(aligned_alloc(16, 16)) +
122 //intptr_t(valloc(4096)) +
123 intptr_t(strdup("dummy"));
125 printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away
127 free((int*)p); // this would crash if ever actually called
129 MOZ_CRASH();
132 } // namespace js
134 #endif // __linux__
136 #ifdef JS_BASIC_STATS
138 #include <math.h>
141 * Histogram bins count occurrences of values <= the bin label, as follows:
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
147 * We wish to count occurrences of 0 and 1 values separately, always.
149 static uint32_t
150 BinToVal(unsigned logscale, unsigned bin)
152 MOZ_ASSERT(bin <= 10);
153 if (bin <= 1 || logscale == 0)
154 return bin;
155 --bin;
156 if (logscale == 2)
157 return JS_BIT(bin);
158 MOZ_ASSERT(logscale == 10);
159 return uint32_t(pow(10.0, (double) bin));
162 static unsigned
163 ValToBin(unsigned logscale, uint32_t val)
165 unsigned bin;
167 if (val <= 1)
168 return val;
169 bin = (logscale == 10)
170 ? (unsigned) ceil(log10((double) val))
171 : (logscale == 2)
172 ? (unsigned) CeilingLog2Size(val)
173 : val;
174 return Min(bin, 10U);
177 void
178 JS_BasicStatsAccum(JSBasicStats* bs, uint32_t val)
180 unsigned oldscale, newscale, bin;
181 double mean;
183 ++bs->num;
184 if (bs->max < val)
185 bs->max = val;
186 bs->sum += val;
187 bs->sqsum += (double)val * val;
189 oldscale = bs->logscale;
190 if (oldscale != 10) {
191 mean = bs->sum / bs->num;
192 if (bs->max > 16 && mean > 8) {
193 newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2;
194 if (newscale != oldscale) {
195 uint32_t newhist[11], newbin;
197 PodArrayZero(newhist);
198 for (bin = 0; bin <= 10; bin++) {
199 newbin = ValToBin(newscale, BinToVal(oldscale, bin));
200 newhist[newbin] += bs->hist[bin];
202 js_memcpy(bs->hist, newhist, sizeof bs->hist);
203 bs->logscale = newscale;
208 bin = ValToBin(bs->logscale, val);
209 ++bs->hist[bin];
212 double
213 JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double* sigma)
215 double var;
217 if (num == 0 || sum == 0) {
218 *sigma = 0;
219 return 0;
222 var = num * sqsum - sum * sum;
223 if (var < 0 || num == 1)
224 var = 0;
225 else
226 var /= (double)num * (num - 1);
228 /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
229 *sigma = (var != 0) ? sqrt(var) : 0;
230 return sum / num;
233 void
234 JS_DumpBasicStats(JSBasicStats* bs, const char* title, FILE* fp)
236 double mean, sigma;
238 mean = JS_MeanAndStdDevBS(bs, &sigma);
239 fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n",
240 title, mean, sigma, (unsigned long) bs->max);
241 JS_DumpHistogram(bs, fp);
244 void
245 JS_DumpHistogram(JSBasicStats* bs, FILE* fp)
247 unsigned bin;
248 uint32_t cnt, max;
249 double sum, mean;
251 for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) {
252 cnt = bs->hist[bin];
253 if (max < cnt)
254 max = cnt;
255 sum += cnt;
257 mean = sum / cnt;
258 for (bin = 0; bin <= 10; bin++) {
259 unsigned val = BinToVal(bs->logscale, bin);
260 unsigned end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1);
261 cnt = bs->hist[bin];
262 if (val + 1 == end)
263 fprintf(fp, " [%6u]", val);
264 else if (end != 0)
265 fprintf(fp, "[%6u, %6u]", val, end - 1);
266 else
267 fprintf(fp, "[%6u, +inf]", val);
268 fprintf(fp, ": %8u ", cnt);
269 if (cnt != 0) {
270 if (max > 1e6 && mean > 1e3)
271 cnt = uint32_t(ceil(log10((double) cnt)));
272 else if (max > 16 && mean > 8)
273 cnt = CeilingLog2Size(cnt);
274 for (unsigned i = 0; i < cnt; i++)
275 putc('*', fp);
277 putc('\n', fp);
281 #endif /* JS_BASIC_STATS */