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