1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/build/perfprobe.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,236 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/***************************** 1.10 + Windows implementation of probes, using xperf 1.11 + *****************************/ 1.12 +#include <windows.h> 1.13 +#include <wmistr.h> 1.14 +#include <evntrace.h> 1.15 + 1.16 +#include "perfprobe.h" 1.17 +#include "nsAutoPtr.h" 1.18 + 1.19 +namespace mozilla { 1.20 +namespace probes { 1.21 + 1.22 +#if defined(MOZ_LOGGING) 1.23 +static PRLogModuleInfo * 1.24 +GetProbeLog() 1.25 +{ 1.26 + static PRLogModuleInfo *sLog; 1.27 + if (!sLog) 1.28 + sLog = PR_NewLogModule("SysProbe"); 1.29 + return sLog; 1.30 +} 1.31 +#define LOG(x) PR_LOG(GetProbeLog(), PR_LOG_DEBUG, x) 1.32 +#else 1.33 +#define LOG(x) 1.34 +#endif 1.35 + 1.36 +//Utility function 1.37 +GUID CID_to_GUID(const nsCID &aCID) 1.38 +{ 1.39 + GUID result; 1.40 + result.Data1 = aCID.m0; 1.41 + result.Data2 = aCID.m1; 1.42 + result.Data3 = aCID.m2; 1.43 + for (int i = 0; i < 8; ++i) 1.44 + result.Data4[i] = aCID.m3[i]; 1.45 + return result; 1.46 +} 1.47 + 1.48 + 1.49 + 1.50 +// Implementation of Probe 1.51 + 1.52 +Probe::Probe(const nsCID &aGUID, 1.53 + const nsACString &aName, 1.54 + ProbeManager *aManager) 1.55 + : mGUID(CID_to_GUID(aGUID)) 1.56 + , mName(aName) 1.57 + , mManager(aManager) 1.58 +{ 1.59 +} 1.60 + 1.61 +nsresult Probe::Trigger() 1.62 +{ 1.63 + if (!(mManager->mIsActive)) { 1.64 + //Do not trigger if there is no session 1.65 + return NS_OK; 1.66 + } 1.67 + 1.68 + _EVENT_TRACE_HEADER event; 1.69 + ZeroMemory(&event, sizeof(event)); 1.70 + event.Size = sizeof(event); 1.71 + event.Flags = WNODE_FLAG_TRACED_GUID ; 1.72 + event.Guid = (const GUID)mGUID; 1.73 + event.Class.Type = 1; 1.74 + event.Class.Version = 0; 1.75 + event.Class.Level = TRACE_LEVEL_INFORMATION; 1.76 + 1.77 + ULONG result = TraceEvent(mManager->mSessionHandle, &event); 1.78 + 1.79 + LOG(("Probes: Triggered %s, %s, %ld", 1.80 + mName.Data(), 1.81 + result==ERROR_SUCCESS ? "success":"failure", 1.82 + result)); 1.83 + 1.84 + nsresult rv; 1.85 + switch(result) 1.86 + { 1.87 + case ERROR_SUCCESS: rv = NS_OK; break; 1.88 + case ERROR_INVALID_FLAG_NUMBER: 1.89 + case ERROR_MORE_DATA: 1.90 + case ERROR_INVALID_PARAMETER: rv = NS_ERROR_INVALID_ARG; break; 1.91 + case ERROR_INVALID_HANDLE: rv = NS_ERROR_FAILURE; break; 1.92 + case ERROR_NOT_ENOUGH_MEMORY: 1.93 + case ERROR_OUTOFMEMORY: rv = NS_ERROR_OUT_OF_MEMORY; break; 1.94 + default: rv = NS_ERROR_UNEXPECTED; 1.95 + } 1.96 + return rv; 1.97 +} 1.98 + 1.99 + 1.100 +// Implementation of ProbeManager 1.101 + 1.102 +ProbeManager::~ProbeManager() 1.103 +{ 1.104 + //If the manager goes out of scope, stop the session. 1.105 + if (mIsActive && mRegistrationHandle) { 1.106 + StopSession(); 1.107 + } 1.108 +} 1.109 + 1.110 +ProbeManager::ProbeManager(const nsCID &aApplicationUID, 1.111 + const nsACString &aApplicationName) 1.112 + : mApplicationUID(aApplicationUID) 1.113 + , mApplicationName(aApplicationName) 1.114 + , mSessionHandle(0) 1.115 + , mRegistrationHandle(0) 1.116 +{ 1.117 +#if defined(MOZ_LOGGING) 1.118 + char cidStr[NSID_LENGTH]; 1.119 + aApplicationUID.ToProvidedString(cidStr); 1.120 + LOG(("ProbeManager::Init for application %s, %s", 1.121 + aApplicationName.Data(), cidStr)); 1.122 +#endif 1.123 +} 1.124 + 1.125 +//Note: The Windows API is just a little bit scary there. 1.126 +//The only way to obtain the session handle is to 1.127 +//- ignore the session handle obtained from RegisterTraceGuids 1.128 +//- pass a callback 1.129 +//- in that callback, request the session handle through 1.130 +// GetTraceLoggerHandle and some opaque value received by the callback 1.131 + 1.132 +ULONG WINAPI ControlCallback( 1.133 + WMIDPREQUESTCODE RequestCode, 1.134 + PVOID Context, 1.135 + ULONG *Reserved, 1.136 + PVOID Buffer 1.137 + ) 1.138 +{ 1.139 + ProbeManager* context = (ProbeManager*)Context; 1.140 + switch(RequestCode) 1.141 + { 1.142 + case WMI_ENABLE_EVENTS: 1.143 + { 1.144 + context->mIsActive = true; 1.145 + TRACEHANDLE sessionHandle = GetTraceLoggerHandle(Buffer); 1.146 + //Note: We only accept one handle 1.147 + if ((HANDLE)sessionHandle == INVALID_HANDLE_VALUE) { 1.148 + ULONG result = GetLastError(); 1.149 + LOG(("Probes: ControlCallback failed, %ul", result)); 1.150 + return result; 1.151 + } else if (context->mIsActive && context->mSessionHandle 1.152 + && context->mSessionHandle != sessionHandle) { 1.153 + LOG(("Probes: Can only handle one context at a time, " 1.154 + "ignoring activation")); 1.155 + return ERROR_SUCCESS; 1.156 + } else { 1.157 + context->mSessionHandle = sessionHandle; 1.158 + LOG(("Probes: ControlCallback activated")); 1.159 + return ERROR_SUCCESS; 1.160 + } 1.161 + } 1.162 + 1.163 + case WMI_DISABLE_EVENTS: 1.164 + context->mIsActive = false; 1.165 + context->mSessionHandle = 0; 1.166 + LOG(("Probes: ControlCallback deactivated")); 1.167 + return ERROR_SUCCESS; 1.168 + 1.169 + default: 1.170 + LOG(("Probes: ControlCallback does not know what to do with %d", 1.171 + RequestCode)); 1.172 + return ERROR_INVALID_PARAMETER; 1.173 + } 1.174 +} 1.175 + 1.176 +already_AddRefed<Probe> ProbeManager::GetProbe(const nsCID &eventUID, 1.177 + const nsACString &eventName) 1.178 +{ 1.179 + nsRefPtr<Probe> result(new Probe(eventUID, eventName, this)); 1.180 + mAllProbes.AppendElement(result); 1.181 + return result.forget(); 1.182 +} 1.183 + 1.184 +nsresult ProbeManager::StartSession() 1.185 +{ 1.186 + return StartSession(mAllProbes); 1.187 +} 1.188 + 1.189 +nsresult ProbeManager::StartSession(nsTArray<nsRefPtr<Probe>> &aProbes) 1.190 +{ 1.191 + const size_t probesCount = aProbes.Length(); 1.192 + _TRACE_GUID_REGISTRATION* probes = new _TRACE_GUID_REGISTRATION[probesCount]; 1.193 + for (unsigned int i = 0; i < probesCount; ++i) { 1.194 + const Probe *probe = aProbes[i]; 1.195 + const Probe *probeX = static_cast<const Probe*>(probe); 1.196 + probes[i].Guid = (LPCGUID)&(probeX->mGUID); 1.197 + } 1.198 + ULONG result = 1.199 + RegisterTraceGuids(&ControlCallback 1.200 + /*RequestAddress: Sets mSessions appropriately.*/, 1.201 + this 1.202 + /*RequestContext: Passed to ControlCallback*/, 1.203 + (LPGUID)&mApplicationUID 1.204 + /*ControlGuid: Tracing GUID 1.205 + the cast comes from MSDN examples*/, 1.206 + probesCount 1.207 + /*GuidCount: Number of probes*/, 1.208 + probes 1.209 + /*TraceGuidReg: Probes registration*/, 1.210 + nullptr 1.211 + /*MofImagePath: Must be nullptr, says MSDN*/, 1.212 + nullptr 1.213 + /*MofResourceName:Must be nullptr, says MSDN*/, 1.214 + &mRegistrationHandle 1.215 + /*RegistrationHandle: Handler. 1.216 + used only for unregistration*/ 1.217 + ); 1.218 + delete[] probes; 1.219 + if (NS_WARN_IF(result != ERROR_SUCCESS)) 1.220 + return NS_ERROR_UNEXPECTED; 1.221 + return NS_OK; 1.222 +} 1.223 + 1.224 +nsresult ProbeManager::StopSession() 1.225 +{ 1.226 + LOG(("Probes: Stopping measures")); 1.227 + if (mSessionHandle != 0) { 1.228 + ULONG result = UnregisterTraceGuids(mSessionHandle); 1.229 + mSessionHandle = 0; 1.230 + if (result != ERROR_SUCCESS) { 1.231 + return NS_ERROR_INVALID_ARG; 1.232 + } 1.233 + } 1.234 + return NS_OK; 1.235 +} 1.236 + 1.237 + 1.238 +} 1.239 +}