Chromium Code Reviews| Index: content/browser/tracing/tracing_controller_impl.cc |
| diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc |
| index 120a00787f4ad64adfbd2cfe2ba2dd94ec9f0a08..9d925054300739f187588120d1d0e2ca717a2399 100644 |
| --- a/content/browser/tracing/tracing_controller_impl.cc |
| +++ b/content/browser/tracing/tracing_controller_impl.cc |
| @@ -20,6 +20,13 @@ |
| #include "chromeos/dbus/debug_daemon_client.h" |
| #endif |
| +#if defined(OS_WIN) |
| +#include "base/values.h" |
| +#include "base/json/json_string_value_serializer.h" |
| +#include "base/win/event_trace_controller.h" |
| +#include "base/win/event_trace_consumer.h" |
| +#endif |
| + |
| using base::debug::TraceLog; |
| namespace content { |
| @@ -29,6 +36,155 @@ namespace { |
| base::LazyInstance<TracingControllerImpl>::Leaky g_controller = |
| LAZY_INSTANCE_INITIALIZER; |
| +#if defined(OS_WIN) |
| + |
| +std::string GuidToString(const GUID& guid) { |
| + return base::StringPrintf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", |
| + guid.Data1, guid.Data2, guid.Data3, |
| + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], |
| + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); |
| +} |
| + |
| +class EtwSystemEventConsumer : |
| + public base::win::EtwTraceConsumerBase<EtwSystemEventConsumer> { |
| + public: |
| + typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&)> |
| + OutputCallback; |
| + |
| + EtwSystemEventConsumer() : thread_("EtwConsumerThread") { |
| + thread_.Start(); |
|
nduca
2014/02/18 22:17:13
you should probably kill the thread when things st
etienneb
2014/02/19 17:14:52
I cannot kill the thread until the events isn't fl
|
| + } |
| + |
| + void RequestStartSystemTracing() { |
| + events_.reset(new base::ListValue()); |
| + thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&EtwSystemEventConsumer::TraceAndConsumeOnThread, |
| + base::Unretained(this))); |
| + } |
| + |
| + void RequestStopSystemTracing(const OutputCallback& callback) { |
| + thread_.message_loop()->PostTask(FROM_HERE, |
| + base::Bind(&EtwSystemEventConsumer::StopSystemTracingOnThread, |
| + base::Unretained(this), callback)); |
| + } |
| + |
| + void AppendEventToBuffer(EVENT_TRACE* event) { |
| + using base::Value; |
| + using base::StringPrintf; |
| + |
| + scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); |
| + |
| + // Add header fields to the event. |
| + value->Set("ts", base::Value::CreateStringValue( |
| + StringPrintf("%08X%08X", |
| + event->Header.TimeStamp.HighPart, |
| + event->Header.TimeStamp.LowPart))); |
| + |
| + value->Set("guid", base::Value::CreateStringValue( |
| + GuidToString(event->Header.Guid))); |
| + |
| + // TODO(etienneb): CreateIntegerValue are deprecated. |
| + value->Set("op", Value::CreateIntegerValue(event->Header.Class.Type)); |
| + value->Set("ver", Value::CreateIntegerValue(event->Header.Class.Version)); |
| + value->Set("pid", Value::CreateIntegerValue(event->Header.ProcessId)); |
| + value->Set("tid", Value::CreateIntegerValue(event->Header.ProcessId)); |
| + value->Set("cpu", Value::CreateIntegerValue( |
| + event->BufferContext.ProcessorNumber)); |
| + |
| + // TODO(etienneb): fix it!!!!! |
| + value->Set("is64", Value::CreateIntegerValue(1)); |
| + |
| + // Encode the payload bytes in hexadecimal. |
| + std::string payload = |
| + StringToLowerASCII(base::HexEncode(event->MofData, event->MofLength)); |
| + value->Set("payload", base::Value::CreateStringValue(payload)); |
| + |
| + // Append it to the events buffer. |
| + events_->Append(value.release()); |
| + } |
| + |
| + static void ProcessEvent(EVENT_TRACE* event); |
| + static EtwSystemEventConsumer* Get(); |
| + |
| + bool StartNTKernelSessionTracing() { |
|
nduca
2014/02/18 22:17:13
can this be a private member and you just make the
etienneb
2014/02/19 17:14:52
I kept them separate to be able to update: is_syst
|
| + // Enabled flags (tracing facilities). |
| + uint32 enabled_flags = EVENT_TRACE_FLAG_IMAGE_LOAD | |
| + EVENT_TRACE_FLAG_PROCESS | |
| + EVENT_TRACE_FLAG_THREAD | |
| + EVENT_TRACE_FLAG_CSWITCH; |
| + |
| + EVENT_TRACE_PROPERTIES& p = *properties_.get(); |
| + p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; |
| + p.FlushTimer = 1; // flush every second. |
| + p.BufferSize = 16; // 16 K buffers. |
| + p.LogFileNameOffset = 0; |
| + p.EnableFlags = enabled_flags; |
| + |
| + HRESULT hr = base::win::EtwTraceController::Start( |
| + KERNEL_LOGGER_NAME, &properties_, &session_handle_); |
| + if (FAILED(hr)) { |
| + VLOG(1) << "StartRealtimeSession() failed with " << hr << "."; |
| + return false; |
| + } |
| + |
| + return true; |
| + } |
| + |
| + bool StopNTKernelSessionTracing() { |
| + HRESULT hr = base::win::EtwTraceController::Stop( |
| + KERNEL_LOGGER_NAME, &properties_); |
| + return SUCCEEDED(hr); |
| + } |
| + |
| + private: |
| + |
| + void TraceAndConsumeOnThread() { |
| + HRESULT hr = OpenRealtimeSession(KERNEL_LOGGER_NAME); |
| + if (FAILED(hr)) |
| + return; |
| + Consume(); |
| + Close(); |
| + } |
| + |
| + void StopSystemTracingOnThread(const OutputCallback& callback) { |
| + // Add the header information to the stream. |
| + scoped_ptr<base::DictionaryValue> header(new base::DictionaryValue()); |
| + header->Set("name", base::Value::CreateStringValue("ETW")); |
| + header->Set("content", events_.release()); |
| + |
| + // Serialize the results as a JSon string. |
| + std::string output; |
| + JSONStringValueSerializer serializer(&output); |
| + serializer.set_pretty_print(true); |
| + serializer.Serialize(*header.get()); |
| + |
| + // Pass the result to the UI Thread. |
| + scoped_refptr<base::RefCountedString> result = |
| + base::RefCountedString::TakeString(&output); |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(callback, result)); |
| + } |
| + |
| + scoped_ptr<base::ListValue> events_; |
| + base::Thread thread_; |
| + TRACEHANDLE session_handle_; |
| + base::win::EtwTraceProperties properties_; |
| +}; |
| + |
| +base::LazyInstance<EtwSystemEventConsumer>::Leaky g_etw_consumer = |
|
nduca
2014/02/18 22:17:13
how about having tracing controller own this insta
etienneb
2014/02/19 17:14:52
The ProcessEvent is called by a windows callback.
|
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +EtwSystemEventConsumer* EtwSystemEventConsumer::Get() { |
| + return g_etw_consumer.Pointer(); |
| +} |
| + |
| +void EtwSystemEventConsumer::ProcessEvent(EVENT_TRACE* event) { |
| + EtwSystemEventConsumer::Get()->AppendEventToBuffer(event); |
| +} |
| + |
| +#endif // OS_WIN |
| + |
| } // namespace |
| TracingController* TracingController::GetInstance() { |
| @@ -129,9 +285,15 @@ void TracingControllerImpl::ResultFile::CloseTask( |
| DCHECK(written == 1); |
| if (system_trace_) { |
| +#if defined(OS_WIN) |
| + // TODO(etienneb): This is ugly patch on windows. We should keep Value for |
| + // all OS instead of String to represent system traces. |
| + std::string json_string = system_trace_->data(); |
| +#else |
| std::string json_string = base::GetQuotedJSONString(system_trace_->data()); |
| +#endif |
| - const char* systemTraceHead = ", \"systemTraceEvents\": "; |
| + const char* systemTraceHead = ",\n\"systemTraceEvents\": "; |
| written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_); |
| DCHECK(written == 1); |
| @@ -236,6 +398,7 @@ bool TracingControllerImpl::EnableRecording( |
| if (options & ENABLE_SAMPLING) { |
| trace_options |= TraceLog::ENABLE_SAMPLING; |
| } |
| + |
| #if defined(OS_CHROMEOS) |
| if (options & ENABLE_SYSTRACE) { |
| DCHECK(!is_system_tracing_); |
| @@ -248,7 +411,9 @@ bool TracingControllerImpl::EnableRecording( |
| #if defined(OS_WIN) |
| if (options & ENABLE_SYSTRACE) { |
| DCHECK(!is_system_tracing_); |
| - is_system_tracing_ = true; |
| + is_system_tracing_ = |
| + EtwSystemEventConsumer::Get()->StartNTKernelSessionTracing(); |
| + g_etw_consumer.Pointer()->RequestStartSystemTracing(); |
| } |
| #endif |
| @@ -692,7 +857,15 @@ void TracingControllerImpl::OnDisableRecordingComplete() { |
| #if defined(OS_WIN) |
|
nduca
2014/02/18 22:17:13
lets pull out this and the cros one to
if (is_sys
etienneb
2014/02/19 17:14:52
Done.
|
| if (is_system_tracing_) { |
| + // Disable system tracing. |
| + EtwSystemEventConsumer::Get()->StopNTKernelSessionTracing(); |
| is_system_tracing_ = false; |
| + |
| + // Request events to be flushed. |
| + EtwSystemEventConsumer::Get()->RequestStopSystemTracing( |
| + base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, |
| + base::Unretained(this))); |
| + return; |
| } |
| #endif |
| @@ -720,7 +893,7 @@ void TracingControllerImpl::OnResultFileClosed() { |
| result_file_.reset(); |
| } |
| -#if defined(OS_CHROMEOS) |
| +#if defined(OS_CHROMEOS) || defined(OS_WIN) |
| void TracingControllerImpl::OnEndSystemTracingAcked( |
| const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |