mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-09-28 20:56:36 +00:00
276 lines
8.6 KiB
C++
276 lines
8.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* 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/DebugOnly.h"
|
|
|
|
#include "jslock.h"
|
|
|
|
#include "js/TypeDecls.h"
|
|
#include "vm/TraceLoggingTypes.h"
|
|
|
|
/*
|
|
* 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]
|
|
*/
|
|
|
|
namespace js {
|
|
void DestroyTraceLoggerGraphState();
|
|
} // namespace js
|
|
|
|
class TraceLoggerGraphState
|
|
{
|
|
uint32_t numLoggers;
|
|
|
|
// File pointer to the "tl-data.json" file. (Explained above).
|
|
FILE* out;
|
|
|
|
#ifdef DEBUG
|
|
bool initialized;
|
|
#endif
|
|
|
|
public:
|
|
PRLock* lock;
|
|
|
|
public:
|
|
TraceLoggerGraphState()
|
|
: numLoggers(0),
|
|
out(nullptr),
|
|
#ifdef DEBUG
|
|
initialized(false),
|
|
#endif
|
|
lock(nullptr)
|
|
{}
|
|
|
|
bool init();
|
|
~TraceLoggerGraphState();
|
|
|
|
uint32_t nextLoggerId();
|
|
};
|
|
|
|
class TraceLoggerGraph
|
|
{
|
|
// 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()
|
|
{ }
|
|
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()
|
|
: failed(false),
|
|
enabled(false),
|
|
nextTextId(0),
|
|
treeOffset(0)
|
|
{ }
|
|
~TraceLoggerGraph();
|
|
|
|
bool init(uint64_t timestamp);
|
|
|
|
// Link a textId with a particular text.
|
|
void addTextId(uint32_t id, const char* text);
|
|
|
|
// Create a tree out of all the given events.
|
|
void log(ContinuousSpace<EventEntry>& events);
|
|
|
|
static size_t treeSizeFlushLimit() {
|
|
// Allow tree size to grow to 100MB.
|
|
return 100 * 1024 * 1024 / sizeof(TreeEntry);
|
|
}
|
|
|
|
private:
|
|
bool failed;
|
|
bool enabled;
|
|
mozilla::DebugOnly<uint32_t> nextTextId;
|
|
|
|
FILE* dictFile;
|
|
FILE* treeFile;
|
|
FILE* eventFile;
|
|
|
|
ContinuousSpace<TreeEntry> tree;
|
|
ContinuousSpace<StackEntry> stack;
|
|
uint32_t treeOffset;
|
|
|
|
// 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 */
|