OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/trace_event.h" | 5 #include "base/debug/trace_event.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 // before throwing them away. | 40 // before throwing them away. |
41 const size_t kTraceEventBufferSize = 500000; | 41 const size_t kTraceEventBufferSize = 500000; |
42 const size_t kTraceEventBatchSize = 1000; | 42 const size_t kTraceEventBatchSize = 1000; |
43 | 43 |
44 #define TRACE_EVENT_MAX_CATEGORIES 100 | 44 #define TRACE_EVENT_MAX_CATEGORIES 100 |
45 | 45 |
46 namespace { | 46 namespace { |
47 | 47 |
48 // Specify these values when the corresponding argument of AddTraceEvent is not | 48 // Specify these values when the corresponding argument of AddTraceEvent is not |
49 // used. | 49 // used. |
50 static const char* kNoArgName = NULL; | 50 static const int kZeroArgs = 0; |
51 static const int kNoArgValue = 0; | 51 static const char** kNoArgNames = NULL; |
| 52 static const uint8* kNoArgTypes = NULL; |
| 53 static const uint64* kNoArgValues = NULL; |
52 static const int kNoThreshholdBeginId = -1; | 54 static const int kNoThreshholdBeginId = -1; |
53 static const int64 kNoThresholdValue = 0; | 55 static const int64 kNoThresholdValue = 0; |
54 static const int kNoEventId = 0; | 56 static const uint64 kNoEventId = 0; |
55 | 57 |
56 TraceCategory g_categories[TRACE_EVENT_MAX_CATEGORIES] = { | 58 // Parallel arrays g_categories and g_category_enabled are separate so that |
57 { "tracing already shutdown", false }, | 59 // a pointer to a member of g_category_enabled can be easily converted to an |
58 { "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES", | 60 // index into g_categories. This allows macros to deal only with bool enabled |
59 false }, | 61 // pointers from g_category_enabled, and we can convert internally to determine |
60 { "__metadata", | 62 // the category name from the bool enabled pointer. |
61 false } | 63 const char* g_categories[TRACE_EVENT_MAX_CATEGORIES] = { |
| 64 "tracing already shutdown", |
| 65 "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES", |
| 66 "__metadata", |
62 }; | 67 }; |
63 const TraceCategory* const g_category_already_shutdown = | 68 volatile bool g_category_enabled[TRACE_EVENT_MAX_CATEGORIES] = { false }; |
64 &g_categories[0]; | 69 const int g_category_already_shutdown = 0; |
65 const TraceCategory* const g_category_categories_exhausted = | 70 const int g_category_categories_exhausted = 1; |
66 &g_categories[1]; | 71 const int g_category_metadata = 2; |
67 const TraceCategory* const g_category_metadata = | |
68 &g_categories[2]; | |
69 int g_category_index = 3; // skip initial 3 categories | 72 int g_category_index = 3; // skip initial 3 categories |
70 | 73 |
71 // The most-recently captured name of the current thread | 74 // The most-recently captured name of the current thread |
72 LazyInstance<ThreadLocalPointer<const char>, | 75 LazyInstance<ThreadLocalPointer<const char>, |
73 LeakyLazyInstanceTraits<ThreadLocalPointer<const char> > > | 76 LeakyLazyInstanceTraits<ThreadLocalPointer<const char> > > |
74 g_current_thread_name = LAZY_INSTANCE_INITIALIZER; | 77 g_current_thread_name = LAZY_INSTANCE_INITIALIZER; |
75 | 78 |
76 } // namespace | 79 void AppendValueAsJSON(uint8 type, |
77 | 80 TraceEvent::TraceValue value, |
78 //////////////////////////////////////////////////////////////////////////////// | 81 std::string* out) { |
79 // | |
80 // TraceValue | |
81 // | |
82 //////////////////////////////////////////////////////////////////////////////// | |
83 | |
84 void TraceValue::AppendAsJSON(std::string* out) const { | |
85 std::string::size_type start_pos; | 82 std::string::size_type start_pos; |
86 switch (type_) { | 83 switch (type) { |
87 case TRACE_TYPE_BOOL: | 84 case TRACE_VALUE_TYPE_BOOL: |
88 *out += as_bool() ? "true" : "false"; | 85 *out += value.as_bool ? "true" : "false"; |
89 break; | 86 break; |
90 case TRACE_TYPE_UINT: | 87 case TRACE_VALUE_TYPE_UINT: |
91 StringAppendF(out, "%" PRIu64, as_uint()); | 88 StringAppendF(out, "%" PRIu64, value.as_uint); |
92 break; | 89 break; |
93 case TRACE_TYPE_INT: | 90 case TRACE_VALUE_TYPE_INT: |
94 StringAppendF(out, "%" PRId64, as_int()); | 91 StringAppendF(out, "%" PRId64, value.as_int); |
95 break; | 92 break; |
96 case TRACE_TYPE_DOUBLE: | 93 case TRACE_VALUE_TYPE_DOUBLE: |
97 StringAppendF(out, "%f", as_double()); | 94 StringAppendF(out, "%f", value.as_double); |
98 break; | 95 break; |
99 case TRACE_TYPE_POINTER: | 96 case TRACE_VALUE_TYPE_POINTER: |
100 // JSON only supports double and int numbers. | 97 // JSON only supports double and int numbers. |
101 // So as not to lose bits from a 64-bit pointer, output as a hex string. | 98 // So as not to lose bits from a 64-bit pointer, output as a hex string. |
102 StringAppendF(out, "\"%" PRIx64 "\"", static_cast<uint64>( | 99 StringAppendF(out, "\"%" PRIx64 "\"", static_cast<uint64>( |
103 reinterpret_cast<intptr_t>( | 100 reinterpret_cast<intptr_t>( |
104 as_pointer()))); | 101 value.as_pointer))); |
105 break; | 102 break; |
106 case TRACE_TYPE_STRING: | 103 case TRACE_VALUE_TYPE_STRING: |
107 case TRACE_TYPE_STATIC_STRING: | 104 case TRACE_VALUE_TYPE_COPY_STRING: |
108 *out += "\""; | 105 *out += "\""; |
109 start_pos = out->size(); | 106 start_pos = out->size(); |
110 *out += as_string() ? as_string() : "NULL"; | 107 *out += value.as_string ? value.as_string : "NULL"; |
111 // insert backslash before special characters for proper json format. | 108 // insert backslash before special characters for proper json format. |
112 while ((start_pos = out->find_first_of("\\\"", start_pos)) != | 109 while ((start_pos = out->find_first_of("\\\"", start_pos)) != |
113 std::string::npos) { | 110 std::string::npos) { |
114 out->insert(start_pos, 1, '\\'); | 111 out->insert(start_pos, 1, '\\'); |
115 // skip inserted escape character and following character. | 112 // skip inserted escape character and following character. |
116 start_pos += 2; | 113 start_pos += 2; |
117 } | 114 } |
118 *out += "\""; | 115 *out += "\""; |
119 break; | 116 break; |
120 default: | 117 default: |
121 NOTREACHED() << "Don't know how to print this value"; | 118 NOTREACHED() << "Don't know how to print this value"; |
122 break; | 119 break; |
123 } | 120 } |
124 } | 121 } |
125 | 122 |
| 123 } // namespace |
| 124 |
126 //////////////////////////////////////////////////////////////////////////////// | 125 //////////////////////////////////////////////////////////////////////////////// |
127 // | 126 // |
128 // TraceID | 127 // TraceID |
129 // | 128 // |
130 //////////////////////////////////////////////////////////////////////////////// | 129 //////////////////////////////////////////////////////////////////////////////// |
131 | 130 |
132 TraceID::TraceID(void* rhs) { | 131 TraceID::TraceID(void* rhs) { |
133 data_ = base::debug::TraceLog::GetInstance()->GetIntraProcessID( | 132 data_ = TRACE_EVENT_API_GET_ID_FROM_POINTER(rhs); |
134 static_cast<uint64>(reinterpret_cast<uintptr_t>(rhs))); | |
135 } | 133 } |
136 | 134 |
137 //////////////////////////////////////////////////////////////////////////////// | 135 //////////////////////////////////////////////////////////////////////////////// |
138 // | 136 // |
139 // TraceEvent | 137 // TraceEvent |
140 // | 138 // |
141 //////////////////////////////////////////////////////////////////////////////// | 139 //////////////////////////////////////////////////////////////////////////////// |
142 | 140 |
143 namespace { | 141 namespace { |
144 | 142 |
145 size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; } | 143 size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; } |
146 | 144 |
147 // Copies |*member| into |*buffer|, sets |*member| to point to this new | 145 // Copies |*member| into |*buffer|, sets |*member| to point to this new |
148 // location, and then advances |*buffer| by the amount written. | 146 // location, and then advances |*buffer| by the amount written. |
149 void CopyTraceEventParameter(char** buffer, | 147 void CopyTraceEventParameter(char** buffer, |
150 const char** member, | 148 const char** member, |
151 const char* end) { | 149 const char* end) { |
152 if (*member) { | 150 if (*member) { |
153 size_t written = strlcpy(*buffer, *member, end - *buffer) + 1; | 151 size_t written = strlcpy(*buffer, *member, end - *buffer) + 1; |
154 DCHECK_LE(static_cast<int>(written), end - *buffer); | 152 DCHECK_LE(static_cast<int>(written), end - *buffer); |
155 *member = *buffer; | 153 *member = *buffer; |
156 *buffer += written; | 154 *buffer += written; |
157 } | 155 } |
158 } | 156 } |
159 | 157 |
160 } // namespace | 158 } // namespace |
161 | 159 |
162 TraceEvent::TraceEvent() | 160 TraceEvent::TraceEvent() |
163 : id_(0u), | 161 : id_(0u), |
164 category_(NULL), | 162 category_enabled_(NULL), |
165 name_(NULL), | 163 name_(NULL), |
166 thread_id_(0), | 164 thread_id_(0), |
167 phase_(TRACE_EVENT_PHASE_BEGIN), | 165 phase_(TRACE_EVENT_PHASE_BEGIN), |
168 flags_(0) { | 166 flags_(0) { |
169 arg_names_[0] = NULL; | 167 arg_names_[0] = NULL; |
170 arg_names_[1] = NULL; | 168 arg_names_[1] = NULL; |
171 } | 169 } |
172 | 170 |
173 TraceEvent::TraceEvent(int thread_id, | 171 TraceEvent::TraceEvent(int thread_id, |
174 TimeTicks timestamp, | 172 TimeTicks timestamp, |
175 TraceEventPhase phase, | 173 char phase, |
176 const TraceCategory* category, | 174 const volatile bool* category_enabled, |
177 const char* name, | 175 const char* name, |
178 TraceID id, | 176 uint64 id, |
179 const char* arg1_name, const TraceValue& arg1_val, | 177 int num_args, |
180 const char* arg2_name, const TraceValue& arg2_val, | 178 const char** arg_names, |
181 TraceEventFlags flags) | 179 const uint8* arg_types, |
| 180 const uint64* arg_values, |
| 181 uint8 flags) |
182 : timestamp_(timestamp), | 182 : timestamp_(timestamp), |
183 id_(id), | 183 id_(id), |
184 category_(category), | 184 category_enabled_(category_enabled), |
185 name_(name), | 185 name_(name), |
186 thread_id_(thread_id), | 186 thread_id_(thread_id), |
187 phase_(phase), | 187 phase_(phase), |
188 flags_(flags) { | 188 flags_(flags) { |
189 COMPILE_ASSERT(kTraceMaxNumArgs == 2, TraceEvent_arg_count_out_of_sync); | 189 // Clamp num_args since it may have been set by a third_party library. |
190 arg_names_[0] = arg1_name; | 190 num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args; |
191 arg_names_[1] = arg2_name; | 191 int i = 0; |
192 arg_values_[0] = arg1_val; | 192 for (; i < num_args; ++i) { |
193 arg_values_[1] = arg2_val; | 193 arg_names_[i] = arg_names[i]; |
| 194 arg_values_[i].as_uint = arg_values[i]; |
| 195 arg_types_[i] = arg_types[i]; |
| 196 } |
| 197 for (; i < kTraceMaxNumArgs; ++i) { |
| 198 arg_names_[i] = NULL; |
| 199 arg_values_[i].as_uint = 0u; |
| 200 arg_types_[i] = TRACE_VALUE_TYPE_UINT; |
| 201 } |
194 | 202 |
195 bool copy = !!(flags & TRACE_EVENT_FLAG_COPY); | 203 bool copy = !!(flags & TRACE_EVENT_FLAG_COPY); |
196 size_t alloc_size = 0; | 204 size_t alloc_size = 0; |
197 if (copy) { | 205 if (copy) { |
198 alloc_size += GetAllocLength(name); | 206 alloc_size += GetAllocLength(name); |
199 alloc_size += GetAllocLength(arg1_name); | 207 for (i = 0; i < num_args; ++i) { |
200 alloc_size += GetAllocLength(arg2_name); | 208 alloc_size += GetAllocLength(arg_names_[i]); |
| 209 if (arg_types_[i] == TRACE_VALUE_TYPE_STRING) |
| 210 arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING; |
| 211 } |
201 } | 212 } |
202 | 213 |
203 bool arg1_is_copy = (arg1_val.type() == TraceValue::TRACE_TYPE_STRING); | 214 bool arg_is_copy[kTraceMaxNumArgs]; |
204 bool arg2_is_copy = (arg2_val.type() == TraceValue::TRACE_TYPE_STRING); | 215 for (i = 0; i < num_args; ++i) { |
205 | 216 // We only take a copy of arg_vals if they are of type COPY_STRING. |
206 // We only take a copy of arg_vals if they are of type string (not static | 217 arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING); |
207 // string), regardless of the |copy| flag. | 218 if (arg_is_copy[i]) |
208 if (arg1_is_copy) | 219 alloc_size += GetAllocLength(arg_values_[i].as_string); |
209 alloc_size += GetAllocLength(arg1_val.as_string()); | 220 } |
210 if (arg2_is_copy) | |
211 alloc_size += GetAllocLength(arg2_val.as_string()); | |
212 | 221 |
213 if (alloc_size) { | 222 if (alloc_size) { |
214 parameter_copy_storage_ = new base::RefCountedString; | 223 parameter_copy_storage_ = new base::RefCountedString; |
215 parameter_copy_storage_->data().resize(alloc_size); | 224 parameter_copy_storage_->data().resize(alloc_size); |
216 char* ptr = string_as_array(¶meter_copy_storage_->data()); | 225 char* ptr = string_as_array(¶meter_copy_storage_->data()); |
217 const char* end = ptr + alloc_size; | 226 const char* end = ptr + alloc_size; |
218 if (copy) { | 227 if (copy) { |
219 CopyTraceEventParameter(&ptr, &name_, end); | 228 CopyTraceEventParameter(&ptr, &name_, end); |
220 CopyTraceEventParameter(&ptr, &arg_names_[0], end); | 229 for (i = 0; i < num_args; ++i) |
221 CopyTraceEventParameter(&ptr, &arg_names_[1], end); | 230 CopyTraceEventParameter(&ptr, &arg_names_[i], end); |
222 } | 231 } |
223 if (arg1_is_copy) | 232 for (i = 0; i < num_args; ++i) { |
224 CopyTraceEventParameter(&ptr, arg_values_[0].as_assignable_string(), end); | 233 if (arg_is_copy[i]) |
225 if (arg2_is_copy) | 234 CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end); |
226 CopyTraceEventParameter(&ptr, arg_values_[1].as_assignable_string(), end); | 235 } |
227 DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; | 236 DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; |
228 } | 237 } |
229 } | 238 } |
230 | 239 |
231 TraceEvent::~TraceEvent() { | 240 TraceEvent::~TraceEvent() { |
232 } | 241 } |
233 | 242 |
234 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, | 243 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, |
235 size_t start, | 244 size_t start, |
236 size_t count, | 245 size_t count, |
237 std::string* out) { | 246 std::string* out) { |
238 for (size_t i = 0; i < count && start + i < events.size(); ++i) { | 247 for (size_t i = 0; i < count && start + i < events.size(); ++i) { |
239 if (i > 0) | 248 if (i > 0) |
240 *out += ","; | 249 *out += ","; |
241 events[i + start].AppendAsJSON(out); | 250 events[i + start].AppendAsJSON(out); |
242 } | 251 } |
243 } | 252 } |
244 | 253 |
245 void TraceEvent::AppendAsJSON(std::string* out) const { | 254 void TraceEvent::AppendAsJSON(std::string* out) const { |
246 const char phase_char = GetPhaseChar(phase_); | |
247 int64 time_int64 = timestamp_.ToInternalValue(); | 255 int64 time_int64 = timestamp_.ToInternalValue(); |
248 int process_id = TraceLog::GetInstance()->process_id(); | 256 int process_id = TraceLog::GetInstance()->process_id(); |
249 // Category name checked at category creation time. | 257 // Category name checked at category creation time. |
250 DCHECK(!strchr(name_, '"')); | 258 DCHECK(!strchr(name_, '"')); |
251 StringAppendF(out, | 259 StringAppendF(out, |
252 "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 "," | 260 "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 "," |
253 "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{", | 261 "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{", |
254 category_->name, | 262 TraceLog::GetCategoryName(category_enabled_), |
255 process_id, | 263 process_id, |
256 thread_id_, | 264 thread_id_, |
257 time_int64, | 265 time_int64, |
258 phase_char, | 266 phase_, |
259 name_); | 267 name_); |
260 | 268 |
261 // Output argument names and values, stop at first NULL argument name. | 269 // Output argument names and values, stop at first NULL argument name. |
262 for (size_t i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { | 270 for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { |
263 if (i > 0) | 271 if (i > 0) |
264 *out += ","; | 272 *out += ","; |
265 *out += "\""; | 273 *out += "\""; |
266 *out += arg_names_[i]; | 274 *out += arg_names_[i]; |
267 *out += "\":"; | 275 *out += "\":"; |
268 arg_values_[i].AppendAsJSON(out); | 276 AppendValueAsJSON(arg_types_[i], arg_values_[i], out); |
269 } | 277 } |
270 *out += "}"; | 278 *out += "}"; |
271 | 279 |
272 // If id_ is set, print it out as a hex string so we don't loose any | 280 // If id_ is set, print it out as a hex string so we don't loose any |
273 // bits (it might be a 64-bit pointer). | 281 // bits (it might be a 64-bit pointer). |
274 if (flags_ & TRACE_EVENT_FLAG_HAS_ID) | 282 if (flags_ & TRACE_EVENT_FLAG_HAS_ID) |
275 StringAppendF(out, ",\"id\":\"%" PRIx64 "\"", id_.data()); | 283 StringAppendF(out, ",\"id\":\"%" PRIx64 "\"", id_); |
276 *out += "}"; | 284 *out += "}"; |
277 } | 285 } |
278 | 286 |
279 //////////////////////////////////////////////////////////////////////////////// | 287 //////////////////////////////////////////////////////////////////////////////// |
280 // | 288 // |
281 // TraceResultBuffer | 289 // TraceResultBuffer |
282 // | 290 // |
283 //////////////////////////////////////////////////////////////////////////////// | 291 //////////////////////////////////////////////////////////////////////////////// |
284 | 292 |
285 TraceResultBuffer::OutputCallback | 293 TraceResultBuffer::OutputCallback |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 } | 339 } |
332 | 340 |
333 TraceLog::TraceLog() | 341 TraceLog::TraceLog() |
334 : enabled_(false) { | 342 : enabled_(false) { |
335 SetProcessID(static_cast<int>(base::GetCurrentProcId())); | 343 SetProcessID(static_cast<int>(base::GetCurrentProcId())); |
336 } | 344 } |
337 | 345 |
338 TraceLog::~TraceLog() { | 346 TraceLog::~TraceLog() { |
339 } | 347 } |
340 | 348 |
341 const TraceCategory* TraceLog::GetCategory(const char* name) { | 349 const volatile bool* TraceLog::GetCategoryEnabled(const char* name) { |
342 TraceLog* tracelog = GetInstance(); | 350 TraceLog* tracelog = GetInstance(); |
343 if (!tracelog){ | 351 if (!tracelog){ |
344 DCHECK(!g_category_already_shutdown->enabled); | 352 DCHECK(!g_category_enabled[g_category_already_shutdown]); |
345 return g_category_already_shutdown; | 353 return &g_category_enabled[g_category_already_shutdown]; |
346 } | 354 } |
347 return tracelog->GetCategoryInternal(name); | 355 return tracelog->GetCategoryEnabledInternal(name); |
| 356 } |
| 357 |
| 358 const char* TraceLog::GetCategoryName(const volatile bool* category_enabled) { |
| 359 // Calculate the index of the category by finding category_enabled in |
| 360 // g_category_enabled array. |
| 361 uintptr_t category_begin = reinterpret_cast<uintptr_t>(g_category_enabled); |
| 362 uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_enabled); |
| 363 DCHECK(category_ptr >= category_begin && |
| 364 category_ptr < reinterpret_cast<uintptr_t>(g_category_enabled + |
| 365 TRACE_EVENT_MAX_CATEGORIES)) << |
| 366 "out of bounds category pointer"; |
| 367 uintptr_t category_index = |
| 368 (category_ptr - category_begin) / sizeof(g_category_enabled[0]); |
| 369 return g_categories[category_index]; |
348 } | 370 } |
349 | 371 |
350 static void EnableMatchingCategory(int category_index, | 372 static void EnableMatchingCategory(int category_index, |
351 const std::vector<std::string>& patterns, | 373 const std::vector<std::string>& patterns, |
352 bool is_included) { | 374 bool is_included) { |
353 std::vector<std::string>::const_iterator ci = patterns.begin(); | 375 std::vector<std::string>::const_iterator ci = patterns.begin(); |
354 bool is_match = false; | 376 bool is_match = false; |
355 for (; ci != patterns.end(); ++ci) { | 377 for (; ci != patterns.end(); ++ci) { |
356 is_match = MatchPattern(g_categories[category_index].name, ci->c_str()); | 378 is_match = MatchPattern(g_categories[category_index], ci->c_str()); |
357 if (is_match) | 379 if (is_match) |
358 break; | 380 break; |
359 } | 381 } |
360 ANNOTATE_BENIGN_RACE(&g_categories[category_index].enabled, | 382 ANNOTATE_BENIGN_RACE(&g_category_enabled[category_index], |
361 "trace_event category enabled"); | 383 "trace_event category enabled"); |
362 g_categories[category_index].enabled = is_match ? is_included : !is_included; | 384 g_category_enabled[category_index] = is_match ? is_included : !is_included; |
363 } | 385 } |
364 | 386 |
365 // Enable/disable each category based on the category filters in |patterns|. | 387 // Enable/disable each category based on the category filters in |patterns|. |
366 // If the category name matches one of the patterns, its enabled status is set | 388 // If the category name matches one of the patterns, its enabled status is set |
367 // to |is_included|. Otherwise its enabled status is set to !|is_included|. | 389 // to |is_included|. Otherwise its enabled status is set to !|is_included|. |
368 static void EnableMatchingCategories(const std::vector<std::string>& patterns, | 390 static void EnableMatchingCategories(const std::vector<std::string>& patterns, |
369 bool is_included) { | 391 bool is_included) { |
370 for (int i = 0; i < g_category_index; i++) | 392 for (int i = 0; i < g_category_index; i++) |
371 EnableMatchingCategory(i, patterns, is_included); | 393 EnableMatchingCategory(i, patterns, is_included); |
372 } | 394 } |
373 | 395 |
374 const TraceCategory* TraceLog::GetCategoryInternal(const char* name) { | 396 const volatile bool* TraceLog::GetCategoryEnabledInternal(const char* name) { |
375 AutoLock lock(lock_); | 397 AutoLock lock(lock_); |
376 DCHECK(!strchr(name, '"')) << "Category names may not contain double quote"; | 398 DCHECK(!strchr(name, '"')) << "Category names may not contain double quote"; |
377 | 399 |
378 // Search for pre-existing category matching this name | 400 // Search for pre-existing category matching this name |
379 for (int i = 0; i < g_category_index; i++) { | 401 for (int i = 0; i < g_category_index; i++) { |
380 if (strcmp(g_categories[i].name, name) == 0) | 402 if (strcmp(g_categories[i], name) == 0) |
381 return &g_categories[i]; | 403 return &g_category_enabled[i]; |
382 } | 404 } |
383 | 405 |
384 // Create a new category | 406 // Create a new category |
385 DCHECK(g_category_index < TRACE_EVENT_MAX_CATEGORIES) << | 407 DCHECK(g_category_index < TRACE_EVENT_MAX_CATEGORIES) << |
386 "must increase TRACE_EVENT_MAX_CATEGORIES"; | 408 "must increase TRACE_EVENT_MAX_CATEGORIES"; |
387 if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) { | 409 if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) { |
388 int new_index = g_category_index++; | 410 int new_index = g_category_index++; |
389 g_categories[new_index].name = name; | 411 g_categories[new_index] = name; |
390 DCHECK(!g_categories[new_index].enabled); | 412 DCHECK(!g_category_enabled[new_index]); |
391 if (enabled_) { | 413 if (enabled_) { |
392 // Note that if both included and excluded_categories are empty, the else | 414 // Note that if both included and excluded_categories are empty, the else |
393 // clause below excludes nothing, thereby enabling this category. | 415 // clause below excludes nothing, thereby enabling this category. |
394 if (!included_categories_.empty()) | 416 if (!included_categories_.empty()) |
395 EnableMatchingCategory(new_index, included_categories_, true); | 417 EnableMatchingCategory(new_index, included_categories_, true); |
396 else | 418 else |
397 EnableMatchingCategory(new_index, excluded_categories_, false); | 419 EnableMatchingCategory(new_index, excluded_categories_, false); |
398 } else { | 420 } else { |
399 ANNOTATE_BENIGN_RACE(&g_categories[new_index].enabled, | 421 ANNOTATE_BENIGN_RACE(&g_category_enabled[new_index], |
400 "trace_event category enabled"); | 422 "trace_event category enabled"); |
401 g_categories[new_index].enabled = false; | 423 g_category_enabled[new_index] = false; |
402 } | 424 } |
403 return &g_categories[new_index]; | 425 return &g_category_enabled[new_index]; |
404 } else { | 426 } else { |
405 return g_category_categories_exhausted; | 427 return &g_category_enabled[g_category_categories_exhausted]; |
406 } | 428 } |
407 } | 429 } |
408 | 430 |
409 void TraceLog::GetKnownCategories(std::vector<std::string>* categories) { | 431 void TraceLog::GetKnownCategories(std::vector<std::string>* categories) { |
410 AutoLock lock(lock_); | 432 AutoLock lock(lock_); |
411 for (int i = 0; i < g_category_index; i++) | 433 for (int i = 0; i < g_category_index; i++) |
412 categories->push_back(g_categories[i].name); | 434 categories->push_back(g_categories[i]); |
413 } | 435 } |
414 | 436 |
415 void TraceLog::SetEnabled(const std::vector<std::string>& included_categories, | 437 void TraceLog::SetEnabled(const std::vector<std::string>& included_categories, |
416 const std::vector<std::string>& excluded_categories) { | 438 const std::vector<std::string>& excluded_categories) { |
417 AutoLock lock(lock_); | 439 AutoLock lock(lock_); |
418 if (enabled_) | 440 if (enabled_) |
419 return; | 441 return; |
420 logged_events_.reserve(1024); | 442 logged_events_.reserve(1024); |
421 enabled_ = true; | 443 enabled_ = true; |
422 included_categories_ = included_categories; | 444 included_categories_ = included_categories; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 void TraceLog::SetDisabled() { | 485 void TraceLog::SetDisabled() { |
464 { | 486 { |
465 AutoLock lock(lock_); | 487 AutoLock lock(lock_); |
466 if (!enabled_) | 488 if (!enabled_) |
467 return; | 489 return; |
468 | 490 |
469 enabled_ = false; | 491 enabled_ = false; |
470 included_categories_.clear(); | 492 included_categories_.clear(); |
471 excluded_categories_.clear(); | 493 excluded_categories_.clear(); |
472 for (int i = 0; i < g_category_index; i++) | 494 for (int i = 0; i < g_category_index; i++) |
473 g_categories[i].enabled = false; | 495 g_category_enabled[i] = false; |
474 AddThreadNameMetadataEvents(); | 496 AddThreadNameMetadataEvents(); |
475 AddClockSyncMetadataEvents(); | 497 AddClockSyncMetadataEvents(); |
476 } // release lock | 498 } // release lock |
477 Flush(); | 499 Flush(); |
478 } | 500 } |
479 | 501 |
480 void TraceLog::SetEnabled(bool enabled) { | 502 void TraceLog::SetEnabled(bool enabled) { |
481 if (enabled) | 503 if (enabled) |
482 SetEnabled(std::vector<std::string>(), std::vector<std::string>()); | 504 SetEnabled(std::vector<std::string>(), std::vector<std::string>()); |
483 else | 505 else |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 scoped_refptr<RefCountedString> json_events_str_ptr = | 538 scoped_refptr<RefCountedString> json_events_str_ptr = |
517 new RefCountedString(); | 539 new RefCountedString(); |
518 TraceEvent::AppendEventsAsJSON(previous_logged_events, | 540 TraceEvent::AppendEventsAsJSON(previous_logged_events, |
519 i, | 541 i, |
520 kTraceEventBatchSize, | 542 kTraceEventBatchSize, |
521 &(json_events_str_ptr->data)); | 543 &(json_events_str_ptr->data)); |
522 output_callback_copy.Run(json_events_str_ptr); | 544 output_callback_copy.Run(json_events_str_ptr); |
523 } | 545 } |
524 } | 546 } |
525 | 547 |
526 int TraceLog::AddTraceEvent(TraceEventPhase phase, | 548 int TraceLog::AddTraceEvent(char phase, |
527 const TraceCategory* category, | 549 const volatile bool* category_enabled, |
528 const char* name, | 550 const char* name, |
529 TraceID id, | 551 uint64 id, |
530 const char* arg1_name, TraceValue arg1_val, | 552 int num_args, |
531 const char* arg2_name, TraceValue arg2_val, | 553 const char** arg_names, |
| 554 const uint8* arg_types, |
| 555 const uint64* arg_values, |
532 int threshold_begin_id, | 556 int threshold_begin_id, |
533 int64 threshold, | 557 int64 threshold, |
534 TraceEventFlags flags) { | 558 uint8 flags) { |
535 DCHECK(name); | 559 DCHECK(name); |
536 TimeTicks now = TimeTicks::HighResNow(); | 560 TimeTicks now = TimeTicks::HighResNow(); |
537 BufferFullCallback buffer_full_callback_copy; | 561 BufferFullCallback buffer_full_callback_copy; |
538 int ret_begin_id = -1; | 562 int ret_begin_id = -1; |
539 { | 563 { |
540 AutoLock lock(lock_); | 564 AutoLock lock(lock_); |
541 if (!category->enabled) | 565 if (!*category_enabled) |
542 return -1; | 566 return -1; |
543 if (logged_events_.size() >= kTraceEventBufferSize) | 567 if (logged_events_.size() >= kTraceEventBufferSize) |
544 return -1; | 568 return -1; |
545 | 569 |
546 int thread_id = static_cast<int>(PlatformThread::CurrentId()); | 570 int thread_id = static_cast<int>(PlatformThread::CurrentId()); |
547 | 571 |
548 const char* new_name = PlatformThread::GetName(); | 572 const char* new_name = PlatformThread::GetName(); |
549 // Check if the thread name has been set or changed since the previous | 573 // Check if the thread name has been set or changed since the previous |
550 // call (if any), but don't bother if the new name is empty. Note this will | 574 // call (if any), but don't bother if the new name is empty. Note this will |
551 // not detect a thread name change within the same char* buffer address: we | 575 // not detect a thread name change within the same char* buffer address: we |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 // Remove begin event and do not add end event. | 609 // Remove begin event and do not add end event. |
586 // This will be expensive if there have been other events in the | 610 // This will be expensive if there have been other events in the |
587 // mean time (should be rare). | 611 // mean time (should be rare). |
588 logged_events_.erase(logged_events_.begin() + begin_i); | 612 logged_events_.erase(logged_events_.begin() + begin_i); |
589 return -1; | 613 return -1; |
590 } | 614 } |
591 } | 615 } |
592 ret_begin_id = static_cast<int>(logged_events_.size()); | 616 ret_begin_id = static_cast<int>(logged_events_.size()); |
593 logged_events_.push_back( | 617 logged_events_.push_back( |
594 TraceEvent(thread_id, | 618 TraceEvent(thread_id, |
595 now, phase, category, name, id, | 619 now, phase, category_enabled, name, id, |
596 arg1_name, arg1_val, | 620 num_args, arg_names, arg_types, arg_values, |
597 arg2_name, arg2_val, | |
598 flags)); | 621 flags)); |
599 | 622 |
600 if (logged_events_.size() == kTraceEventBufferSize) { | 623 if (logged_events_.size() == kTraceEventBufferSize) { |
601 buffer_full_callback_copy = buffer_full_callback_; | 624 buffer_full_callback_copy = buffer_full_callback_; |
602 } | 625 } |
603 } // release lock | 626 } // release lock |
604 | 627 |
605 if (!buffer_full_callback_copy.is_null()) | 628 if (!buffer_full_callback_copy.is_null()) |
606 buffer_full_callback_copy.Run(); | 629 buffer_full_callback_copy.Run(); |
607 | 630 |
608 return ret_begin_id; | 631 return ret_begin_id; |
609 } | 632 } |
610 | 633 |
611 void TraceLog::AddTraceEventEtw(TraceEventPhase phase, | 634 void TraceLog::AddTraceEventEtw(char phase, |
612 const char* name, | 635 const char* name, |
613 const void* id, | 636 const void* id, |
614 const char* extra) { | 637 const char* extra) { |
615 #if defined(OS_WIN) | 638 #if defined(OS_WIN) |
616 TraceEventETWProvider::Trace(name, phase, id, extra); | 639 TraceEventETWProvider::Trace(name, phase, id, extra); |
617 #endif | 640 #endif |
618 INTERNAL_TRACE_EVENT_ADD(phase, | 641 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, |
619 "ETW Trace Event", name, "id", id, "extra", TRACE_STR_COPY(extra), | 642 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); |
620 TRACE_EVENT_FLAG_COPY); | |
621 } | 643 } |
622 | 644 |
623 void TraceLog::AddTraceEventEtw(TraceEventPhase phase, | 645 void TraceLog::AddTraceEventEtw(char phase, |
624 const char* name, | 646 const char* name, |
625 const void* id, | 647 const void* id, |
626 const std::string& extra) | 648 const std::string& extra) |
627 { | 649 { |
628 #if defined(OS_WIN) | 650 #if defined(OS_WIN) |
629 TraceEventETWProvider::Trace(name, phase, id, extra); | 651 TraceEventETWProvider::Trace(name, phase, id, extra); |
630 #endif | 652 #endif |
631 INTERNAL_TRACE_EVENT_ADD(phase, | 653 INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, |
632 "ETW Trace Event", name, "id", id, "extra", extra, | 654 TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); |
633 TRACE_EVENT_FLAG_COPY); | |
634 } | 655 } |
635 | 656 |
636 int TraceLog::AddCounterEvent(const TraceCategory* category, | 657 void TraceLog::AddCounterEvent(const volatile bool* category_enabled, |
637 const char* name, | 658 const char* name, |
638 TraceID id, | 659 uint64 id, |
639 const char* value1_name, int32 value1_val, | 660 const char* value1_name, int32 value1_val, |
640 const char* value2_name, int32 value2_val, | 661 const char* value2_name, int32 value2_val, |
641 TraceEventFlags flags) { | 662 uint8 flags) { |
642 return AddTraceEvent(TRACE_EVENT_PHASE_COUNTER, | 663 int num_args = value2_name ? 2 : 1; |
643 category, | 664 const char* arg_names[2] = {value1_name, value2_name}; |
644 name, | 665 uint8 arg_types[2]; |
645 id, | 666 uint64 arg_values[2]; |
646 value1_name, value1_val, | 667 base::debug::internal::SetTraceValue(value1_val, &arg_types[0], |
647 value2_name, value2_val, | 668 &arg_values[0]); |
648 -1, 0, | 669 base::debug::internal::SetTraceValue(value2_val, &arg_types[1], |
649 flags); | 670 &arg_values[1]); |
| 671 AddTraceEvent(TRACE_EVENT_PHASE_COUNTER, |
| 672 category_enabled, |
| 673 name, |
| 674 id, |
| 675 num_args, |
| 676 arg_names, |
| 677 arg_types, |
| 678 arg_values, |
| 679 kNoThreshholdBeginId, kNoThresholdValue, |
| 680 flags); |
650 } | 681 } |
651 | 682 |
652 void TraceLog::AddClockSyncMetadataEvents() { | 683 void TraceLog::AddClockSyncMetadataEvents() { |
653 #if defined(OS_ANDROID) | 684 #if defined(OS_ANDROID) |
654 // Since Android does not support sched_setaffinity, we cannot establish clock | 685 // Since Android does not support sched_setaffinity, we cannot establish clock |
655 // sync unless the scheduler clock is set to global. If the trace_clock file | 686 // sync unless the scheduler clock is set to global. If the trace_clock file |
656 // can't be read, we will assume the kernel doesn't support tracing and do | 687 // can't be read, we will assume the kernel doesn't support tracing and do |
657 // nothing. | 688 // nothing. |
658 std::string clock_mode; | 689 std::string clock_mode; |
659 if (!file_util::ReadFileToString( | 690 if (!file_util::ReadFileToString( |
(...skipping 26 matching lines...) Expand all Loading... |
686 return; | 717 return; |
687 } | 718 } |
688 #endif | 719 #endif |
689 } | 720 } |
690 | 721 |
691 void TraceLog::AddThreadNameMetadataEvents() { | 722 void TraceLog::AddThreadNameMetadataEvents() { |
692 lock_.AssertAcquired(); | 723 lock_.AssertAcquired(); |
693 for(base::hash_map<int, std::string>::iterator it = thread_names_.begin(); | 724 for(base::hash_map<int, std::string>::iterator it = thread_names_.begin(); |
694 it != thread_names_.end(); | 725 it != thread_names_.end(); |
695 it++) { | 726 it++) { |
696 if (!it->second.empty()) | 727 if (!it->second.empty()) { |
| 728 int num_args = 1; |
| 729 const char* arg_name = "name"; |
| 730 uint8 arg_type; |
| 731 uint64 arg_value; |
| 732 base::debug::internal::SetTraceValue(it->second, &arg_type, &arg_value); |
697 logged_events_.push_back( | 733 logged_events_.push_back( |
698 TraceEvent(it->first, | 734 TraceEvent(it->first, |
699 TimeTicks(), TRACE_EVENT_PHASE_METADATA, | 735 TimeTicks(), TRACE_EVENT_PHASE_METADATA, |
700 g_category_metadata, "thread_name", 0, | 736 &g_category_enabled[g_category_metadata], |
701 "name", it->second, | 737 "thread_name", kNoEventId, |
702 NULL, 0, | 738 num_args, &arg_name, &arg_type, &arg_value, |
703 TRACE_EVENT_FLAG_NONE)); | 739 TRACE_EVENT_FLAG_NONE)); |
| 740 } |
704 } | 741 } |
705 } | 742 } |
706 | 743 |
707 void TraceLog::DeleteForTesting() { | 744 void TraceLog::DeleteForTesting() { |
708 DeleteTraceLogForTesting::Delete(); | 745 DeleteTraceLogForTesting::Delete(); |
709 } | 746 } |
710 | 747 |
711 void TraceLog::Resurrect() { | 748 void TraceLog::Resurrect() { |
712 StaticMemorySingletonTraits<TraceLog>::Resurrect(); | 749 StaticMemorySingletonTraits<TraceLog>::Resurrect(); |
713 } | 750 } |
714 | 751 |
715 void TraceLog::SetProcessID(int process_id) { | 752 void TraceLog::SetProcessID(int process_id) { |
716 process_id_ = process_id; | 753 process_id_ = process_id; |
717 // Create a FNV hash from the process ID for XORing. | 754 // Create a FNV hash from the process ID for XORing. |
718 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. | 755 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. |
719 uint64 offset_basis = 14695981039346656037ull; | 756 uint64 offset_basis = 14695981039346656037ull; |
720 uint64 fnv_prime = 1099511628211ull; | 757 uint64 fnv_prime = 1099511628211ull; |
721 unsigned long long pid = static_cast<unsigned long long>(process_id_); | 758 unsigned long long pid = static_cast<unsigned long long>(process_id_); |
722 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; | 759 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; |
723 } | 760 } |
724 | 761 |
725 namespace internal { | 762 namespace internal { |
726 | 763 |
727 void TraceEndOnScopeClose::Initialize(const TraceCategory* category, | 764 void TraceEndOnScopeClose::Initialize(const volatile bool* category_enabled, |
728 const char* name) { | 765 const char* name) { |
729 data_.category = category; | 766 data_.category_enabled = category_enabled; |
730 data_.name = name; | 767 data_.name = name; |
731 p_data_ = &data_; | 768 p_data_ = &data_; |
732 } | 769 } |
733 | 770 |
734 void TraceEndOnScopeClose::AddEventIfEnabled() { | 771 void TraceEndOnScopeClose::AddEventIfEnabled() { |
735 // Only called when p_data_ is non-null. | 772 // Only called when p_data_ is non-null. |
736 if (p_data_->category->enabled) { | 773 if (*p_data_->category_enabled) { |
737 base::debug::TraceLog::GetInstance()->AddTraceEvent( | 774 TRACE_EVENT_API_ADD_TRACE_EVENT( |
738 TRACE_EVENT_PHASE_END, | 775 TRACE_EVENT_PHASE_END, |
739 p_data_->category, | 776 p_data_->category_enabled, |
740 p_data_->name, kNoEventId, | 777 p_data_->name, kNoEventId, |
741 kNoArgName, kNoArgValue, kNoArgName, kNoArgValue, | 778 kZeroArgs, kNoArgNames, kNoArgTypes, kNoArgValues, |
742 kNoThreshholdBeginId, kNoThresholdValue, TRACE_EVENT_FLAG_NONE); | 779 kNoThreshholdBeginId, kNoThresholdValue, TRACE_EVENT_FLAG_NONE); |
743 } | 780 } |
744 } | 781 } |
745 | 782 |
746 void TraceEndOnScopeCloseThreshold::Initialize(const TraceCategory* category, | 783 void TraceEndOnScopeCloseThreshold::Initialize( |
747 const char* name, | 784 const volatile bool* category_enabled, |
748 int threshold_begin_id, | 785 const char* name, |
749 int64 threshold) { | 786 int threshold_begin_id, |
750 data_.category = category; | 787 int64 threshold) { |
| 788 data_.category_enabled = category_enabled; |
751 data_.name = name; | 789 data_.name = name; |
752 data_.threshold_begin_id = threshold_begin_id; | 790 data_.threshold_begin_id = threshold_begin_id; |
753 data_.threshold = threshold; | 791 data_.threshold = threshold; |
754 p_data_ = &data_; | 792 p_data_ = &data_; |
755 } | 793 } |
756 | 794 |
757 void TraceEndOnScopeCloseThreshold::AddEventIfEnabled() { | 795 void TraceEndOnScopeCloseThreshold::AddEventIfEnabled() { |
758 // Only called when p_data_ is non-null. | 796 // Only called when p_data_ is non-null. |
759 if (p_data_->category->enabled) { | 797 if (*p_data_->category_enabled) { |
760 base::debug::TraceLog::GetInstance()->AddTraceEvent( | 798 TRACE_EVENT_API_ADD_TRACE_EVENT( |
761 TRACE_EVENT_PHASE_END, | 799 TRACE_EVENT_PHASE_END, |
762 p_data_->category, | 800 p_data_->category_enabled, |
763 p_data_->name, kNoEventId, | 801 p_data_->name, kNoEventId, |
764 kNoArgName, kNoArgValue, kNoArgName, kNoArgValue, | 802 kZeroArgs, kNoArgNames, kNoArgTypes, kNoArgValues, |
765 p_data_->threshold_begin_id, p_data_->threshold, | 803 p_data_->threshold_begin_id, p_data_->threshold, |
766 TRACE_EVENT_FLAG_NONE); | 804 TRACE_EVENT_FLAG_NONE); |
767 } | 805 } |
768 } | 806 } |
769 | 807 |
770 } // namespace internal | 808 } // namespace internal |
771 | 809 |
772 } // namespace debug | 810 } // namespace debug |
773 } // namespace base | 811 } // namespace base |
OLD | NEW |