OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 #include "webrtc/base/event_tracer.h" | 10 #include "webrtc/base/event_tracer.h" |
11 | 11 |
12 #include <inttypes.h> | 12 #include <inttypes.h> |
13 | 13 |
| 14 #include <string> |
14 #include <vector> | 15 #include <vector> |
15 | 16 |
16 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
17 #include "webrtc/base/criticalsection.h" | 18 #include "webrtc/base/criticalsection.h" |
18 #include "webrtc/base/event.h" | 19 #include "webrtc/base/event.h" |
19 #include "webrtc/base/logging.h" | 20 #include "webrtc/base/logging.h" |
20 #include "webrtc/base/platform_thread.h" | 21 #include "webrtc/base/platform_thread.h" |
| 22 #include "webrtc/base/stringutils.h" |
21 #include "webrtc/base/timeutils.h" | 23 #include "webrtc/base/timeutils.h" |
22 #include "webrtc/base/trace_event.h" | 24 #include "webrtc/base/trace_event.h" |
23 | 25 |
| 26 // This is a guesstimate that should be enough in most cases. |
| 27 static const size_t kEventLoggerArgsStrBufferInitialSize = 256; |
| 28 static const size_t kTraceArgBufferLength = 32; |
| 29 |
24 namespace webrtc { | 30 namespace webrtc { |
25 | 31 |
26 namespace { | 32 namespace { |
27 | 33 |
28 GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr; | 34 GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr; |
29 AddTraceEventPtr g_add_trace_event_ptr = nullptr; | 35 AddTraceEventPtr g_add_trace_event_ptr = nullptr; |
30 | 36 |
31 } // namespace | 37 } // namespace |
32 | 38 |
33 void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, | 39 void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 class EventLogger final { | 89 class EventLogger final { |
84 public: | 90 public: |
85 EventLogger() | 91 EventLogger() |
86 : logging_thread_(EventTracingThreadFunc, this, "EventTracingThread"), | 92 : logging_thread_(EventTracingThreadFunc, this, "EventTracingThread"), |
87 shutdown_event_(false, false) {} | 93 shutdown_event_(false, false) {} |
88 ~EventLogger() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); } | 94 ~EventLogger() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); } |
89 | 95 |
90 void AddTraceEvent(const char* name, | 96 void AddTraceEvent(const char* name, |
91 const unsigned char* category_enabled, | 97 const unsigned char* category_enabled, |
92 char phase, | 98 char phase, |
| 99 int num_args, |
| 100 const char** arg_names, |
| 101 const unsigned char* arg_types, |
| 102 const unsigned long long* arg_values, |
93 uint64_t timestamp, | 103 uint64_t timestamp, |
94 int pid, | 104 int pid, |
95 rtc::PlatformThreadId thread_id) { | 105 rtc::PlatformThreadId thread_id) { |
| 106 std::vector<TraceArg> args(num_args); |
| 107 for (int i = 0; i < num_args; ++i) { |
| 108 TraceArg& arg = args[i]; |
| 109 arg.name = arg_names[i]; |
| 110 arg.type = arg_types[i]; |
| 111 arg.value.as_uint = arg_values[i]; |
| 112 |
| 113 // Value is a pointer to a temporary string, so we have to make a copy. |
| 114 if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { |
| 115 // Space for the string and for the terminating null character. |
| 116 size_t str_length = strlen(arg.value.as_string) + 1; |
| 117 char* str_copy = new char[str_length]; |
| 118 memcpy(str_copy, arg.value.as_string, str_length); |
| 119 arg.value.as_string = str_copy; |
| 120 } |
| 121 } |
96 rtc::CritScope lock(&crit_); | 122 rtc::CritScope lock(&crit_); |
97 trace_events_.push_back( | 123 trace_events_.push_back( |
98 {name, category_enabled, phase, timestamp, 1, thread_id}); | 124 {name, category_enabled, phase, args, timestamp, 1, thread_id}); |
99 } | 125 } |
100 | 126 |
101 // The TraceEvent format is documented here: | 127 // The TraceEvent format is documented here: |
102 // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAy
SU/preview | 128 // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAy
SU/preview |
103 void Log() { | 129 void Log() { |
104 RTC_DCHECK(output_file_); | 130 RTC_DCHECK(output_file_); |
105 static const int kLoggingIntervalMs = 100; | 131 static const int kLoggingIntervalMs = 100; |
106 fprintf(output_file_, "{ \"traceEvents\": [\n"); | 132 fprintf(output_file_, "{ \"traceEvents\": [\n"); |
107 bool has_logged_event = false; | 133 bool has_logged_event = false; |
108 while (true) { | 134 while (true) { |
109 bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs); | 135 bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs); |
110 std::vector<TraceEvent> events; | 136 std::vector<TraceEvent> events; |
111 { | 137 { |
112 rtc::CritScope lock(&crit_); | 138 rtc::CritScope lock(&crit_); |
113 trace_events_.swap(events); | 139 trace_events_.swap(events); |
114 } | 140 } |
115 for (const TraceEvent& e : events) { | 141 std::string args_str; |
| 142 args_str.reserve(kEventLoggerArgsStrBufferInitialSize); |
| 143 for (TraceEvent& e : events) { |
| 144 args_str.clear(); |
| 145 if (!e.args.empty()) { |
| 146 args_str += ", \"args\": {"; |
| 147 bool is_first_argument = true; |
| 148 for (TraceArg& arg : e.args) { |
| 149 if (!is_first_argument) |
| 150 args_str += ","; |
| 151 is_first_argument = false; |
| 152 args_str += " \""; |
| 153 args_str += arg.name; |
| 154 args_str += "\": "; |
| 155 args_str += TraceArgValueAsString(arg); |
| 156 |
| 157 // Delete our copy of the string. |
| 158 if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { |
| 159 delete[] arg.value.as_string; |
| 160 arg.value.as_string = nullptr; |
| 161 } |
| 162 } |
| 163 args_str += " }"; |
| 164 } |
116 fprintf(output_file_, | 165 fprintf(output_file_, |
117 "%s{ \"name\": \"%s\"" | 166 "%s{ \"name\": \"%s\"" |
118 ", \"cat\": \"%s\"" | 167 ", \"cat\": \"%s\"" |
119 ", \"ph\": \"%c\"" | 168 ", \"ph\": \"%c\"" |
120 ", \"ts\": %" PRIu64 | 169 ", \"ts\": %" PRIu64 |
121 ", \"pid\": %d" | 170 ", \"pid\": %d" |
122 #if defined(WEBRTC_WIN) | 171 #if defined(WEBRTC_WIN) |
123 ", \"tid\": %lu" | 172 ", \"tid\": %lu" |
124 #else | 173 #else |
125 ", \"tid\": %d" | 174 ", \"tid\": %d" |
126 #endif // defined(WEBRTC_WIN) | 175 #endif // defined(WEBRTC_WIN) |
| 176 "%s" |
127 "}\n", | 177 "}\n", |
128 has_logged_event ? "," : " ", e.name, e.category_enabled, | 178 has_logged_event ? "," : " ", e.name, e.category_enabled, |
129 e.phase, e.timestamp, e.pid, e.tid); | 179 e.phase, e.timestamp, e.pid, e.tid, args_str.c_str()); |
130 has_logged_event = true; | 180 has_logged_event = true; |
131 } | 181 } |
132 if (shutting_down) | 182 if (shutting_down) |
133 break; | 183 break; |
134 } | 184 } |
135 fprintf(output_file_, "]}\n"); | 185 fprintf(output_file_, "]}\n"); |
136 if (output_file_owned_) | 186 if (output_file_owned_) |
137 fclose(output_file_); | 187 fclose(output_file_); |
138 output_file_ = nullptr; | 188 output_file_ = nullptr; |
139 } | 189 } |
(...skipping 30 matching lines...) Expand all Loading... |
170 if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0) | 220 if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0) |
171 return; | 221 return; |
172 | 222 |
173 // Wake up logging thread to finish writing. | 223 // Wake up logging thread to finish writing. |
174 shutdown_event_.Set(); | 224 shutdown_event_.Set(); |
175 // Join the logging thread. | 225 // Join the logging thread. |
176 logging_thread_.Stop(); | 226 logging_thread_.Stop(); |
177 } | 227 } |
178 | 228 |
179 private: | 229 private: |
| 230 struct TraceArg { |
| 231 const char* name; |
| 232 unsigned char type; |
| 233 // Copied from webrtc/base/trace_event.h TraceValueUnion. |
| 234 union TraceArgValue { |
| 235 bool as_bool; |
| 236 unsigned long long as_uint; |
| 237 long long as_int; |
| 238 double as_double; |
| 239 const void* as_pointer; |
| 240 const char* as_string; |
| 241 } value; |
| 242 |
| 243 // Assert that the size of the union is equal to the size of the as_uint |
| 244 // field since we are assigning to arbitrary types using it. |
| 245 static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long), |
| 246 "Size of TraceArg value union is not equal to the size of " |
| 247 "the uint field of that union."); |
| 248 }; |
| 249 |
180 struct TraceEvent { | 250 struct TraceEvent { |
181 const char* name; | 251 const char* name; |
182 const unsigned char* category_enabled; | 252 const unsigned char* category_enabled; |
183 char phase; | 253 char phase; |
| 254 std::vector<TraceArg> args; |
184 uint64_t timestamp; | 255 uint64_t timestamp; |
185 int pid; | 256 int pid; |
186 rtc::PlatformThreadId tid; | 257 rtc::PlatformThreadId tid; |
187 }; | 258 }; |
188 | 259 |
| 260 static std::string TraceArgValueAsString(TraceArg arg) { |
| 261 std::string output; |
| 262 |
| 263 if (arg.type == TRACE_VALUE_TYPE_STRING || |
| 264 arg.type == TRACE_VALUE_TYPE_COPY_STRING) { |
| 265 // Space for every character to be an espaced character + two for |
| 266 // quatation marks. |
| 267 output.reserve(strlen(arg.value.as_string) * 2 + 2); |
| 268 output += '\"'; |
| 269 const char* c = arg.value.as_string; |
| 270 do { |
| 271 if (*c == '"' || *c == '\\') { |
| 272 output += '\\'; |
| 273 output += *c; |
| 274 } else { |
| 275 output += *c; |
| 276 } |
| 277 } while (*++c); |
| 278 output += '\"'; |
| 279 } else { |
| 280 output.resize(kTraceArgBufferLength); |
| 281 size_t print_length = 0; |
| 282 switch (arg.type) { |
| 283 case TRACE_VALUE_TYPE_BOOL: |
| 284 if (arg.value.as_bool) { |
| 285 strcpy(&output[0], "true"); |
| 286 print_length = 4; |
| 287 } else { |
| 288 strcpy(&output[0], "false"); |
| 289 print_length = 5; |
| 290 } |
| 291 break; |
| 292 case TRACE_VALUE_TYPE_UINT: |
| 293 print_length = sprintfn(&output[0], kTraceArgBufferLength, "%llu", |
| 294 arg.value.as_uint); |
| 295 break; |
| 296 case TRACE_VALUE_TYPE_INT: |
| 297 print_length = sprintfn(&output[0], kTraceArgBufferLength, "%lld", |
| 298 arg.value.as_int); |
| 299 break; |
| 300 case TRACE_VALUE_TYPE_DOUBLE: |
| 301 print_length = sprintfn(&output[0], kTraceArgBufferLength, "%f", |
| 302 arg.value.as_double); |
| 303 break; |
| 304 case TRACE_VALUE_TYPE_POINTER: |
| 305 print_length = sprintfn(&output[0], kTraceArgBufferLength, "\"%p\"", |
| 306 arg.value.as_pointer); |
| 307 break; |
| 308 } |
| 309 size_t output_length = print_length < kTraceArgBufferLength |
| 310 ? print_length |
| 311 : kTraceArgBufferLength - 1; |
| 312 // This will hopefully be very close to nop. On most implementations, it |
| 313 // just writes null byte and sets the length field of the string. |
| 314 output.resize(output_length); |
| 315 } |
| 316 |
| 317 return output; |
| 318 } |
| 319 |
189 rtc::CriticalSection crit_; | 320 rtc::CriticalSection crit_; |
190 std::vector<TraceEvent> trace_events_ GUARDED_BY(crit_); | 321 std::vector<TraceEvent> trace_events_ GUARDED_BY(crit_); |
191 rtc::PlatformThread logging_thread_; | 322 rtc::PlatformThread logging_thread_; |
192 rtc::Event shutdown_event_; | 323 rtc::Event shutdown_event_; |
193 rtc::ThreadChecker thread_checker_; | 324 rtc::ThreadChecker thread_checker_; |
194 FILE* output_file_ = nullptr; | 325 FILE* output_file_ = nullptr; |
195 bool output_file_owned_ = false; | 326 bool output_file_owned_ = false; |
196 }; | 327 }; |
197 | 328 |
198 static bool EventTracingThreadFunc(void* params) { | 329 static bool EventTracingThreadFunc(void* params) { |
(...skipping 23 matching lines...) Expand all Loading... |
222 unsigned long long id, | 353 unsigned long long id, |
223 int num_args, | 354 int num_args, |
224 const char** arg_names, | 355 const char** arg_names, |
225 const unsigned char* arg_types, | 356 const unsigned char* arg_types, |
226 const unsigned long long* arg_values, | 357 const unsigned long long* arg_values, |
227 unsigned char flags) { | 358 unsigned char flags) { |
228 // Fast path for when event tracing is inactive. | 359 // Fast path for when event tracing is inactive. |
229 if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) | 360 if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) |
230 return; | 361 return; |
231 | 362 |
232 g_event_logger->AddTraceEvent(name, category_enabled, phase, | 363 g_event_logger->AddTraceEvent(name, category_enabled, phase, num_args, |
| 364 arg_names, arg_types, arg_values, |
233 rtc::TimeMicros(), 1, rtc::CurrentThreadId()); | 365 rtc::TimeMicros(), 1, rtc::CurrentThreadId()); |
234 } | 366 } |
235 | 367 |
236 } // namespace | 368 } // namespace |
237 | 369 |
238 void SetupInternalTracer() { | 370 void SetupInternalTracer() { |
239 RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( | 371 RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( |
240 &g_event_logger, static_cast<EventLogger*>(nullptr), | 372 &g_event_logger, static_cast<EventLogger*>(nullptr), |
241 new EventLogger()) == nullptr); | 373 new EventLogger()) == nullptr); |
242 webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent); | 374 webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent); |
(...skipping 24 matching lines...) Expand all Loading... |
267 RTC_DCHECK(old_logger); | 399 RTC_DCHECK(old_logger); |
268 RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( | 400 RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( |
269 &g_event_logger, old_logger, | 401 &g_event_logger, old_logger, |
270 static_cast<EventLogger*>(nullptr)) == old_logger); | 402 static_cast<EventLogger*>(nullptr)) == old_logger); |
271 delete old_logger; | 403 delete old_logger; |
272 webrtc::SetupEventTracer(nullptr, nullptr); | 404 webrtc::SetupEventTracer(nullptr, nullptr); |
273 } | 405 } |
274 | 406 |
275 } // namespace tracing | 407 } // namespace tracing |
276 } // namespace rtc | 408 } // namespace rtc |
OLD | NEW |