1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 GECKO_TASK_TRACER_H
#define GECKO_TASK_TRACER_H
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include "nsCOMPtr.h"
#include "nsStringFwd.h"
#include <stdarg.h>
/**
* TaskTracer provides a way to trace the correlation between different tasks
* across threads and processes. Unlike sampling based profilers, TaskTracer can
* tell you where a task is dispatched from, what its original source was, how
* long it waited in the event queue, and how long it took to execute.
*
* Source Events are usually some kinds of I/O events we're interested in, such
* as touch events, timer events, network events, etc. When a source event is
* created, TaskTracer records the entire chain of Tasks and nsRunnables as they
* are dispatched to different threads and processes. It records latency,
* execution time, etc. for each Task and nsRunnable that chains back to the
* original source event.
*/
class nsIRunnable;
namespace mozilla {
class TimeStamp;
class Runnable;
namespace tasktracer {
extern bool gStarted;
/**
* Check if the TaskTracer has been started.
*/
inline bool IsStartLogging() {
// |gStarted| is not an atomic variable, but it is fine for it is a
// boolean value and will be changed under the protection of
// |sMutex|.
//
// There is a latency between the change of the value and the
// observation of threads. |gStarted| would be checked again with
// the protection of mutex in logging functions; for example,
// |AddLabel()|, so all false positive would be blocked with the
// double checks. For false negative, it is fine to lose some
// records at begin of logging.
return gStarted;
}
enum { FORKED_AFTER_NUWA = 1 << 0 };
enum SourceEventType {
#define SOURCE_EVENT_NAME(x) x,
#include "SourceEventTypeMap.h"
#undef SOURCE_EVENT_NAME
};
class AutoSaveCurTraceInfoImpl {
uint64_t mSavedTaskId;
uint64_t mSavedSourceEventId;
SourceEventType mSavedSourceEventType;
public:
AutoSaveCurTraceInfoImpl();
~AutoSaveCurTraceInfoImpl();
};
class AutoSaveCurTraceInfo {
Maybe<AutoSaveCurTraceInfoImpl> mSaved;
public:
AutoSaveCurTraceInfo() {
if (IsStartLogging()) {
mSaved.emplace();
}
}
/**
* The instance had saved TraceInfo.
*
* It means that TaskTrace had been enabled when the instance was
* created.
*/
bool HasSavedTraceInfo() { return !!mSaved; }
};
class AutoSourceEvent : public AutoSaveCurTraceInfo {
void StartScope(SourceEventType aType);
void StopScope();
public:
explicit AutoSourceEvent(SourceEventType aType) : AutoSaveCurTraceInfo() {
if (HasSavedTraceInfo()) {
StartScope(aType);
}
}
~AutoSourceEvent() {
if (HasSavedTraceInfo()) {
StopScope();
}
}
};
void InitTaskTracer(uint32_t aFlags = 0);
void ShutdownTaskTracer();
void DoAddLabel(const char* aFormat, va_list& aArgs);
// Add a label to the currently running task, aFormat is the message to log,
// followed by corresponding parameters.
inline void AddLabel(const char* aFormat, ...) MOZ_FORMAT_PRINTF(1, 2);
inline void AddLabel(const char* aFormat, ...) {
if (IsStartLogging()) {
va_list args;
va_start(args, aFormat);
DoAddLabel(aFormat, args);
va_end(args);
}
}
void StartLogging();
void StopLogging();
UniquePtr<Vector<nsCString>> GetLoggedData(TimeStamp aStartTime);
// Returns the timestamp when Task Tracer is enabled in this process.
PRTime GetStartTime();
/**
* Internal functions.
*/
already_AddRefed<nsIRunnable> CreateTracedRunnable(
already_AddRefed<nsIRunnable>&& aRunnable);
// Free the TraceInfo allocated on a thread's TLS. Currently we are wrapping
// tasks running on nsThreads and base::thread, so FreeTraceInfo is called at
// where nsThread and base::thread release themselves.
void FreeTraceInfo();
const char* GetJSLabelPrefix();
void GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId,
SourceEventType* aOutSourceEventType);
class AutoScopedLabel {
char* mLabel;
void Init(const char* aFormat, va_list& aArgs);
public:
explicit AutoScopedLabel(const char* aFormat, ...) : mLabel(nullptr) {
if (IsStartLogging()) {
va_list args;
va_start(args, aFormat);
Init(aFormat, args);
va_end(args);
}
}
~AutoScopedLabel() {
if (mLabel) {
AddLabel("End %s", mLabel);
free(mLabel);
}
}
};
} // namespace tasktracer
} // namespace mozilla.
#endif
|