summaryrefslogtreecommitdiffstats
path: root/js/src/vm/TraceLoggingGraph.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/TraceLoggingGraph.h')
-rw-r--r--js/src/vm/TraceLoggingGraph.h263
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 */