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 : #ifndef TraceLoggingGraph_h
8 : #define TraceLoggingGraph_h
9 :
10 : #include "mozilla/MemoryReporting.h"
11 :
12 : #include "js/TypeDecls.h"
13 : #include "vm/MutexIDs.h"
14 : #include "vm/TraceLoggingTypes.h"
15 :
16 : /*
17 : * The output of a tracelogging session is saved in /tmp/tl-data.json.
18 : * The format of that file is a JS array per tracelogger (=thread), with a map
19 : * containing:
20 : * - dict: Name of the file containing a json table with the log text.
21 : * All other files only contain a index to this table when logging.
22 : * - events: Name of the file containing a flat list of log events saved
23 : * in binary format.
24 : * (64bit: Time Stamp Counter, 32bit index to dict)
25 : * - tree: Name of the file containing the events with duration. The content
26 : * is already in a tree data structure. This is also saved in a
27 : * binary file.
28 : * - treeFormat: The format used to encode the tree. By default "64,64,31,1,32".
29 : * There are currently no other formats to save the tree.
30 : * - 64,64,31,1,32 signifies how many bytes are used for the different
31 : * parts of the tree.
32 : * => 64 bits: Time Stamp Counter of start of event.
33 : * => 64 bits: Time Stamp Counter of end of event.
34 : * => 31 bits: Index to dict file containing the log text.
35 : * => 1 bit: Boolean signifying if this entry has children.
36 : * When true, the child can be found just right after this entry.
37 : * => 32 bits: Containing the ID of the next event on the same depth
38 : * or 0 if there isn't an event on the same depth anymore.
39 : *
40 : * /-> The position in the file. Id is this divided by size of entry.
41 : * | So in this case this would be 1 (192bits per entry).
42 : * | /-> Indicates there are children. The
43 : * | | first child is located at current
44 : * | | ID + 1. So 1 + 1 in this case: 2.
45 : * | | Or 0x00180 in the tree file.
46 : * | | /-> Next event on the same depth is
47 : * | | | located at 4. So 0x00300 in the
48 : * | | | tree file.
49 : * 0x0000C0: [start, end, dictId, 1, 4]
50 : *
51 : *
52 : * Example:
53 : * 0x0: [start, end, dictId, 1, 0]
54 : * |
55 : * /----------------------------------\
56 : * | |
57 : * 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0]
58 : * |
59 : * /----------------------------------\
60 : * | |
61 : * 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0]
62 : */
63 :
64 : namespace js {
65 : void DestroyTraceLoggerGraphState();
66 : size_t SizeOfTraceLogGraphState(mozilla::MallocSizeOf mallocSizeOf);
67 : } // namespace js
68 :
69 : class TraceLoggerGraphState
70 : {
71 : uint32_t numLoggers;
72 : uint32_t pid_;
73 :
74 : // File pointer to the "tl-data.json" file. (Explained above).
75 : FILE* out;
76 :
77 : #ifdef DEBUG
78 : bool initialized;
79 : #endif
80 :
81 : public:
82 : js::Mutex lock;
83 :
84 : public:
85 0 : TraceLoggerGraphState()
86 0 : : numLoggers(0)
87 : , pid_(0)
88 : , out(nullptr)
89 : #ifdef DEBUG
90 : , initialized(false)
91 : #endif
92 0 : , lock(js::mutexid::TraceLoggerGraphState)
93 0 : {}
94 :
95 : bool init();
96 : ~TraceLoggerGraphState();
97 :
98 : uint32_t nextLoggerId();
99 0 : uint32_t pid() { return pid_; }
100 :
101 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
102 0 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
103 0 : return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
104 : }
105 : };
106 :
107 : class TraceLoggerGraph
108 : {
109 : // The layout of the tree in memory and in the log file. Readable by JS
110 : // using TypedArrays.
111 : struct TreeEntry {
112 : uint64_t start_;
113 : uint64_t stop_;
114 : union {
115 : struct {
116 : uint32_t textId_: 31;
117 : uint32_t hasChildren_: 1;
118 : } s;
119 : uint32_t value_;
120 : } u;
121 : uint32_t nextId_;
122 :
123 : TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren,
124 : uint32_t nextId)
125 : {
126 : start_ = start;
127 : stop_ = stop;
128 : u.s.textId_ = textId;
129 : u.s.hasChildren_ = hasChildren;
130 : nextId_ = nextId;
131 : }
132 0 : TreeEntry()
133 0 : { }
134 : uint64_t start() {
135 : return start_;
136 : }
137 : uint64_t stop() {
138 : return stop_;
139 : }
140 0 : uint32_t textId() {
141 0 : return u.s.textId_;
142 : }
143 0 : bool hasChildren() {
144 0 : return u.s.hasChildren_;
145 : }
146 : uint32_t nextId() {
147 : return nextId_;
148 : }
149 0 : void setStart(uint64_t start) {
150 0 : start_ = start;
151 0 : }
152 0 : void setStop(uint64_t stop) {
153 0 : stop_ = stop;
154 0 : }
155 0 : void setTextId(uint32_t textId) {
156 0 : MOZ_ASSERT(textId < uint32_t(1 << 31));
157 0 : u.s.textId_ = textId;
158 0 : }
159 0 : void setHasChildren(bool hasChildren) {
160 0 : u.s.hasChildren_ = hasChildren;
161 0 : }
162 0 : void setNextId(uint32_t nextId) {
163 0 : nextId_ = nextId;
164 0 : }
165 : };
166 :
167 : // Helper structure for keeping track of the current entries in
168 : // the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag
169 : // is used to know if a subtree doesn't need to get logged.
170 : struct StackEntry {
171 : uint32_t treeId_;
172 : uint32_t lastChildId_;
173 : struct {
174 : uint32_t textId_: 31;
175 : uint32_t active_: 1;
176 : } s;
177 : StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true)
178 : : treeId_(treeId), lastChildId_(lastChildId)
179 : {
180 : s.textId_ = 0;
181 : s.active_ = active;
182 : }
183 0 : uint32_t treeId() {
184 0 : return treeId_;
185 : }
186 0 : uint32_t lastChildId() {
187 0 : return lastChildId_;
188 : }
189 : uint32_t textId() {
190 : return s.textId_;
191 : }
192 0 : bool active() {
193 0 : return s.active_;
194 : }
195 0 : void setTreeId(uint32_t treeId) {
196 0 : treeId_ = treeId;
197 0 : }
198 0 : void setLastChildId(uint32_t lastChildId) {
199 0 : lastChildId_ = lastChildId;
200 0 : }
201 : void setTextId(uint32_t textId) {
202 : MOZ_ASSERT(textId < uint32_t(1<<31));
203 : s.textId_ = textId;
204 : }
205 0 : void setActive(bool active) {
206 0 : s.active_ = active;
207 0 : }
208 : };
209 :
210 : public:
211 0 : TraceLoggerGraph() {}
212 : ~TraceLoggerGraph();
213 :
214 : bool init(uint64_t timestamp);
215 :
216 : // Link a textId with a particular text.
217 : void addTextId(uint32_t id, const char* text);
218 :
219 : // Create a tree out of all the given events.
220 : void log(ContinuousSpace<EventEntry>& events);
221 :
222 0 : static size_t treeSizeFlushLimit() {
223 : // Allow tree size to grow to 100MB.
224 0 : return 100 * 1024 * 1024 / sizeof(TreeEntry);
225 : }
226 :
227 0 : uint32_t nextTextId() { return nextTextId_; }
228 :
229 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
230 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
231 :
232 : private:
233 : bool failed = false;
234 : bool enabled = false;
235 : uint32_t nextTextId_ = 0;
236 :
237 : FILE* dictFile = nullptr;
238 : FILE* treeFile = nullptr;
239 : FILE* eventFile = nullptr;
240 :
241 : ContinuousSpace<TreeEntry> tree;
242 : ContinuousSpace<StackEntry> stack;
243 : uint32_t treeOffset = 0;
244 :
245 : // Helper functions that convert a TreeEntry in different endianness
246 : // in place.
247 : void entryToBigEndian(TreeEntry* entry);
248 : void entryToSystemEndian(TreeEntry* entry);
249 :
250 : // Helper functions to get/save a tree from file.
251 : bool getTreeEntry(uint32_t treeId, TreeEntry* entry);
252 : bool saveTreeEntry(uint32_t treeId, TreeEntry* entry);
253 :
254 : // Return the first StackEntry that is active.
255 : StackEntry& getActiveAncestor();
256 :
257 : // This contains the meat of startEvent, except the test for enough space,
258 : // the test if tracelogger is enabled and the timestamp computation.
259 : void startEvent(uint32_t id, uint64_t timestamp);
260 : bool startEventInternal(uint32_t id, uint64_t timestamp);
261 :
262 : // Update functions that can adjust the items in the tree,
263 : // both in memory or already written to disk.
264 : bool updateHasChildren(uint32_t treeId, bool hasChildren = true);
265 : bool updateNextId(uint32_t treeId, uint32_t nextId);
266 : bool updateStop(uint32_t treeId, uint64_t timestamp);
267 :
268 : // Flush the tree.
269 : bool flush();
270 :
271 : // Stop a tree event.
272 : void stopEvent(uint32_t id, uint64_t timestamp);
273 : void stopEvent(uint64_t timestamp);
274 :
275 : // Log an (non-tree) event.
276 : void logTimestamp(uint32_t id, uint64_t timestamp);
277 :
278 : // Disable logging and forcefully report all not yet stopped tree events
279 : // as stopped.
280 : void disable(uint64_t timestamp);
281 : };
282 :
283 : #endif /* TraceLoggingGraph_h */
|