|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
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 #include "GeckoTaskTracer.h" |
|
8 #include "GeckoTaskTracerImpl.h" |
|
9 |
|
10 #include "mozilla/StaticMutex.h" |
|
11 #include "mozilla/ThreadLocal.h" |
|
12 #include "mozilla/unused.h" |
|
13 |
|
14 #include "nsClassHashtable.h" |
|
15 #include "nsThreadUtils.h" |
|
16 |
|
17 #include <stdarg.h> |
|
18 #include <stdio.h> |
|
19 #include <unistd.h> |
|
20 |
|
21 #if defined(__GLIBC__) |
|
22 // glibc doesn't implement gettid(2). |
|
23 #include <sys/syscall.h> |
|
24 static pid_t gettid() |
|
25 { |
|
26 return (pid_t) syscall(SYS_gettid); |
|
27 } |
|
28 #endif |
|
29 |
|
30 #define MAX_USER_LABEL_LEN 512 |
|
31 |
|
32 namespace mozilla { |
|
33 namespace tasktracer { |
|
34 |
|
35 static mozilla::ThreadLocal<TraceInfo*> sTraceInfoTLS; |
|
36 static StaticMutex sMutex; |
|
37 static nsClassHashtable<nsUint32HashKey, TraceInfo>* sTraceInfos = nullptr; |
|
38 |
|
39 namespace { |
|
40 |
|
41 static TraceInfo* |
|
42 AllocTraceInfo(int aTid) |
|
43 { |
|
44 StaticMutexAutoLock lock(sMutex); |
|
45 |
|
46 sTraceInfos->Put(aTid, new TraceInfo(aTid)); |
|
47 return sTraceInfos->Get(aTid); |
|
48 } |
|
49 |
|
50 static void |
|
51 FreeTraceInfo(int aTid) |
|
52 { |
|
53 StaticMutexAutoLock lock(sMutex); |
|
54 |
|
55 sTraceInfos->Remove(aTid); |
|
56 } |
|
57 |
|
58 static bool |
|
59 IsInitialized() |
|
60 { |
|
61 return sTraceInfoTLS.initialized(); |
|
62 } |
|
63 |
|
64 static void |
|
65 SaveCurTraceInfo() |
|
66 { |
|
67 TraceInfo* info = GetOrCreateTraceInfo(); |
|
68 NS_ENSURE_TRUE_VOID(info); |
|
69 |
|
70 info->mSavedCurTraceSourceId = info->mCurTraceSourceId; |
|
71 info->mSavedCurTraceSourceType = info->mCurTraceSourceType; |
|
72 info->mSavedCurTaskId = info->mCurTaskId; |
|
73 } |
|
74 |
|
75 static void |
|
76 RestoreCurTraceInfo() |
|
77 { |
|
78 TraceInfo* info = GetOrCreateTraceInfo(); |
|
79 NS_ENSURE_TRUE_VOID(info); |
|
80 |
|
81 info->mCurTraceSourceId = info->mSavedCurTraceSourceId; |
|
82 info->mCurTraceSourceType = info->mSavedCurTraceSourceType; |
|
83 info->mCurTaskId = info->mSavedCurTaskId; |
|
84 } |
|
85 |
|
86 static void |
|
87 CreateSourceEvent(SourceEventType aType) |
|
88 { |
|
89 NS_ENSURE_TRUE_VOID(IsInitialized()); |
|
90 |
|
91 // Save the currently traced source event info. |
|
92 SaveCurTraceInfo(); |
|
93 |
|
94 // Create a new unique task id. |
|
95 uint64_t newId = GenNewUniqueTaskId(); |
|
96 TraceInfo* info = GetOrCreateTraceInfo(); |
|
97 info->mCurTraceSourceId = newId; |
|
98 info->mCurTraceSourceType = aType; |
|
99 info->mCurTaskId = newId; |
|
100 |
|
101 // Log a fake dispatch and start for this source event. |
|
102 LogDispatch(newId, newId,newId, aType); |
|
103 LogBegin(newId, newId); |
|
104 } |
|
105 |
|
106 static void |
|
107 DestroySourceEvent() |
|
108 { |
|
109 NS_ENSURE_TRUE_VOID(IsInitialized()); |
|
110 |
|
111 // Log a fake end for this source event. |
|
112 TraceInfo* info = GetOrCreateTraceInfo(); |
|
113 LogEnd(info->mCurTraceSourceId, info->mCurTraceSourceId); |
|
114 |
|
115 // Restore the previously saved source event info. |
|
116 RestoreCurTraceInfo(); |
|
117 } |
|
118 |
|
119 } // namespace anonymous |
|
120 |
|
121 void |
|
122 InitTaskTracer() |
|
123 { |
|
124 MOZ_ASSERT(!sTraceInfos); |
|
125 |
|
126 sTraceInfos = new nsClassHashtable<nsUint32HashKey, TraceInfo>(); |
|
127 |
|
128 if (!sTraceInfoTLS.initialized()) { |
|
129 unused << sTraceInfoTLS.init(); |
|
130 } |
|
131 } |
|
132 |
|
133 void |
|
134 ShutdownTaskTracer() |
|
135 { |
|
136 delete sTraceInfos; |
|
137 sTraceInfos = nullptr; |
|
138 } |
|
139 |
|
140 TraceInfo* |
|
141 GetOrCreateTraceInfo() |
|
142 { |
|
143 NS_ENSURE_TRUE(IsInitialized(), nullptr); |
|
144 |
|
145 TraceInfo* info = sTraceInfoTLS.get(); |
|
146 if (!info) { |
|
147 info = AllocTraceInfo(gettid()); |
|
148 sTraceInfoTLS.set(info); |
|
149 } |
|
150 |
|
151 return info; |
|
152 } |
|
153 |
|
154 uint64_t |
|
155 GenNewUniqueTaskId() |
|
156 { |
|
157 TraceInfo* info = GetOrCreateTraceInfo(); |
|
158 NS_ENSURE_TRUE(info, 0); |
|
159 |
|
160 pid_t tid = gettid(); |
|
161 uint64_t taskid = ((uint64_t)tid << 32) | ++info->mLastUniqueTaskId; |
|
162 return taskid; |
|
163 } |
|
164 |
|
165 AutoSaveCurTraceInfo::AutoSaveCurTraceInfo() |
|
166 { |
|
167 SaveCurTraceInfo(); |
|
168 } |
|
169 |
|
170 AutoSaveCurTraceInfo::~AutoSaveCurTraceInfo() |
|
171 { |
|
172 RestoreCurTraceInfo(); |
|
173 } |
|
174 |
|
175 void |
|
176 SetCurTraceInfo(uint64_t aSourceEventId, uint64_t aParentTaskId, |
|
177 SourceEventType aSourceEventType) |
|
178 { |
|
179 TraceInfo* info = GetOrCreateTraceInfo(); |
|
180 NS_ENSURE_TRUE_VOID(info); |
|
181 |
|
182 info->mCurTraceSourceId = aSourceEventId; |
|
183 info->mCurTaskId = aParentTaskId; |
|
184 info->mCurTraceSourceType = aSourceEventType; |
|
185 } |
|
186 |
|
187 void |
|
188 GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId, |
|
189 SourceEventType* aOutSourceEventType) |
|
190 { |
|
191 TraceInfo* info = GetOrCreateTraceInfo(); |
|
192 NS_ENSURE_TRUE_VOID(info); |
|
193 |
|
194 *aOutSourceEventId = info->mCurTraceSourceId; |
|
195 *aOutParentTaskId = info->mCurTaskId; |
|
196 *aOutSourceEventType = info->mCurTraceSourceType; |
|
197 } |
|
198 |
|
199 void |
|
200 LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, uint64_t aSourceEventId, |
|
201 SourceEventType aSourceEventType) |
|
202 { |
|
203 NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); |
|
204 |
|
205 // Log format: |
|
206 // [0 taskId dispatchTime sourceEventId sourceEventType parentTaskId] |
|
207 } |
|
208 |
|
209 void |
|
210 LogBegin(uint64_t aTaskId, uint64_t aSourceEventId) |
|
211 { |
|
212 NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); |
|
213 |
|
214 // Log format: |
|
215 // [1 taskId beginTime processId threadId] |
|
216 } |
|
217 |
|
218 void |
|
219 LogEnd(uint64_t aTaskId, uint64_t aSourceEventId) |
|
220 { |
|
221 NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); |
|
222 |
|
223 // Log format: |
|
224 // [2 taskId endTime] |
|
225 } |
|
226 |
|
227 void |
|
228 LogVirtualTablePtr(uint64_t aTaskId, uint64_t aSourceEventId, int* aVptr) |
|
229 { |
|
230 NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); |
|
231 |
|
232 // Log format: |
|
233 // [4 taskId address] |
|
234 } |
|
235 |
|
236 void |
|
237 FreeTraceInfo() |
|
238 { |
|
239 NS_ENSURE_TRUE_VOID(IsInitialized()); |
|
240 |
|
241 FreeTraceInfo(gettid()); |
|
242 } |
|
243 |
|
244 AutoSourceEvent::AutoSourceEvent(SourceEventType aType) |
|
245 { |
|
246 CreateSourceEvent(aType); |
|
247 } |
|
248 |
|
249 AutoSourceEvent::~AutoSourceEvent() |
|
250 { |
|
251 DestroySourceEvent(); |
|
252 } |
|
253 |
|
254 void AddLabel(const char* aFormat, ...) |
|
255 { |
|
256 NS_ENSURE_TRUE_VOID(IsInitialized()); |
|
257 |
|
258 va_list args; |
|
259 va_start(args, aFormat); |
|
260 char buffer[MAX_USER_LABEL_LEN] = {0}; |
|
261 vsnprintf(buffer, MAX_USER_LABEL_LEN, aFormat, args); |
|
262 va_end(args); |
|
263 |
|
264 // Log format: |
|
265 // [3 taskId "label"] |
|
266 } |
|
267 |
|
268 } // namespace tasktracer |
|
269 } // namespace mozilla |