LCOV - code coverage report
Current view: top level - js/src/vm - TraceLoggingGraph.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 362 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

          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             : #include "vm/TraceLoggingGraph.h"
       8             : 
       9             : #ifdef XP_WIN
      10             : #include <process.h>
      11             : #define getpid _getpid
      12             : #else
      13             : #include <unistd.h>
      14             : #endif
      15             : 
      16             : #include "mozilla/EndianUtils.h"
      17             : #include "mozilla/MemoryReporting.h"
      18             : #include "mozilla/ScopeExit.h"
      19             : 
      20             : #include "jsstr.h"
      21             : 
      22             : #include "js/UniquePtr.h"
      23             : #include "threading/LockGuard.h"
      24             : #include "threading/Thread.h"
      25             : #include "vm/TraceLogging.h"
      26             : 
      27             : #ifndef DEFAULT_TRACE_LOG_DIR
      28             : # if defined(_WIN32)
      29             : #  define DEFAULT_TRACE_LOG_DIR "."
      30             : # else
      31             : #  define DEFAULT_TRACE_LOG_DIR "/tmp/"
      32             : # endif
      33             : #endif
      34             : 
      35             : using mozilla::MakeScopeExit;
      36             : using mozilla::NativeEndian;
      37             : 
      38             : TraceLoggerGraphState* traceLoggerGraphState = nullptr;
      39             : 
      40             : // gcc and clang have these in symcat.h, but MSVC does not.
      41             : #ifndef STRINGX
      42             : # define STRINGX(x) #x
      43             : #endif
      44             : #ifndef XSTRING
      45             : # define XSTRING(macro) STRINGX(macro)
      46             : #endif
      47             : 
      48             : #define MAX_LOGGERS 999
      49             : 
      50             : // Return a filename relative to the output directory. %u and %d substitutions
      51             : // are allowed, with %u standing for a full 32-bit number and %d standing for
      52             : // an up to 3-digit number.
      53             : static js::UniqueChars
      54             : MOZ_FORMAT_PRINTF(1, 2)
      55           0 : AllocTraceLogFilename(const char* pattern, ...) {
      56           0 :     js::UniqueChars filename;
      57             : 
      58             :     va_list ap;
      59             : 
      60           0 :     static const char* outdir = getenv("TLDIR") ? getenv("TLDIR") : DEFAULT_TRACE_LOG_DIR;
      61           0 :     size_t len = strlen(outdir) + 1; // "+ 1" is for the '/'
      62             : 
      63           0 :     for (const char* p = pattern; *p; p++) {
      64           0 :         if (*p == '%') {
      65           0 :             p++;
      66           0 :             if (*p == 'u')
      67           0 :                 len += sizeof("4294967295") - 1;
      68           0 :             else if (*p == 'd')
      69           0 :                 len += sizeof(XSTRING(MAX_LOGGERS)) - 1;
      70             :             else
      71           0 :                 MOZ_CRASH("Invalid format");
      72             :         } else {
      73           0 :             len++;
      74             :         }
      75             :     }
      76             : 
      77           0 :     len++; // For the terminating NUL.
      78             : 
      79           0 :     filename.reset((char*) js_malloc(len));
      80           0 :     if (!filename)
      81           0 :         return nullptr;
      82           0 :     char* rest = filename.get() + sprintf(filename.get(), "%s/", outdir);
      83             : 
      84           0 :     va_start(ap, pattern);
      85           0 :     int ret = vsnprintf(rest, len, pattern, ap);
      86           0 :     va_end(ap);
      87           0 :     if (ret < 0)
      88           0 :         return nullptr;
      89             : 
      90           0 :     MOZ_ASSERT(size_t(ret) <= len - (strlen(outdir) + 1),
      91             :                "overran TL filename buffer; %d given too large a value?");
      92             : 
      93           0 :     return filename;
      94             : }
      95             : 
      96             : bool
      97           0 : TraceLoggerGraphState::init()
      98             : {
      99           0 :     pid_ = (uint32_t) getpid();
     100             : 
     101           0 :     js::UniqueChars filename = AllocTraceLogFilename("tl-data.%u.json", pid_);
     102           0 :     out = fopen(filename.get(), "w");
     103           0 :     if (!out) {
     104           0 :         fprintf(stderr, "warning: failed to create TraceLogger output file %s\n", filename.get());
     105           0 :         return false;
     106             :     }
     107             : 
     108           0 :     fprintf(out, "[");
     109             : 
     110             :     // Write the latest tl-data.*.json file to tl-data.json.
     111             :     // In most cases that is the wanted file.
     112           0 :     js::UniqueChars masterFilename = AllocTraceLogFilename("tl-data.json");
     113           0 :     if (FILE* last = fopen(masterFilename.get(), "w")) {
     114           0 :         char *basename = strrchr(filename.get(), '/');
     115           0 :         basename = basename ? basename + 1 : filename.get();
     116           0 :         fprintf(last, "\"%s\"", basename);
     117           0 :         fclose(last);
     118             :     }
     119             : 
     120             : #ifdef DEBUG
     121           0 :     initialized = true;
     122             : #endif
     123           0 :     return true;
     124             : }
     125             : 
     126           0 : TraceLoggerGraphState::~TraceLoggerGraphState()
     127             : {
     128           0 :     if (out) {
     129           0 :         fprintf(out, "]");
     130           0 :         fclose(out);
     131           0 :         out = nullptr;
     132             :     }
     133             : 
     134             : #ifdef DEBUG
     135           0 :     initialized = false;
     136             : #endif
     137           0 : }
     138             : 
     139             : uint32_t
     140           0 : TraceLoggerGraphState::nextLoggerId()
     141             : {
     142           0 :     js::LockGuard<js::Mutex> guard(lock);
     143             : 
     144           0 :     MOZ_ASSERT(initialized);
     145             : 
     146           0 :     if (numLoggers > MAX_LOGGERS) {
     147             :         fputs("TraceLogging: Can't create more than " XSTRING(MAX_LOGGERS) " different loggers.",
     148           0 :               stderr);
     149           0 :         return uint32_t(-1);
     150             :     }
     151             : 
     152           0 :     if (numLoggers > 0) {
     153           0 :         int written = fprintf(out, ",\n");
     154           0 :         if (written < 0) {
     155           0 :             fprintf(stderr, "TraceLogging: Error while writing.\n");
     156           0 :             return uint32_t(-1);
     157             :         }
     158             :     }
     159             : 
     160           0 :     int written = fprintf(out, "{\"tree\":\"tl-tree.%u.%d.tl\", \"events\":\"tl-event.%u.%d.tl\", "
     161             :                                "\"dict\":\"tl-dict.%u.%d.json\", \"treeFormat\":\"64,64,31,1,32\"",
     162           0 :                           pid_, numLoggers, pid_, numLoggers, pid_, numLoggers);
     163             : 
     164           0 :     if (written > 0) {
     165             :         char threadName[16];
     166           0 :         js::ThisThread::GetName(threadName, sizeof(threadName));
     167           0 :         if (threadName[0])
     168           0 :             written = fprintf(out, ", \"threadName\":\"%s\"", threadName);
     169             :     }
     170             : 
     171           0 :     if (written > 0)
     172           0 :         written = fprintf(out, "}");
     173             : 
     174           0 :     if (written < 0) {
     175           0 :         fprintf(stderr, "TraceLogging: Error while writing.\n");
     176           0 :         return uint32_t(-1);
     177             :     }
     178             : 
     179           0 :     return numLoggers++;
     180             : }
     181             : 
     182             : size_t
     183           0 : TraceLoggerGraphState::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
     184             : {
     185           0 :     return 0;
     186             : }
     187             : 
     188             : static bool
     189           0 : EnsureTraceLoggerGraphState()
     190             : {
     191           0 :     if (MOZ_LIKELY(traceLoggerGraphState))
     192           0 :         return true;
     193             : 
     194           0 :     traceLoggerGraphState = js_new<TraceLoggerGraphState>();
     195           0 :     if (!traceLoggerGraphState)
     196           0 :         return false;
     197             : 
     198           0 :     if (!traceLoggerGraphState->init()) {
     199           0 :         js::DestroyTraceLoggerGraphState();
     200           0 :         return false;
     201             :     }
     202             : 
     203           0 :     return true;
     204             : }
     205             : 
     206             : size_t
     207           0 : js::SizeOfTraceLogGraphState(mozilla::MallocSizeOf mallocSizeOf)
     208             : {
     209           0 :     return traceLoggerGraphState ? traceLoggerGraphState->sizeOfIncludingThis(mallocSizeOf) : 0;
     210             : }
     211             : 
     212             : void
     213           0 : js::DestroyTraceLoggerGraphState()
     214             : {
     215           0 :     if (traceLoggerGraphState) {
     216           0 :         js_delete(traceLoggerGraphState);
     217           0 :         traceLoggerGraphState = nullptr;
     218             :     }
     219           0 : }
     220             : 
     221             : bool
     222           0 : TraceLoggerGraph::init(uint64_t startTimestamp)
     223             : {
     224           0 :     auto fail = MakeScopeExit([&] { failed = true; });
     225             : 
     226           0 :     if (!tree.init())
     227           0 :         return false;
     228           0 :     if (!stack.init())
     229           0 :         return false;
     230             : 
     231           0 :     if (!EnsureTraceLoggerGraphState())
     232           0 :         return false;
     233             : 
     234           0 :     uint32_t loggerId = traceLoggerGraphState->nextLoggerId();
     235           0 :     if (loggerId == uint32_t(-1))
     236           0 :         return false;
     237             : 
     238           0 :     uint32_t pid = traceLoggerGraphState->pid();
     239             : 
     240           0 :     js::UniqueChars dictFilename = AllocTraceLogFilename("tl-dict.%u.%d.json", pid, loggerId);
     241           0 :     dictFile = fopen(dictFilename.get(), "w");
     242           0 :     if (!dictFile)
     243           0 :         return false;
     244           0 :     auto cleanupDict = MakeScopeExit([&] { fclose(dictFile); dictFile = nullptr; });
     245             : 
     246           0 :     js::UniqueChars treeFilename = AllocTraceLogFilename("tl-tree.%u.%d.tl", pid, loggerId);
     247           0 :     treeFile = fopen(treeFilename.get(), "w+b");
     248           0 :     if (!treeFile)
     249           0 :         return false;
     250           0 :     auto cleanupTree = MakeScopeExit([&] { fclose(treeFile); treeFile = nullptr; });
     251             : 
     252           0 :     js::UniqueChars eventFilename = AllocTraceLogFilename("tl-event.%u.%d.tl", pid, loggerId);
     253           0 :     eventFile = fopen(eventFilename.get(), "wb");
     254           0 :     if (!eventFile)
     255           0 :         return false;
     256           0 :     auto cleanupEvent = MakeScopeExit([&] { fclose(eventFile); eventFile = nullptr; });
     257             : 
     258             :     // Create the top tree node and corresponding first stack item.
     259           0 :     TreeEntry& treeEntry = tree.pushUninitialized();
     260           0 :     treeEntry.setStart(startTimestamp);
     261           0 :     treeEntry.setStop(0);
     262           0 :     treeEntry.setTextId(0);
     263           0 :     treeEntry.setHasChildren(false);
     264           0 :     treeEntry.setNextId(0);
     265             : 
     266           0 :     StackEntry& stackEntry = stack.pushUninitialized();
     267           0 :     stackEntry.setTreeId(0);
     268           0 :     stackEntry.setLastChildId(0);
     269           0 :     stackEntry.setActive(true);
     270             : 
     271           0 :     if (fprintf(dictFile, "[") < 0) {
     272           0 :         fprintf(stderr, "TraceLogging: Error while writing.\n");
     273           0 :         return false;
     274             :     }
     275             : 
     276           0 :     fail.release();
     277           0 :     cleanupDict.release();
     278           0 :     cleanupTree.release();
     279           0 :     cleanupEvent.release();
     280             : 
     281           0 :     return true;
     282             : }
     283             : 
     284           0 : TraceLoggerGraph::~TraceLoggerGraph()
     285             : {
     286             :     // Write dictionary to disk
     287           0 :     if (dictFile) {
     288           0 :         int written = fprintf(dictFile, "]");
     289           0 :         if (written < 0)
     290           0 :             fprintf(stderr, "TraceLogging: Error while writing.\n");
     291           0 :         fclose(dictFile);
     292             : 
     293           0 :         dictFile = nullptr;
     294             :     }
     295             : 
     296           0 :     if (!failed && treeFile) {
     297             :         // Make sure every start entry has a corresponding stop value.
     298             :         // We temporarily enable logging for this. Stop doesn't need any extra data,
     299             :         // so is safe to do even when we have encountered OOM.
     300           0 :         enabled = true;
     301           0 :         while (stack.size() > 1)
     302           0 :             stopEvent(0);
     303           0 :         enabled = false;
     304             :     }
     305             : 
     306           0 :     if (!failed && !flush()) {
     307           0 :         fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
     308           0 :         enabled = false;
     309           0 :         failed = true;
     310             :     }
     311             : 
     312           0 :     if (treeFile) {
     313           0 :         fclose(treeFile);
     314           0 :         treeFile = nullptr;
     315             :     }
     316             : 
     317           0 :     if (eventFile) {
     318           0 :         fclose(eventFile);
     319           0 :         eventFile = nullptr;
     320             :     }
     321           0 : }
     322             : 
     323             : bool
     324           0 : TraceLoggerGraph::flush()
     325             : {
     326           0 :     MOZ_ASSERT(!failed);
     327             : 
     328           0 :     if (treeFile) {
     329             :         // Format data in big endian.
     330           0 :         for (size_t i = 0; i < tree.size(); i++)
     331           0 :             entryToBigEndian(&tree[i]);
     332             : 
     333           0 :         int success = fseek(treeFile, 0, SEEK_END);
     334           0 :         if (success != 0)
     335           0 :             return false;
     336             : 
     337           0 :         size_t bytesWritten = fwrite(tree.data(), sizeof(TreeEntry), tree.size(), treeFile);
     338           0 :         if (bytesWritten < tree.size())
     339           0 :             return false;
     340             : 
     341           0 :         treeOffset += tree.size();
     342           0 :         tree.clear();
     343             :     }
     344             : 
     345           0 :     return true;
     346             : }
     347             : 
     348             : void
     349           0 : TraceLoggerGraph::entryToBigEndian(TreeEntry* entry)
     350             : {
     351           0 :     entry->start_ = NativeEndian::swapToBigEndian(entry->start_);
     352           0 :     entry->stop_ = NativeEndian::swapToBigEndian(entry->stop_);
     353           0 :     uint32_t data = (entry->u.s.textId_ << 1) + entry->u.s.hasChildren_;
     354           0 :     entry->u.value_ = NativeEndian::swapToBigEndian(data);
     355           0 :     entry->nextId_ = NativeEndian::swapToBigEndian(entry->nextId_);
     356           0 : }
     357             : 
     358             : void
     359           0 : TraceLoggerGraph::entryToSystemEndian(TreeEntry* entry)
     360             : {
     361           0 :     entry->start_ = NativeEndian::swapFromBigEndian(entry->start_);
     362           0 :     entry->stop_ = NativeEndian::swapFromBigEndian(entry->stop_);
     363             : 
     364           0 :     uint32_t data = NativeEndian::swapFromBigEndian(entry->u.value_);
     365           0 :     entry->u.s.textId_ = data >> 1;
     366           0 :     entry->u.s.hasChildren_ = data & 0x1;
     367             : 
     368           0 :     entry->nextId_ = NativeEndian::swapFromBigEndian(entry->nextId_);
     369           0 : }
     370             : 
     371             : void
     372           0 : TraceLoggerGraph::startEvent(uint32_t id, uint64_t timestamp)
     373             : {
     374           0 :     if (failed || enabled == 0)
     375           0 :         return;
     376             : 
     377           0 :     if (!tree.hasSpaceForAdd()) {
     378           0 :         if (tree.size() >= treeSizeFlushLimit() || !tree.ensureSpaceBeforeAdd()) {
     379           0 :             if (!flush()) {
     380           0 :                 fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
     381           0 :                 enabled = false;
     382           0 :                 failed = true;
     383           0 :                 return;
     384             :             }
     385             :         }
     386             :     }
     387             : 
     388           0 :     if (!startEventInternal(id, timestamp)) {
     389           0 :         fprintf(stderr, "TraceLogging: Failed to start an event.\n");
     390           0 :         enabled = false;
     391           0 :         failed = true;
     392           0 :         return;
     393             :     }
     394             : }
     395             : 
     396             : TraceLoggerGraph::StackEntry&
     397           0 : TraceLoggerGraph::getActiveAncestor()
     398             : {
     399           0 :     uint32_t parentId = stack.lastEntryId();
     400           0 :     while (!stack[parentId].active())
     401           0 :         parentId--;
     402           0 :     return stack[parentId];
     403             : }
     404             : 
     405             : bool
     406           0 : TraceLoggerGraph::startEventInternal(uint32_t id, uint64_t timestamp)
     407             : {
     408           0 :     if (!stack.ensureSpaceBeforeAdd())
     409           0 :         return false;
     410             : 
     411             :     // Patch up the tree to be correct. There are two scenarios:
     412             :     // 1) Parent has no children yet. So update parent to include children.
     413             :     // 2) Parent has already children. Update last child to link to the new
     414             :     //    child.
     415           0 :     StackEntry& parent = getActiveAncestor();
     416             : #ifdef DEBUG
     417           0 :     TreeEntry entry;
     418           0 :     if (!getTreeEntry(parent.treeId(), &entry))
     419           0 :         return false;
     420             : #endif
     421             : 
     422           0 :     if (parent.lastChildId() == 0) {
     423           0 :         MOZ_ASSERT(!entry.hasChildren());
     424           0 :         MOZ_ASSERT(parent.treeId() == treeOffset + tree.size() - 1);
     425             : 
     426           0 :         if (!updateHasChildren(parent.treeId()))
     427           0 :             return false;
     428             :     } else {
     429           0 :         MOZ_ASSERT(entry.hasChildren());
     430             : 
     431           0 :         if (!updateNextId(parent.lastChildId(), tree.size() + treeOffset))
     432           0 :             return false;
     433             :     }
     434             : 
     435             :     // Add a new tree entry.
     436           0 :     TreeEntry& treeEntry = tree.pushUninitialized();
     437           0 :     treeEntry.setStart(timestamp);
     438           0 :     treeEntry.setStop(0);
     439           0 :     treeEntry.setTextId(id);
     440           0 :     treeEntry.setHasChildren(false);
     441           0 :     treeEntry.setNextId(0);
     442             : 
     443             :     // Add a new stack entry.
     444           0 :     StackEntry& stackEntry = stack.pushUninitialized();
     445           0 :     stackEntry.setTreeId(tree.lastEntryId() + treeOffset);
     446           0 :     stackEntry.setLastChildId(0);
     447           0 :     stackEntry.setActive(true);
     448             : 
     449             :     // Set the last child of the parent to this newly added entry.
     450           0 :     parent.setLastChildId(tree.lastEntryId() + treeOffset);
     451             : 
     452           0 :     return true;
     453             : }
     454             : 
     455             : void
     456           0 : TraceLoggerGraph::stopEvent(uint32_t id, uint64_t timestamp)
     457             : {
     458             : #ifdef DEBUG
     459           0 :     if (id != TraceLogger_Scripts &&
     460           0 :         id != TraceLogger_Engine &&
     461           0 :         stack.size() > 1 &&
     462           0 :         stack.lastEntry().active())
     463             :     {
     464           0 :         TreeEntry entry;
     465           0 :         MOZ_ASSERT(getTreeEntry(stack.lastEntry().treeId(), &entry));
     466           0 :         MOZ_ASSERT(entry.textId() == id);
     467             :     }
     468             : #endif
     469             : 
     470           0 :     stopEvent(timestamp);
     471           0 : }
     472             : 
     473             : void
     474           0 : TraceLoggerGraph::stopEvent(uint64_t timestamp)
     475             : {
     476           0 :     if (enabled && stack.lastEntry().active()) {
     477           0 :         if (!updateStop(stack.lastEntry().treeId(), timestamp)) {
     478           0 :             fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
     479           0 :             enabled = false;
     480           0 :             failed = true;
     481           0 :             return;
     482             :         }
     483             :     }
     484           0 :     if (stack.size() == 1) {
     485           0 :         if (!enabled)
     486           0 :             return;
     487             : 
     488             :         // Forcefully disable logging. We have no stack information anymore.
     489           0 :         logTimestamp(TraceLogger_Disable, timestamp);
     490           0 :         return;
     491             :     }
     492           0 :     stack.pop();
     493             : }
     494             : 
     495             : void
     496           0 : TraceLoggerGraph::logTimestamp(uint32_t id, uint64_t timestamp)
     497             : {
     498           0 :     if (failed)
     499           0 :         return;
     500             : 
     501           0 :     if (id == TraceLogger_Enable)
     502           0 :         enabled = true;
     503             : 
     504           0 :     if (!enabled)
     505           0 :         return;
     506             : 
     507           0 :     if (id == TraceLogger_Disable)
     508           0 :         disable(timestamp);
     509             : 
     510           0 :     MOZ_ASSERT(eventFile);
     511             : 
     512             :     // Format data in big endian
     513           0 :     timestamp = NativeEndian::swapToBigEndian(timestamp);
     514           0 :     id = NativeEndian::swapToBigEndian(id);
     515             : 
     516             :     // The layout of the event log in the log file is:
     517             :     // [timestamp, textId]
     518           0 :     size_t itemsWritten = 0;
     519           0 :     itemsWritten += fwrite(&timestamp, sizeof(uint64_t), 1, eventFile);
     520           0 :     itemsWritten += fwrite(&id, sizeof(uint32_t), 1, eventFile);
     521           0 :     if (itemsWritten < 2) {
     522           0 :         failed = true;
     523           0 :         enabled = false;
     524             :     }
     525             : }
     526             : 
     527             : bool
     528           0 : TraceLoggerGraph::getTreeEntry(uint32_t treeId, TreeEntry* entry)
     529             : {
     530             :     // Entry is still in memory
     531           0 :     if (treeId >= treeOffset) {
     532           0 :         *entry = tree[treeId - treeOffset];
     533           0 :         return true;
     534             :     }
     535             : 
     536           0 :     int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
     537           0 :     if (success != 0)
     538           0 :         return false;
     539             : 
     540           0 :     size_t itemsRead = fread((void*)entry, sizeof(TreeEntry), 1, treeFile);
     541           0 :     if (itemsRead < 1)
     542           0 :         return false;
     543             : 
     544           0 :     entryToSystemEndian(entry);
     545           0 :     return true;
     546             : }
     547             : 
     548             : bool
     549           0 : TraceLoggerGraph::saveTreeEntry(uint32_t treeId, TreeEntry* entry)
     550             : {
     551           0 :     int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
     552           0 :     if (success != 0)
     553           0 :         return false;
     554             : 
     555           0 :     entryToBigEndian(entry);
     556             : 
     557           0 :     size_t itemsWritten = fwrite(entry, sizeof(TreeEntry), 1, treeFile);
     558           0 :     if (itemsWritten < 1)
     559           0 :         return false;
     560             : 
     561           0 :     return true;
     562             : }
     563             : 
     564             : bool
     565           0 : TraceLoggerGraph::updateHasChildren(uint32_t treeId, bool hasChildren)
     566             : {
     567           0 :     if (treeId < treeOffset) {
     568           0 :         TreeEntry entry;
     569           0 :         if (!getTreeEntry(treeId, &entry))
     570           0 :             return false;
     571           0 :         entry.setHasChildren(hasChildren);
     572           0 :         if (!saveTreeEntry(treeId, &entry))
     573           0 :             return false;
     574           0 :         return true;
     575             :     }
     576             : 
     577           0 :     tree[treeId - treeOffset].setHasChildren(hasChildren);
     578           0 :     return true;
     579             : }
     580             : 
     581             : bool
     582           0 : TraceLoggerGraph::updateNextId(uint32_t treeId, uint32_t nextId)
     583             : {
     584           0 :     if (treeId < treeOffset) {
     585           0 :         TreeEntry entry;
     586           0 :         if (!getTreeEntry(treeId, &entry))
     587           0 :             return false;
     588           0 :         entry.setNextId(nextId);
     589           0 :         if (!saveTreeEntry(treeId, &entry))
     590           0 :             return false;
     591           0 :         return true;
     592             :     }
     593             : 
     594           0 :     tree[treeId - treeOffset].setNextId(nextId);
     595           0 :     return true;
     596             : }
     597             : 
     598             : bool
     599           0 : TraceLoggerGraph::updateStop(uint32_t treeId, uint64_t timestamp)
     600             : {
     601           0 :     if (treeId < treeOffset) {
     602           0 :         TreeEntry entry;
     603           0 :         if (!getTreeEntry(treeId, &entry))
     604           0 :             return false;
     605           0 :         entry.setStop(timestamp);
     606           0 :         if (!saveTreeEntry(treeId, &entry))
     607           0 :             return false;
     608           0 :         return true;
     609             :     }
     610             : 
     611           0 :     tree[treeId - treeOffset].setStop(timestamp);
     612           0 :     return true;
     613             : }
     614             : 
     615             : void
     616           0 : TraceLoggerGraph::disable(uint64_t timestamp)
     617             : {
     618           0 :     MOZ_ASSERT(enabled);
     619           0 :     while (stack.size() > 1)
     620           0 :         stopEvent(timestamp);
     621             : 
     622           0 :     enabled = false;
     623           0 : }
     624             : 
     625             : void
     626           0 : TraceLoggerGraph::log(ContinuousSpace<EventEntry>& events)
     627             : {
     628           0 :     for (uint32_t i = 0; i < events.size(); i++) {
     629           0 :         if (events[i].textId == TraceLogger_Stop)
     630           0 :             stopEvent(events[i].time);
     631           0 :         else if (TLTextIdIsTreeEvent(events[i].textId))
     632           0 :             startEvent(events[i].textId, events[i].time);
     633             :         else
     634           0 :             logTimestamp(events[i].textId, events[i].time);
     635             :     }
     636           0 : }
     637             : 
     638             : void
     639           0 : TraceLoggerGraph::addTextId(uint32_t id, const char* text)
     640             : {
     641           0 :     if (failed)
     642           0 :         return;
     643             : 
     644             :     // Assume ids are given in order. Which is currently true.
     645           0 :     MOZ_ASSERT(id == nextTextId_);
     646           0 :     nextTextId_++;
     647             : 
     648           0 :     if (id > 0) {
     649           0 :         int written = fprintf(dictFile, ",\n");
     650           0 :         if (written < 0) {
     651           0 :             failed = true;
     652           0 :             return;
     653             :         }
     654             :     }
     655             : 
     656           0 :     if (!js::FileEscapedString(dictFile, text, strlen(text), '"'))
     657           0 :         failed = true;
     658             : }
     659             : 
     660             : size_t
     661           0 : TraceLoggerGraph::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     662           0 :     size_t size = 0;
     663           0 :     size += tree.sizeOfExcludingThis(mallocSizeOf);
     664           0 :     size += stack.sizeOfExcludingThis(mallocSizeOf);
     665           0 :     return size;
     666             : }
     667             : 
     668             : size_t
     669           0 : TraceLoggerGraph::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     670           0 :     return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
     671             : }
     672             : 
     673             : #undef getpid

Generated by: LCOV version 1.13