1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// Implementation of a Windows event trace controller class.
6#include "base/win/event_trace_controller.h"
7#include "base/logging.h"
8
9namespace base {
10namespace win {
11
12EtwTraceProperties::EtwTraceProperties() {
13  memset(buffer_, 0, sizeof(buffer_));
14  EVENT_TRACE_PROPERTIES* prop = get();
15
16  prop->Wnode.BufferSize = sizeof(buffer_);
17  prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
18  prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
19  prop->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) +
20                            sizeof(wchar_t) * kMaxStringLen;
21}
22
23HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) {
24  size_t len = wcslen(logger_name) + 1;
25  if (kMaxStringLen < len)
26    return E_INVALIDARG;
27
28  memcpy(buffer_ + get()->LoggerNameOffset,
29         logger_name,
30         sizeof(wchar_t) * len);
31  return S_OK;
32}
33
34HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) {
35  size_t len = wcslen(logger_file_name) + 1;
36  if (kMaxStringLen < len)
37    return E_INVALIDARG;
38
39  memcpy(buffer_ + get()->LogFileNameOffset,
40         logger_file_name,
41         sizeof(wchar_t) * len);
42  return S_OK;
43}
44
45EtwTraceController::EtwTraceController() : session_(NULL) {
46}
47
48EtwTraceController::~EtwTraceController() {
49  Stop(NULL);
50}
51
52HRESULT EtwTraceController::Start(const wchar_t* session_name,
53    EtwTraceProperties* prop) {
54  DCHECK(NULL == session_ && session_name_.empty());
55  EtwTraceProperties ignore;
56  if (prop == NULL)
57    prop = &ignore;
58
59  HRESULT hr = Start(session_name, prop, &session_);
60  if (SUCCEEDED(hr))
61    session_name_ = session_name;
62
63  return hr;
64}
65
66HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name,
67    const wchar_t* logfile_path, bool realtime) {
68  DCHECK(NULL == session_ && session_name_.empty());
69
70  EtwTraceProperties prop;
71  prop.SetLoggerFileName(logfile_path);
72  EVENT_TRACE_PROPERTIES& p = *prop.get();
73  p.Wnode.ClientContext = 1;  // QPC timer accuracy.
74  p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;  // Sequential log.
75  if (realtime)
76    p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
77
78  p.MaximumFileSize = 100;  // 100M file size.
79  p.FlushTimer = 30;  // 30 seconds flush lag.
80  return Start(session_name, &prop);
81}
82
83HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name,
84    size_t buffer_size) {
85  DCHECK(NULL == session_ && session_name_.empty());
86  EtwTraceProperties prop;
87  EVENT_TRACE_PROPERTIES& p = *prop.get();
88  p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY;
89  p.FlushTimer = 1;  // flush every second.
90  p.BufferSize = 16;  // 16 K buffers.
91  p.LogFileNameOffset = 0;
92  return Start(session_name, &prop);
93}
94
95HRESULT EtwTraceController::EnableProvider(REFGUID provider, UCHAR level,
96    ULONG flags) {
97  ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_);
98  return HRESULT_FROM_WIN32(error);
99}
100
101HRESULT EtwTraceController::DisableProvider(REFGUID provider) {
102  ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_);
103  return HRESULT_FROM_WIN32(error);
104}
105
106HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) {
107  EtwTraceProperties ignore;
108  if (properties == NULL)
109    properties = &ignore;
110
111  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
112    EVENT_TRACE_CONTROL_STOP);
113  if (ERROR_SUCCESS != error)
114    return HRESULT_FROM_WIN32(error);
115
116  session_ = NULL;
117  session_name_.clear();
118  return S_OK;
119}
120
121HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) {
122  EtwTraceProperties ignore;
123  if (properties == NULL)
124    properties = &ignore;
125
126  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
127                               EVENT_TRACE_CONTROL_FLUSH);
128  if (ERROR_SUCCESS != error)
129    return HRESULT_FROM_WIN32(error);
130
131  return S_OK;
132}
133
134HRESULT EtwTraceController::Start(const wchar_t* session_name,
135    EtwTraceProperties* properties, TRACEHANDLE* session_handle) {
136  DCHECK(properties != NULL);
137  ULONG err = ::StartTrace(session_handle, session_name, properties->get());
138  return HRESULT_FROM_WIN32(err);
139}
140
141HRESULT EtwTraceController::Query(const wchar_t* session_name,
142    EtwTraceProperties* properties) {
143  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
144                             EVENT_TRACE_CONTROL_QUERY);
145  return HRESULT_FROM_WIN32(err);
146};
147
148HRESULT EtwTraceController::Update(const wchar_t* session_name,
149    EtwTraceProperties* properties) {
150  DCHECK(properties != NULL);
151  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
152                             EVENT_TRACE_CONTROL_UPDATE);
153  return HRESULT_FROM_WIN32(err);
154}
155
156HRESULT EtwTraceController::Stop(const wchar_t* session_name,
157    EtwTraceProperties* properties) {
158  DCHECK(properties != NULL);
159  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
160                             EVENT_TRACE_CONTROL_STOP);
161  return HRESULT_FROM_WIN32(err);
162}
163
164HRESULT EtwTraceController::Flush(const wchar_t* session_name,
165    EtwTraceProperties* properties) {
166  DCHECK(properties != NULL);
167  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
168                             EVENT_TRACE_CONTROL_FLUSH);
169  return HRESULT_FROM_WIN32(err);
170}
171
172}  // namespace win
173}  // namespace base
174