| // Copyright 2009 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // Implementation of a Windows event trace controller class. |
| |
| #include "base/win/event_trace_controller.h" |
| |
| #include "base/check.h" |
| #include "base/numerics/checked_math.h" |
| |
| constexpr size_t kDefaultRealtimeBufferSizeKb = 16; |
| |
| namespace base { |
| namespace win { |
| |
| EtwTraceProperties::EtwTraceProperties() { |
| memset(buffer_, 0, sizeof(buffer_)); |
| EVENT_TRACE_PROPERTIES* prop = get(); |
| |
| prop->Wnode.BufferSize = sizeof(buffer_); |
| prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID; |
| prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); |
| prop->LogFileNameOffset = |
| sizeof(EVENT_TRACE_PROPERTIES) + sizeof(wchar_t) * kMaxStringLen; |
| } |
| |
| HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) { |
| size_t len = wcslen(logger_name) + 1; |
| if (kMaxStringLen < len) |
| return E_INVALIDARG; |
| |
| memcpy(buffer_ + get()->LoggerNameOffset, logger_name, sizeof(wchar_t) * len); |
| return S_OK; |
| } |
| |
| HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) { |
| size_t len = wcslen(logger_file_name) + 1; |
| if (kMaxStringLen < len) |
| return E_INVALIDARG; |
| |
| memcpy(buffer_ + get()->LogFileNameOffset, logger_file_name, |
| sizeof(wchar_t) * len); |
| return S_OK; |
| } |
| |
| EtwTraceController::EtwTraceController() = default; |
| |
| EtwTraceController::~EtwTraceController() { |
| if (session_) |
| Stop(nullptr); |
| } |
| |
| HRESULT EtwTraceController::Start(const wchar_t* session_name, |
| EtwTraceProperties* prop) { |
| DCHECK(NULL == session_ && session_name_.empty()); |
| EtwTraceProperties ignore; |
| if (prop == nullptr) |
| prop = &ignore; |
| |
| HRESULT hr = Start(session_name, prop, &session_); |
| if (SUCCEEDED(hr)) |
| session_name_ = session_name; |
| |
| return hr; |
| } |
| |
| HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name, |
| const wchar_t* logfile_path, |
| bool realtime) { |
| DCHECK(NULL == session_ && session_name_.empty()); |
| |
| EtwTraceProperties prop; |
| prop.SetLoggerFileName(logfile_path); |
| EVENT_TRACE_PROPERTIES& p = *prop.get(); |
| p.Wnode.ClientContext = 1; // QPC timer accuracy. |
| p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL; // Sequential log. |
| if (realtime) |
| p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE; |
| |
| p.MaximumFileSize = 100; // 100M file size. |
| p.FlushTimer = 30; // 30 seconds flush lag. |
| return Start(session_name, &prop); |
| } |
| |
| HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name, |
| size_t buffer_size) { |
| DCHECK(NULL == session_ && session_name_.empty()); |
| |
| EtwTraceProperties prop; |
| EVENT_TRACE_PROPERTIES& p = *prop.get(); |
| p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY; |
| p.FlushTimer = 1; // flush every second. |
| p.BufferSize = checked_cast<ULONG>( |
| buffer_size ? buffer_size : kDefaultRealtimeBufferSizeKb); |
| p.LogFileNameOffset = 0; |
| return Start(session_name, &prop); |
| } |
| |
| HRESULT EtwTraceController::EnableProvider(REFGUID provider, |
| UCHAR level, |
| ULONG flags) { |
| ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_); |
| return HRESULT_FROM_WIN32(error); |
| } |
| |
| HRESULT EtwTraceController::DisableProvider(REFGUID provider) { |
| ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_); |
| return HRESULT_FROM_WIN32(error); |
| } |
| |
| HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) { |
| EtwTraceProperties ignore; |
| if (properties == nullptr) |
| properties = &ignore; |
| |
| ULONG error = ::ControlTrace(session_, nullptr, properties->get(), |
| EVENT_TRACE_CONTROL_STOP); |
| if (ERROR_SUCCESS != error) |
| return HRESULT_FROM_WIN32(error); |
| |
| session_ = NULL; |
| session_name_.clear(); |
| return S_OK; |
| } |
| |
| HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) { |
| EtwTraceProperties ignore; |
| if (properties == nullptr) |
| properties = &ignore; |
| |
| ULONG error = ::ControlTrace(session_, nullptr, properties->get(), |
| EVENT_TRACE_CONTROL_FLUSH); |
| if (ERROR_SUCCESS != error) |
| return HRESULT_FROM_WIN32(error); |
| |
| return S_OK; |
| } |
| |
| HRESULT EtwTraceController::Start(const wchar_t* session_name, |
| EtwTraceProperties* properties, |
| TRACEHANDLE* session_handle) { |
| DCHECK(properties != nullptr); |
| ULONG err = ::StartTrace(session_handle, session_name, properties->get()); |
| return HRESULT_FROM_WIN32(err); |
| } |
| |
| HRESULT EtwTraceController::Query(const wchar_t* session_name, |
| EtwTraceProperties* properties) { |
| ULONG err = ::ControlTrace(NULL, session_name, properties->get(), |
| EVENT_TRACE_CONTROL_QUERY); |
| return HRESULT_FROM_WIN32(err); |
| } |
| |
| HRESULT EtwTraceController::Update(const wchar_t* session_name, |
| EtwTraceProperties* properties) { |
| DCHECK(properties != nullptr); |
| ULONG err = ::ControlTrace(NULL, session_name, properties->get(), |
| EVENT_TRACE_CONTROL_UPDATE); |
| return HRESULT_FROM_WIN32(err); |
| } |
| |
| HRESULT EtwTraceController::Stop(const wchar_t* session_name, |
| EtwTraceProperties* properties) { |
| DCHECK(properties != nullptr); |
| ULONG err = ::ControlTrace(NULL, session_name, properties->get(), |
| EVENT_TRACE_CONTROL_STOP); |
| return HRESULT_FROM_WIN32(err); |
| } |
| |
| HRESULT EtwTraceController::Flush(const wchar_t* session_name, |
| EtwTraceProperties* properties) { |
| DCHECK(properties != nullptr); |
| ULONG err = ::ControlTrace(NULL, session_name, properties->get(), |
| EVENT_TRACE_CONTROL_FLUSH); |
| return HRESULT_FROM_WIN32(err); |
| } |
| |
| } // namespace win |
| } // namespace base |