js/src/jit/PerfSpewer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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 #include "jit/PerfSpewer.h"
     9 #if defined(__linux__)
    10 # include <unistd.h>
    11 #endif
    13 #ifdef JS_ION_PERF
    14 # include "jit/IonSpewer.h"
    15 # include "jit/LinearScan.h"
    16 # include "jit/LIR.h"
    17 # include "jit/MIR.h"
    18 # include "jit/MIRGraph.h"
    19 #endif
    21 // perf expects its data to be in a file /tmp/perf-PID.map, but for Android
    22 // and B2G the map files are written to /data/local/tmp/perf-PID.map
    23 //
    24 // Except that Android 4.3 no longer allows the browser to write to /data/local/tmp/
    25 // so also try /sdcard/.
    27 #ifndef PERF_SPEW_DIR
    28 # if defined(__ANDROID__)
    29 #  define PERF_SPEW_DIR "/data/local/tmp/"
    30 #  define PERF_SPEW_DIR_2 "/sdcard/"
    31 # else
    32 #  define PERF_SPEW_DIR "/tmp/"
    33 # endif
    34 #endif
    36 using namespace js;
    37 using namespace js::jit;
    39 #define PERF_MODE_NONE  1
    40 #define PERF_MODE_FUNC  2
    41 #define PERF_MODE_BLOCK 3
    43 #ifdef JS_ION_PERF
    45 static uint32_t PerfMode = 0;
    47 static bool PerfChecked = false;
    49 static FILE *PerfFilePtr = nullptr;
    51 #ifdef JS_THREADSAFE
    52 # include "jslock.h"
    53 static PRLock *PerfMutex;
    54 #endif
    56 static bool
    57 openPerfMap(const char *dir)
    58 {
    59     const ssize_t bufferSize = 256;
    60     char filenameBuffer[bufferSize];
    62     if (snprintf(filenameBuffer, bufferSize, "%sperf-%d.map", dir, getpid()) >= bufferSize)
    63         return false;
    65     JS_ASSERT(!PerfFilePtr);
    66     PerfFilePtr = fopen(filenameBuffer, "a");
    68     if (!PerfFilePtr)
    69         return false;
    71     return true;
    72 }
    74 void
    75 js::jit::CheckPerf() {
    76     if (!PerfChecked) {
    77         const char *env = getenv("IONPERF");
    78         if (env == nullptr) {
    79             PerfMode = PERF_MODE_NONE;
    80             fprintf(stderr, "Warning: JIT perf reporting requires IONPERF set to \"block\" or \"func\". ");
    81             fprintf(stderr, "Perf mapping will be deactivated.\n");
    82         } else if (!strcmp(env, "none")) {
    83             PerfMode = PERF_MODE_NONE;
    84         } else if (!strcmp(env, "block")) {
    85             PerfMode = PERF_MODE_BLOCK;
    86         } else if (!strcmp(env, "func")) {
    87             PerfMode = PERF_MODE_FUNC;
    88         } else {
    89             fprintf(stderr, "Use IONPERF=func to record at function granularity\n");
    90             fprintf(stderr, "Use IONPERF=block to record at basic block granularity\n");
    91             fprintf(stderr, "\n");
    92             fprintf(stderr, "Be advised that using IONPERF will cause all scripts\n");
    93             fprintf(stderr, "to be leaked.\n");
    94             exit(0);
    95         }
    97         if (PerfMode != PERF_MODE_NONE) {
    98 #ifdef JS_THREADSAFE
    99             PerfMutex = PR_NewLock();
   100             if (!PerfMutex)
   101                 MOZ_CRASH();
   102 #endif
   104             if (openPerfMap(PERF_SPEW_DIR)) {
   105                 PerfChecked = true;
   106                 return;
   107             }
   109 #if defined(__ANDROID__)
   110             if (openPerfMap(PERF_SPEW_DIR_2)) {
   111                 PerfChecked = true;
   112                 return;
   113             }
   114 #endif
   115             fprintf(stderr, "Failed to open perf map file.  Disabling IONPERF.\n");
   116             PerfMode = PERF_MODE_NONE;
   117         }
   118         PerfChecked = true;
   119     }
   120 }
   122 bool
   123 js::jit::PerfBlockEnabled() {
   124     JS_ASSERT(PerfMode);
   125     return PerfMode == PERF_MODE_BLOCK;
   126 }
   128 bool
   129 js::jit::PerfFuncEnabled() {
   130     JS_ASSERT(PerfMode);
   131     return PerfMode == PERF_MODE_FUNC;
   132 }
   134 static bool
   135 lockPerfMap(void)
   136 {
   137     if (!PerfEnabled())
   138         return false;
   140 #ifdef JS_THREADSAFE
   141     PR_Lock(PerfMutex);
   142 #endif
   144     JS_ASSERT(PerfFilePtr);
   145     return true;
   146 }
   148 static void
   149 unlockPerfMap()
   150 {
   151     JS_ASSERT(PerfFilePtr);
   152     fflush(PerfFilePtr);
   153 #ifdef JS_THREADSAFE
   154     PR_Unlock(PerfMutex);
   155 #endif
   156 }
   158 uint32_t PerfSpewer::nextFunctionIndex = 0;
   160 bool
   161 PerfSpewer::startBasicBlock(MBasicBlock *blk,
   162                             MacroAssembler &masm)
   163 {
   164     if (!PerfBlockEnabled())
   165         return true;
   167     const char *filename = blk->info().script()->filename();
   168     unsigned lineNumber, columnNumber;
   169     if (blk->pc()) {
   170         lineNumber = PCToLineNumber(blk->info().script(),
   171                                     blk->pc(),
   172                                     &columnNumber);
   173     } else {
   174         lineNumber = 0;
   175         columnNumber = 0;
   176     }
   177     Record r(filename, lineNumber, columnNumber, blk->id());
   178     masm.bind(&r.start);
   179     return basicBlocks_.append(r);
   180 }
   182 bool
   183 PerfSpewer::endBasicBlock(MacroAssembler &masm)
   184 {
   185     if (!PerfBlockEnabled())
   186         return true;
   188     masm.bind(&basicBlocks_.back().end);
   189     return true;
   190 }
   192 bool
   193 PerfSpewer::noteEndInlineCode(MacroAssembler &masm)
   194 {
   195     if (!PerfBlockEnabled())
   196         return true;
   198     masm.bind(&endInlineCode);
   199     return true;
   200 }
   202 void
   203 PerfSpewer::writeProfile(JSScript *script,
   204                          JitCode *code,
   205                          MacroAssembler &masm)
   206 {
   207     if (PerfFuncEnabled()) {
   208         if (!lockPerfMap())
   209             return;
   211         uint32_t thisFunctionIndex = nextFunctionIndex++;
   213         size_t size = code->instructionsSize();
   214         if (size > 0) {
   215             fprintf(PerfFilePtr, "%zx %zx %s:%d: Func%02d\n",
   216                     reinterpret_cast<uintptr_t>(code->raw()),
   217                     size,
   218                     script->filename(),
   219                     script->lineno(),
   220                     thisFunctionIndex);
   221         }
   222         unlockPerfMap();
   223         return;
   224     }
   226     if (PerfBlockEnabled() && basicBlocks_.length() > 0) {
   227         if (!lockPerfMap())
   228             return;
   230         uint32_t thisFunctionIndex = nextFunctionIndex++;
   231         uintptr_t funcStart = uintptr_t(code->raw());
   232         uintptr_t funcEndInlineCode = funcStart + masm.actualOffset(endInlineCode.offset());
   233         uintptr_t funcEnd = funcStart + code->instructionsSize();
   235         // function begins with the prologue, which is located before the first basic block
   236         size_t prologueSize = masm.actualOffset(basicBlocks_[0].start.offset());
   238         if (prologueSize > 0) {
   239             fprintf(PerfFilePtr, "%zx %zx %s:%d: Func%02d-Prologue\n",
   240                     funcStart, prologueSize, script->filename(), script->lineno(), thisFunctionIndex);
   241         }
   243         uintptr_t cur = funcStart + prologueSize;
   244         for (uint32_t i = 0; i < basicBlocks_.length(); i++) {
   245             Record &r = basicBlocks_[i];
   247             uintptr_t blockStart = funcStart + masm.actualOffset(r.start.offset());
   248             uintptr_t blockEnd = funcStart + masm.actualOffset(r.end.offset());
   250             JS_ASSERT(cur <= blockStart);
   251             if (cur < blockStart) {
   252                 fprintf(PerfFilePtr, "%zx %zx %s:%d: Func%02d-Block?\n",
   253                         static_cast<uintptr_t>(cur),
   254                         static_cast<uintptr_t>(blockStart - cur),
   255                         script->filename(), script->lineno(),
   256                         thisFunctionIndex);
   257             }
   258             cur = blockEnd;
   260             size_t size = blockEnd - blockStart;
   262             if (size > 0) {
   263                 fprintf(PerfFilePtr, "%zx %zx %s:%d:%d: Func%02d-Block%d\n",
   264                         static_cast<uintptr_t>(blockStart), size,
   265                         r.filename, r.lineNumber, r.columnNumber,
   266                         thisFunctionIndex, r.id);
   267             }
   268         }
   270         JS_ASSERT(cur <= funcEndInlineCode);
   271         if (cur < funcEndInlineCode) {
   272             fprintf(PerfFilePtr, "%zx %zx %s:%d: Func%02d-Epilogue\n",
   273                     cur, funcEndInlineCode - cur,
   274                     script->filename(), script->lineno(),
   275                     thisFunctionIndex);
   276         }
   278         JS_ASSERT(funcEndInlineCode <= funcEnd);
   279         if (funcEndInlineCode < funcEnd) {
   280             fprintf(PerfFilePtr, "%zx %zx %s:%d: Func%02d-OOL\n",
   281                     funcEndInlineCode, funcEnd - funcEndInlineCode,
   282                     script->filename(), script->lineno(),
   283                     thisFunctionIndex);
   284         }
   286         unlockPerfMap();
   287         return;
   288     }
   289 }
   291 void
   292 js::jit::writePerfSpewerBaselineProfile(JSScript *script, JitCode *code)
   293 {
   294     if (!PerfEnabled())
   295         return;
   297     if (!lockPerfMap())
   298         return;
   300     size_t size = code->instructionsSize();
   301     if (size > 0) {
   302         fprintf(PerfFilePtr, "%zx %zx %s:%d: Baseline\n",
   303                 reinterpret_cast<uintptr_t>(code->raw()),
   304                 size, script->filename(), script->lineno());
   305     }
   307     unlockPerfMap();
   308 }
   310 void
   311 js::jit::writePerfSpewerJitCodeProfile(JitCode *code, const char *msg)
   312 {
   313     if (!code || !PerfEnabled())
   314         return;
   316     if (!lockPerfMap())
   317         return;
   319     size_t size = code->instructionsSize();
   320     if (size > 0) {
   321         fprintf(PerfFilePtr, "%zx %zx %s (%p 0x%zx)\n",
   322                 reinterpret_cast<uintptr_t>(code->raw()),
   323                 size, msg, code->raw(), size);
   324     }
   326     unlockPerfMap();
   327 }
   329 void
   330 js::jit::writePerfSpewerAsmJSFunctionMap(uintptr_t base, uintptr_t size,
   331                                          const char *filename, unsigned lineno, unsigned colIndex,
   332                                          const char *funcName)
   333 {
   334     if (!PerfFuncEnabled() || size == 0U)
   335         return;
   337     if (!lockPerfMap())
   338         return;
   340     fprintf(PerfFilePtr, "%zx %zx %s:%d:%d: Function %s\n", base, size, filename, lineno, colIndex, funcName);
   342     unlockPerfMap();
   343 }
   345 bool
   346 AsmJSPerfSpewer::startBasicBlock(MBasicBlock *blk, MacroAssembler &masm)
   347 {
   348     if (!PerfBlockEnabled())
   349         return true;
   351     Record r("", blk->lineno(), blk->columnIndex(), blk->id()); // filename is retrieved later
   352     masm.bind(&r.start);
   353     return basicBlocks_.append(r);
   354 }
   356 void
   357 AsmJSPerfSpewer::noteBlocksOffsets()
   358 {
   359     if (!PerfBlockEnabled())
   360         return;
   362     for (uint32_t i = 0; i < basicBlocks_.length(); i++) {
   363         Record &r = basicBlocks_[i];
   364         r.startOffset = r.start.offset();
   365         r.endOffset = r.end.offset();
   366     }
   367 }
   369 void
   370 js::jit::writePerfSpewerAsmJSBlocksMap(uintptr_t baseAddress, size_t funcStartOffset,
   371                                        size_t funcEndInlineOffset, size_t funcSize,
   372                                        const char *filename, const char *funcName,
   373                                        const js::jit::BasicBlocksVector &basicBlocks)
   374 {
   375     if (!PerfBlockEnabled() || basicBlocks.empty())
   376         return;
   378     if (!lockPerfMap())
   379         return;
   381     // function begins with the prologue, which is located before the first basic block
   382     size_t prologueSize = basicBlocks[0].startOffset - funcStartOffset;
   383     size_t cur = baseAddress + funcStartOffset + prologueSize;
   384     size_t funcEndInlineCode = baseAddress + funcEndInlineOffset;
   385     size_t funcEnd = baseAddress + funcStartOffset + funcSize;
   387     if (prologueSize > 0) {
   388         fprintf(PerfFilePtr, "%zx %zx %s: Function %s - Prologue\n",
   389                 baseAddress + funcStartOffset, prologueSize, filename, funcName);
   390     }
   392     for (uint32_t i = 0; i < basicBlocks.length(); i++) {
   393         const Record &r = basicBlocks[i];
   395         size_t blockStart = baseAddress + r.startOffset;
   396         size_t blockEnd = baseAddress + r.endOffset;
   398         JS_ASSERT(cur <= blockStart);
   399         if (cur < blockStart) {
   400             fprintf(PerfFilePtr, "%zx %zx %s: Function %s - unknown block\n",
   401                     cur, blockStart - cur,
   402                     filename,
   403                     funcName);
   404         }
   405         cur = blockEnd;
   407         size_t size = blockEnd - blockStart;
   408         if (size > 0) {
   409             fprintf(PerfFilePtr, "%zx %zx %s:%d:%d: Function %s - Block %d\n",
   410                     blockStart, size,
   411                     filename, r.lineNumber, r.columnNumber,
   412                     funcName, r.id);
   413         }
   414     }
   416     JS_ASSERT(cur <= funcEndInlineCode);
   417     if (cur < funcEndInlineCode)
   418         fprintf(PerfFilePtr, "%zx %zx %s: Function %s - Epilogue\n",
   419                 cur, funcEndInlineCode - cur, filename, funcName);
   421     JS_ASSERT(funcEndInlineCode <= funcEnd);
   422     if (funcEndInlineCode < funcEnd) {
   423         fprintf(PerfFilePtr, "%zx %zx %s: Function %s - OOL\n",
   424                 funcEndInlineCode, funcEnd - funcEndInlineCode, filename, funcName);
   425     }
   427     unlockPerfMap();
   428 }
   430 void
   431 js::jit::writePerfSpewerAsmJSEntriesAndExits(uintptr_t base, size_t size)
   432 {
   433     if (size == 0)
   434         return;
   436     if (!lockPerfMap())
   437         return;
   439     fprintf(PerfFilePtr, "%zx %zx AsmJS Entries and Exits (0x%zx 0x%zx)\n", base, size, base, size);
   441     unlockPerfMap();
   442 }
   444 #endif // defined (JS_ION_PERF)

mercurial