15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Declaration of a Windows event trace consumer base class.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_WIN_EVENT_TRACE_CONSUMER_H_
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wmistr.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <evntrace.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace win {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is a base class that makes it easier to consume events
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// from realtime or file sessions. Concrete consumers need to subclass
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a specialization of this class and override the ProcessEvent and/or
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the ProcessBuffer methods to implement the event consumption logic.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Usage might look like:
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// class MyConsumer: public EtwTraceConsumerBase<MyConsumer, 1> {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  protected:
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    static VOID WINAPI ProcessEvent(PEVENT_TRACE event);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// };
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MyConsumer consumer;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// consumer.OpenFileSession(file_path);
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// consumer.Consume();
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ImplClass>
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EtwTraceConsumerBase {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Constructs a closed consumer.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwTraceConsumerBase() {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~EtwTraceConsumerBase() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Close();
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Opens the named realtime session, which must be existent.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: You can use OpenRealtimeSession or OpenFileSession
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    any one time, though only one of them may be a realtime
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    session.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT OpenRealtimeSession(const wchar_t* session_name);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Opens the event trace log in "file_name", which must be a full or
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // relative path to an existing event trace log file.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: You can use OpenRealtimeSession or OpenFileSession
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    to open as many as kNumSessions at any one time.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT OpenFileSession(const wchar_t* file_name);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Consume all open sessions from beginning to end.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT Consume();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close all open sessions.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT Close();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Override in subclasses to handle events.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void ProcessEvent(EVENT_TRACE* event) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Override in subclasses to handle buffers.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // keep going
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Currently open sessions.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<TRACEHANDLE> trace_handles_;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These delegate to ImplClass callbacks with saner signatures.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ImplClass::ProcessEvent(event);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ImplClass::ProcessBuffer(buffer);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ImplClass> inline
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* session_name) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVENT_TRACE_LOGFILE logfile = {};
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.LoggerName = const_cast<wchar_t*>(session_name);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.BufferCallback = &ProcessBufferCallback;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.EventCallback = &ProcessEventCallback;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.Context = this;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return HRESULT_FROM_WIN32(::GetLastError());
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  trace_handles_.push_back(trace_handle);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ImplClass> inline
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* file_name) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVENT_TRACE_LOGFILE logfile = {};
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.LogFileName = const_cast<wchar_t*>(file_name);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.BufferCallback = &ProcessBufferCallback;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.EventCallback = &ProcessEventCallback;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logfile.Context = this;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return HRESULT_FROM_WIN32(::GetLastError());
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  trace_handles_.push_back(trace_handle);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ImplClass> inline
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG err = ::ProcessTrace(&trace_handles_[0],
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             trace_handles_.size(),
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NULL,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NULL);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HRESULT_FROM_WIN32(err);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ImplClass> inline
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = S_OK;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < trace_handles_.size(); ++i) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NULL != trace_handles_[i]) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ULONG ret = ::CloseTrace(trace_handles_[i]);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      trace_handles_[i] = NULL;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(HRESULT_FROM_WIN32(ret)))
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = HRESULT_FROM_WIN32(ret);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  trace_handles_.clear();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace win
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_WIN_EVENT_TRACE_CONSUMER_H_
149