diff options
Diffstat (limited to 'js/src/vm/TraceLoggingGraph.h')
-rw-r--r-- | js/src/vm/TraceLoggingGraph.h | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/js/src/vm/TraceLoggingGraph.h b/js/src/vm/TraceLoggingGraph.h new file mode 100644 index 0000000000..39ddee03e9 --- /dev/null +++ b/js/src/vm/TraceLoggingGraph.h @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TraceLoggingGraph_h +#define TraceLoggingGraph_h + +#include "mozilla/MemoryReporting.h" +#include "mozilla/TimeStamp.h" + +#include "js/TypeDecls.h" +#include "vm/MutexIDs.h" +#include "vm/TraceLoggingTypes.h" + +// clang-format off +/* + * The output of a tracelogging session is saved in /tmp/tl-data.json. + * The format of that file is a JS array per tracelogger (=thread), with a map + * containing: + * - dict: Name of the file containing a json table with the log text. + * All other files only contain a index to this table when logging. + * - events: Name of the file containing a flat list of log events saved + * in binary format. + * (64bit: Time Stamp Counter, 32bit index to dict) + * - tree: Name of the file containing the events with duration. The content + * is already in a tree data structure. This is also saved in a + * binary file. + * - treeFormat: The format used to encode the tree. By default "64,64,31,1,32". + * There are currently no other formats to save the tree. + * - 64,64,31,1,32 signifies how many bytes are used for the different + * parts of the tree. + * => 64 bits: Time Stamp Counter of start of event. + * => 64 bits: Time Stamp Counter of end of event. + * => 31 bits: Index to dict file containing the log text. + * => 1 bit: Boolean signifying if this entry has children. + * When true, the child can be found just right after this + * entry. + * => 32 bits: Containing the ID of the next event on the same depth + * or 0 if there isn't an event on the same depth anymore. + * + * /-> The position in the file. Id is this divided by size of entry. + * | So in this case this would be 1 (192bits per entry). + * | /-> Indicates there are children. The + * | | first child is located at current + * | | ID + 1. So 1 + 1 in this case: 2. + * | | Or 0x00180 in the tree file. + * | | /-> Next event on the same depth is + * | | | located at 4. So 0x00300 in the + * | | | tree file. + * 0x0000C0: [start, end, dictId, 1, 4] + * + * + * Example: + * 0x0: [start, end, dictId, 1, 0] + * | + * /----------------------------------\ + * | | + * 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0] + * | + * /----------------------------------\ + * | | + * 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0] + */ +// clang-format on + +namespace js { +void DestroyTraceLoggerGraphState(); +size_t SizeOfTraceLogGraphState(mozilla::MallocSizeOf mallocSizeOf); +} // namespace js + +class TraceLoggerGraphState { + uint32_t numLoggers; + uint32_t pid_; + + // File pointer to the "tl-data.json" file. (Explained above). + FILE* out; + +#ifdef DEBUG + bool initialized; +#endif + + public: + js::Mutex lock; + + public: + TraceLoggerGraphState() + : numLoggers(0), + pid_(0), + out(nullptr) +#ifdef DEBUG + , + initialized(false) +#endif + , + lock(js::mutexid::TraceLoggerGraphState) { + } + + bool init(); + ~TraceLoggerGraphState(); + + uint32_t nextLoggerId(); + uint32_t pid() { return pid_; } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); + } +}; + +namespace js { +class TraceLoggerThread; +} // namespace js + +class TraceLoggerGraph { + // This is needed so that we can write the data to the JSON writer from the TL + // thread class. + friend class js::TraceLoggerThread; + + private: + // The layout of the tree in memory and in the log file. Readable by JS + // using TypedArrays. + struct TreeEntry { + uint64_t start_; + uint64_t stop_; + union { + struct { + uint32_t textId_ : 31; + uint32_t hasChildren_ : 1; + } s; + uint32_t value_; + } u; + uint32_t nextId_; + + TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren, + uint32_t nextId) { + start_ = start; + stop_ = stop; + u.s.textId_ = textId; + u.s.hasChildren_ = hasChildren; + nextId_ = nextId; + } + TreeEntry() : start_(0), stop_(0), u{}, nextId_(0) {} + uint64_t start() { return start_; } + uint64_t stop() { return stop_; } + uint32_t textId() { return u.s.textId_; } + bool hasChildren() { return u.s.hasChildren_; } + uint32_t nextId() { return nextId_; } + void setStart(uint64_t start) { start_ = start; } + void setStop(uint64_t stop) { stop_ = stop; } + void setTextId(uint32_t textId) { + MOZ_ASSERT(textId < uint32_t(1 << 31)); + u.s.textId_ = textId; + } + void setHasChildren(bool hasChildren) { u.s.hasChildren_ = hasChildren; } + void setNextId(uint32_t nextId) { nextId_ = nextId; } + }; + + // Helper structure for keeping track of the current entries in + // the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag + // is used to know if a subtree doesn't need to get logged. + struct StackEntry { + uint32_t treeId_; + uint32_t lastChildId_; + struct { + uint32_t textId_ : 31; + uint32_t active_ : 1; + } s; + StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true) + : treeId_(treeId), lastChildId_(lastChildId) { + s.textId_ = 0; + s.active_ = active; + } + uint32_t treeId() { return treeId_; } + uint32_t lastChildId() { return lastChildId_; } + uint32_t textId() { return s.textId_; } + bool active() { return s.active_; } + void setTreeId(uint32_t treeId) { treeId_ = treeId; } + void setLastChildId(uint32_t lastChildId) { lastChildId_ = lastChildId; } + void setTextId(uint32_t textId) { + MOZ_ASSERT(textId < uint32_t(1 << 31)); + s.textId_ = textId; + } + void setActive(bool active) { s.active_ = active; } + }; + + public: + TraceLoggerGraph() = default; + ~TraceLoggerGraph(); + + bool init(uint64_t timestamp, bool graphFileEnabled); + + // Link a textId with a particular text. + void addTextId(uint32_t id, const char* text); + void addTextId(uint32_t id, const char* text, mozilla::Maybe<uint32_t>& line, + mozilla::Maybe<uint32_t>& column); + + // Create a tree out of all the given events. + void log(ContinuousSpace<EventEntry>& events, mozilla::TimeStamp startTime); + + static size_t treeSizeFlushLimit() { + // Allow tree size to grow to 100MB. + return 100 * 1024 * 1024 / sizeof(TreeEntry); + } + + uint32_t nextTextId() { return nextTextId_; } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + bool failed = false; + bool enabled = false; + uint32_t nextTextId_ = 0; + + FILE* dictFile = nullptr; + FILE* treeFile = nullptr; + FILE* eventFile = nullptr; + + ContinuousSpace<TreeEntry> tree; + ContinuousSpace<StackEntry> stack; + uint32_t treeOffset = 0; + + // Helper functions that convert a TreeEntry in different endianness + // in place. + void entryToBigEndian(TreeEntry* entry); + void entryToSystemEndian(TreeEntry* entry); + + // Helper functions to get/save a tree from file. + bool getTreeEntry(uint32_t treeId, TreeEntry* entry); + bool saveTreeEntry(uint32_t treeId, TreeEntry* entry); + + // Return the first StackEntry that is active. + StackEntry& getActiveAncestor(); + + // This contains the meat of startEvent, except the test for enough space, + // the test if tracelogger is enabled and the timestamp computation. + void startEvent(uint32_t id, uint64_t timestamp); + bool startEventInternal(uint32_t id, uint64_t timestamp); + + // Update functions that can adjust the items in the tree, + // both in memory or already written to disk. + bool updateHasChildren(uint32_t treeId, bool hasChildren = true); + bool updateNextId(uint32_t treeId, uint32_t nextId); + bool updateStop(uint32_t treeId, uint64_t timestamp); + + // Flush the tree. + bool flush(); + + // Stop a tree event. + void stopEvent(uint32_t id, uint64_t timestamp); + void stopEvent(uint64_t timestamp); + + // Log an (non-tree) event. + void logTimestamp(uint32_t id, uint64_t timestamp); + + // Disable logging and forcefully report all not yet stopped tree events + // as stopped. + void disable(uint64_t timestamp); +}; + +#endif /* TraceLoggingGraph_h */ |