Index: webrtc/base/event_tracer.cc |
diff --git a/webrtc/base/event_tracer.cc b/webrtc/base/event_tracer.cc |
index 5c6d39f0a49219d24cd307d1d2610eb13a54658f..2973955dd9df8b4451e652cf3fff8909bf9cb9d1 100644 |
--- a/webrtc/base/event_tracer.cc |
+++ b/webrtc/base/event_tracer.cc |
@@ -7,15 +7,27 @@ |
* in the file PATENTS. All contributing project authors may |
* be found in the AUTHORS file in the root of the source tree. |
*/ |
- |
#include "webrtc/base/event_tracer.h" |
+#include <inttypes.h> |
+ |
+#include <vector> |
+ |
+#include "webrtc/base/checks.h" |
+#include "webrtc/base/criticalsection.h" |
+#include "webrtc/base/event.h" |
+#include "webrtc/base/logging.h" |
+#include "webrtc/base/timeutils.h" |
+#include "webrtc/base/trace_event.h" |
+#include "webrtc/base/platform_thread.h" |
+#include "webrtc/system_wrappers/include/thread_wrapper.h" |
+ |
namespace webrtc { |
namespace { |
-GetCategoryEnabledPtr g_get_category_enabled_ptr = 0; |
-AddTraceEventPtr g_add_trace_event_ptr = 0; |
+GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr; |
+AddTraceEventPtr g_add_trace_event_ptr = nullptr; |
} // namespace |
@@ -57,4 +69,164 @@ void EventTracer::AddTraceEvent(char phase, |
} |
} |
+namespace { |
+ |
+struct TraceEvent { |
+ const char* name; |
+ const unsigned char* category_enabled; |
tommi
2015/11/20 13:49:54
uint8_t?
pbos-webrtc
2015/11/20 15:11:05
Consistent with AddTraceEvent functions.
|
+ char phase; |
tommi
2015/11/20 13:49:54
what is phase used for?
Is this code borrowed from
pbos-webrtc
2015/11/20 15:11:05
Done, by referring to webrtc/base/trace_event.h. W
|
+ uint64_t timestamp; |
+ int pid; |
+ rtc::PlatformThreadId tid; |
+}; |
+ |
+const unsigned char* InternalGetCategoryEnabled(const char* name) { |
+ return reinterpret_cast<const unsigned char*>( |
+ strstr(name, TRACE_DISABLED_BY_DEFAULT("")) == name ? "" : name); |
tommi
2015/11/20 13:49:54
I'm not groking what this actually does or is supp
pbos-webrtc
2015/11/20 15:11:05
Should be a prefix search, I was lazy and did strs
|
+} |
+ |
+static volatile int g_event_logging_active = 0; |
+static rtc::CriticalSection* g_event_crit; |
tommi
2015/11/20 13:49:54
also initialize?
can we bundle these variables in
pbos-webrtc
2015/11/20 15:11:05
class done
|
+static std::vector<TraceEvent>* g_event_trace_events GUARDED_BY(g_event_crit) = |
+ nullptr; |
+ |
+// Logging thread "members". |
+static ThreadWrapper* g_event_logging_thread = nullptr; |
+static rtc::Event* g_event_wakeup_event = nullptr; |
+static FILE* g_event_output_file = nullptr; |
+static bool g_event_output_file_owned; |
tommi
2015/11/20 13:49:54
and this one?
pbos-webrtc
2015/11/20 15:11:05
Done.
|
+ |
+void InternalAddTraceEvent(char phase, |
+ const unsigned char* category_enabled, |
+ const char* name, |
+ unsigned long long id, |
+ int num_args, |
+ const char** arg_names, |
+ const unsigned char* arg_types, |
+ const unsigned long long* arg_values, |
+ unsigned char flags) { |
+ // Fast path for when event tracing is inactive. |
+ if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) |
+ return; |
+ |
+ uint64_t timestamp = rtc::TimeMicros(); |
+ rtc::PlatformThreadId tid = rtc::CurrentThreadId(); |
+ rtc::CritScope lock(g_event_crit); |
+ if (g_event_trace_events == nullptr) |
+ return; |
+ g_event_trace_events->push_back( |
+ TraceEvent{name, category_enabled, phase, timestamp, 1, tid}); |
+} |
+ |
+// TODO(pbos): Log metadata for all threads, etc. |
+bool LoggingThread(void* obj) { |
+ static const int kLoggingIntervalMs = 100; |
+ fprintf(g_event_output_file, "{ \"traceEvents\": [\n"); |
+ bool has_logged_event = false; |
+ while (true) { |
+ g_event_wakeup_event->Wait(kLoggingIntervalMs); |
+ std::vector<TraceEvent> events; |
+ { |
+ rtc::CritScope lock(g_event_crit); |
+ g_event_trace_events->swap(events); |
+ } |
+ for (const TraceEvent e : events) { |
tommi
2015/11/20 13:49:54
copy by value intentionally or missing &?
pbos-webrtc
2015/11/20 15:11:05
Done.
|
+ fprintf(g_event_output_file, |
+ "%s{ \"name\": \"%s\"" |
+ ", \"cat\": \"%s\"" |
+ ", \"ph\": \"%c\"" |
+ ", \"ts\": %" PRIu64 |
+ ", \"pid\": %d" |
+ ", \"tid\": %d}\n", |
+ has_logged_event ? "," : " ", e.name, e.category_enabled, e.phase, |
+ e.timestamp, e.pid, e.tid); |
+ has_logged_event = true; |
+ } |
+ if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) |
+ break; |
+ } |
+ fprintf(g_event_output_file, "]}\n"); |
+ if (g_event_output_file_owned) |
+ fclose(g_event_output_file); |
+ { |
+ rtc::CritScope lock(g_event_crit); |
+ delete g_event_trace_events; |
+ g_event_trace_events = nullptr; |
+ } |
+ // We're done, so return false to prevent another run w/ wait. |
+ return false; |
+} |
+ |
+void StartInternalCaptureToFilePtr(FILE* output_file, |
+ bool file_owned_by_tracer) { |
+ RTC_DCHECK(!g_event_crit) << "Internal tracing not initialized."; |
+ RTC_DCHECK(!g_event_logging_thread) |
+ << "Internal tracing should not start twice."; |
+ RTC_DCHECK_EQ(0, rtc::AtomicOps::AcquireLoad(&g_event_logging_active)); |
+ g_event_output_file = output_file; |
tommi
2015/11/20 13:49:54
how do we know we're not overwriting a previous va
pbos-webrtc
2015/11/20 15:11:05
Assuming that start and stop are done on the same
|
+ g_event_output_file_owned = file_owned_by_tracer; |
+ { |
+ rtc::CritScope lock(g_event_crit); |
+ g_event_trace_events = new std::vector<TraceEvent>(); |
+ } |
+ g_event_wakeup_event = new rtc::Event(false, false); |
+ g_event_logging_thread = |
+ ThreadWrapper::CreateThread(&LoggingThread, nullptr, "EventTracingThread") |
tommi
2015/11/20 13:49:54
instead of having g_event_output_file be a global,
pbos-webrtc
2015/11/20 15:11:05
-> class
|
+ .release(); |
+ rtc::AtomicOps::ReleaseStore(&g_event_logging_active, 1); |
+ |
+ // Finally start, everything should be set up now. |
+ g_event_logging_thread->Start(); |
+} |
+ |
+} // namespace |
+ |
+// static |
+void EventTracer::SetupInternalTracer() { |
+ RTC_DCHECK(!g_get_category_enabled_ptr); |
+ RTC_DCHECK(!g_add_trace_event_ptr); |
+ g_event_crit = new rtc::CriticalSection(); |
+ SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent); |
+} |
+ |
+void EventTracer::StartInternalCaptureToFile(FILE* file) { |
+ StartInternalCaptureToFilePtr(file, false); |
+} |
+ |
+bool EventTracer::StartInternalCapture(const char* filename) { |
+ FILE* file = fopen(filename, "w"); |
+ if (!file) { |
+ LOG(LS_ERROR) << "Failed to open trace file '" << filename |
+ << "' for writing."; |
+ return false; |
+ } |
+ StartInternalCaptureToFilePtr(file, true); |
+ return true; |
+} |
+ |
+void EventTracer::StopInternalCapture() { |
+ // Abort if we're not currently logging. |
+ if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) |
tommi
2015/11/20 13:49:54
this should also be a CompareAndSwap since otherwi
pbos-webrtc
2015/11/20 15:11:05
This is only a best-effort fast path for early abo
|
+ return; |
+ // Disable event logging. |
+ rtc::AtomicOps::ReleaseStore(&g_event_logging_active, 0); |
+ // Wake up logging thread to finish writing. |
+ g_event_wakeup_event->Set(); |
+ // Join the logging thread. |
+ g_event_logging_thread->Stop(); |
+ delete g_event_logging_thread; |
+ delete g_event_wakeup_event; |
+ g_event_logging_thread = nullptr; |
+ g_event_wakeup_event = nullptr; |
+} |
+ |
+void EventTracer::ShutdownInternalTracer() { |
+ StopInternalCapture(); |
+ RTC_DCHECK(g_get_category_enabled_ptr == InternalGetCategoryEnabled); |
+ RTC_DCHECK(g_add_trace_event_ptr == InternalAddTraceEvent); |
+ SetupEventTracer(nullptr, nullptr); |
+ delete g_event_crit; |
+ g_event_crit = nullptr; |
+} |
+ |
} // namespace webrtc |