michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Various JS utility functions. */ michael@0: michael@0: #include "jsutil.h" michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/MathAlgorithms.h" michael@0: #include "mozilla/PodOperations.h" michael@0: michael@0: #include michael@0: michael@0: #include "jstypes.h" michael@0: michael@0: #ifdef WIN32 michael@0: # include "jswin.h" michael@0: #endif michael@0: michael@0: #include "js/Utility.h" michael@0: michael@0: using namespace js; michael@0: michael@0: using mozilla::CeilingLog2Size; michael@0: using mozilla::PodArrayZero; michael@0: michael@0: #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) michael@0: /* For JS_OOM_POSSIBLY_FAIL in jsutil.h. */ michael@0: JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations = UINT32_MAX; michael@0: JS_PUBLIC_DATA(uint32_t) OOM_counter = 0; michael@0: #endif michael@0: michael@0: /* michael@0: * Checks the assumption that JS_FUNC_TO_DATA_PTR and JS_DATA_TO_FUNC_PTR michael@0: * macros uses to implement casts between function and data pointers. michael@0: */ michael@0: JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)())); michael@0: michael@0: JS_PUBLIC_API(void) michael@0: JS_Assert(const char *s, const char *file, int ln) michael@0: { michael@0: MOZ_ReportAssertionFailure(s, file, ln); michael@0: MOZ_CRASH(); michael@0: } michael@0: michael@0: #ifdef __linux__ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: namespace js { michael@0: michael@0: // This function calls all the vanilla heap allocation functions. It is never michael@0: // called, and exists purely to help config/check_vanilla_allocations.py. See michael@0: // that script for more details. michael@0: extern void michael@0: AllTheNonBasicVanillaNewAllocations() michael@0: { michael@0: // posix_memalign and aligned_alloc aren't available on all Linux michael@0: // configurations. michael@0: //char *q; michael@0: //posix_memalign((void**)&q, 16, 16); michael@0: michael@0: intptr_t p = michael@0: intptr_t(malloc(16)) + michael@0: intptr_t(calloc(1, 16)) + michael@0: intptr_t(realloc(nullptr, 16)) + michael@0: intptr_t(new char) + michael@0: intptr_t(new char) + michael@0: intptr_t(new char) + michael@0: intptr_t(new char[16]) + michael@0: intptr_t(memalign(16, 16)) + michael@0: //intptr_t(q) + michael@0: //intptr_t(aligned_alloc(16, 16)) + michael@0: intptr_t(valloc(4096)) + michael@0: intptr_t(strdup("dummy")); michael@0: michael@0: printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away michael@0: michael@0: free((int*)p); // this would crash if ever actually called michael@0: michael@0: MOZ_CRASH(); michael@0: } michael@0: michael@0: } // namespace js michael@0: michael@0: #endif // __linux__ michael@0: michael@0: #ifdef JS_BASIC_STATS michael@0: michael@0: #include michael@0: michael@0: /* michael@0: * Histogram bins count occurrences of values <= the bin label, as follows: michael@0: * michael@0: * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more michael@0: * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more michael@0: * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more michael@0: * michael@0: * We wish to count occurrences of 0 and 1 values separately, always. michael@0: */ michael@0: static uint32_t michael@0: BinToVal(unsigned logscale, unsigned bin) michael@0: { michael@0: JS_ASSERT(bin <= 10); michael@0: if (bin <= 1 || logscale == 0) michael@0: return bin; michael@0: --bin; michael@0: if (logscale == 2) michael@0: return JS_BIT(bin); michael@0: JS_ASSERT(logscale == 10); michael@0: return uint32_t(pow(10.0, (double) bin)); michael@0: } michael@0: michael@0: static unsigned michael@0: ValToBin(unsigned logscale, uint32_t val) michael@0: { michael@0: unsigned bin; michael@0: michael@0: if (val <= 1) michael@0: return val; michael@0: bin = (logscale == 10) michael@0: ? (unsigned) ceil(log10((double) val)) michael@0: : (logscale == 2) michael@0: ? (unsigned) CeilingLog2Size(val) michael@0: : val; michael@0: return Min(bin, 10U); michael@0: } michael@0: michael@0: void michael@0: JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val) michael@0: { michael@0: unsigned oldscale, newscale, bin; michael@0: double mean; michael@0: michael@0: ++bs->num; michael@0: if (bs->max < val) michael@0: bs->max = val; michael@0: bs->sum += val; michael@0: bs->sqsum += (double)val * val; michael@0: michael@0: oldscale = bs->logscale; michael@0: if (oldscale != 10) { michael@0: mean = bs->sum / bs->num; michael@0: if (bs->max > 16 && mean > 8) { michael@0: newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2; michael@0: if (newscale != oldscale) { michael@0: uint32_t newhist[11], newbin; michael@0: michael@0: PodArrayZero(newhist); michael@0: for (bin = 0; bin <= 10; bin++) { michael@0: newbin = ValToBin(newscale, BinToVal(oldscale, bin)); michael@0: newhist[newbin] += bs->hist[bin]; michael@0: } michael@0: js_memcpy(bs->hist, newhist, sizeof bs->hist); michael@0: bs->logscale = newscale; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bin = ValToBin(bs->logscale, val); michael@0: ++bs->hist[bin]; michael@0: } michael@0: michael@0: double michael@0: JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double *sigma) michael@0: { michael@0: double var; michael@0: michael@0: if (num == 0 || sum == 0) { michael@0: *sigma = 0; michael@0: return 0; michael@0: } michael@0: michael@0: var = num * sqsum - sum * sum; michael@0: if (var < 0 || num == 1) michael@0: var = 0; michael@0: else michael@0: var /= (double)num * (num - 1); michael@0: michael@0: /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */ michael@0: *sigma = (var != 0) ? sqrt(var) : 0; michael@0: return sum / num; michael@0: } michael@0: michael@0: void michael@0: JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp) michael@0: { michael@0: double mean, sigma; michael@0: michael@0: mean = JS_MeanAndStdDevBS(bs, &sigma); michael@0: fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n", michael@0: title, mean, sigma, (unsigned long) bs->max); michael@0: JS_DumpHistogram(bs, fp); michael@0: } michael@0: michael@0: void michael@0: JS_DumpHistogram(JSBasicStats *bs, FILE *fp) michael@0: { michael@0: unsigned bin; michael@0: uint32_t cnt, max; michael@0: double sum, mean; michael@0: michael@0: for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) { michael@0: cnt = bs->hist[bin]; michael@0: if (max < cnt) michael@0: max = cnt; michael@0: sum += cnt; michael@0: } michael@0: mean = sum / cnt; michael@0: for (bin = 0; bin <= 10; bin++) { michael@0: unsigned val = BinToVal(bs->logscale, bin); michael@0: unsigned end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1); michael@0: cnt = bs->hist[bin]; michael@0: if (val + 1 == end) michael@0: fprintf(fp, " [%6u]", val); michael@0: else if (end != 0) michael@0: fprintf(fp, "[%6u, %6u]", val, end - 1); michael@0: else michael@0: fprintf(fp, "[%6u, +inf]", val); michael@0: fprintf(fp, ": %8u ", cnt); michael@0: if (cnt != 0) { michael@0: if (max > 1e6 && mean > 1e3) michael@0: cnt = uint32_t(ceil(log10((double) cnt))); michael@0: else if (max > 16 && mean > 8) michael@0: cnt = CeilingLog2Size(cnt); michael@0: for (unsigned i = 0; i < cnt; i++) michael@0: putc('*', fp); michael@0: } michael@0: putc('\n', fp); michael@0: } michael@0: } michael@0: michael@0: #endif /* JS_BASIC_STATS */