michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /***************************** michael@0: Windows implementation of probes, using xperf michael@0: *****************************/ michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "perfprobe.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: namespace mozilla { michael@0: namespace probes { michael@0: michael@0: #if defined(MOZ_LOGGING) michael@0: static PRLogModuleInfo * michael@0: GetProbeLog() michael@0: { michael@0: static PRLogModuleInfo *sLog; michael@0: if (!sLog) michael@0: sLog = PR_NewLogModule("SysProbe"); michael@0: return sLog; michael@0: } michael@0: #define LOG(x) PR_LOG(GetProbeLog(), PR_LOG_DEBUG, x) michael@0: #else michael@0: #define LOG(x) michael@0: #endif michael@0: michael@0: //Utility function michael@0: GUID CID_to_GUID(const nsCID &aCID) michael@0: { michael@0: GUID result; michael@0: result.Data1 = aCID.m0; michael@0: result.Data2 = aCID.m1; michael@0: result.Data3 = aCID.m2; michael@0: for (int i = 0; i < 8; ++i) michael@0: result.Data4[i] = aCID.m3[i]; michael@0: return result; michael@0: } michael@0: michael@0: michael@0: michael@0: // Implementation of Probe michael@0: michael@0: Probe::Probe(const nsCID &aGUID, michael@0: const nsACString &aName, michael@0: ProbeManager *aManager) michael@0: : mGUID(CID_to_GUID(aGUID)) michael@0: , mName(aName) michael@0: , mManager(aManager) michael@0: { michael@0: } michael@0: michael@0: nsresult Probe::Trigger() michael@0: { michael@0: if (!(mManager->mIsActive)) { michael@0: //Do not trigger if there is no session michael@0: return NS_OK; michael@0: } michael@0: michael@0: _EVENT_TRACE_HEADER event; michael@0: ZeroMemory(&event, sizeof(event)); michael@0: event.Size = sizeof(event); michael@0: event.Flags = WNODE_FLAG_TRACED_GUID ; michael@0: event.Guid = (const GUID)mGUID; michael@0: event.Class.Type = 1; michael@0: event.Class.Version = 0; michael@0: event.Class.Level = TRACE_LEVEL_INFORMATION; michael@0: michael@0: ULONG result = TraceEvent(mManager->mSessionHandle, &event); michael@0: michael@0: LOG(("Probes: Triggered %s, %s, %ld", michael@0: mName.Data(), michael@0: result==ERROR_SUCCESS ? "success":"failure", michael@0: result)); michael@0: michael@0: nsresult rv; michael@0: switch(result) michael@0: { michael@0: case ERROR_SUCCESS: rv = NS_OK; break; michael@0: case ERROR_INVALID_FLAG_NUMBER: michael@0: case ERROR_MORE_DATA: michael@0: case ERROR_INVALID_PARAMETER: rv = NS_ERROR_INVALID_ARG; break; michael@0: case ERROR_INVALID_HANDLE: rv = NS_ERROR_FAILURE; break; michael@0: case ERROR_NOT_ENOUGH_MEMORY: michael@0: case ERROR_OUTOFMEMORY: rv = NS_ERROR_OUT_OF_MEMORY; break; michael@0: default: rv = NS_ERROR_UNEXPECTED; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: // Implementation of ProbeManager michael@0: michael@0: ProbeManager::~ProbeManager() michael@0: { michael@0: //If the manager goes out of scope, stop the session. michael@0: if (mIsActive && mRegistrationHandle) { michael@0: StopSession(); michael@0: } michael@0: } michael@0: michael@0: ProbeManager::ProbeManager(const nsCID &aApplicationUID, michael@0: const nsACString &aApplicationName) michael@0: : mApplicationUID(aApplicationUID) michael@0: , mApplicationName(aApplicationName) michael@0: , mSessionHandle(0) michael@0: , mRegistrationHandle(0) michael@0: { michael@0: #if defined(MOZ_LOGGING) michael@0: char cidStr[NSID_LENGTH]; michael@0: aApplicationUID.ToProvidedString(cidStr); michael@0: LOG(("ProbeManager::Init for application %s, %s", michael@0: aApplicationName.Data(), cidStr)); michael@0: #endif michael@0: } michael@0: michael@0: //Note: The Windows API is just a little bit scary there. michael@0: //The only way to obtain the session handle is to michael@0: //- ignore the session handle obtained from RegisterTraceGuids michael@0: //- pass a callback michael@0: //- in that callback, request the session handle through michael@0: // GetTraceLoggerHandle and some opaque value received by the callback michael@0: michael@0: ULONG WINAPI ControlCallback( michael@0: WMIDPREQUESTCODE RequestCode, michael@0: PVOID Context, michael@0: ULONG *Reserved, michael@0: PVOID Buffer michael@0: ) michael@0: { michael@0: ProbeManager* context = (ProbeManager*)Context; michael@0: switch(RequestCode) michael@0: { michael@0: case WMI_ENABLE_EVENTS: michael@0: { michael@0: context->mIsActive = true; michael@0: TRACEHANDLE sessionHandle = GetTraceLoggerHandle(Buffer); michael@0: //Note: We only accept one handle michael@0: if ((HANDLE)sessionHandle == INVALID_HANDLE_VALUE) { michael@0: ULONG result = GetLastError(); michael@0: LOG(("Probes: ControlCallback failed, %ul", result)); michael@0: return result; michael@0: } else if (context->mIsActive && context->mSessionHandle michael@0: && context->mSessionHandle != sessionHandle) { michael@0: LOG(("Probes: Can only handle one context at a time, " michael@0: "ignoring activation")); michael@0: return ERROR_SUCCESS; michael@0: } else { michael@0: context->mSessionHandle = sessionHandle; michael@0: LOG(("Probes: ControlCallback activated")); michael@0: return ERROR_SUCCESS; michael@0: } michael@0: } michael@0: michael@0: case WMI_DISABLE_EVENTS: michael@0: context->mIsActive = false; michael@0: context->mSessionHandle = 0; michael@0: LOG(("Probes: ControlCallback deactivated")); michael@0: return ERROR_SUCCESS; michael@0: michael@0: default: michael@0: LOG(("Probes: ControlCallback does not know what to do with %d", michael@0: RequestCode)); michael@0: return ERROR_INVALID_PARAMETER; michael@0: } michael@0: } michael@0: michael@0: already_AddRefed ProbeManager::GetProbe(const nsCID &eventUID, michael@0: const nsACString &eventName) michael@0: { michael@0: nsRefPtr result(new Probe(eventUID, eventName, this)); michael@0: mAllProbes.AppendElement(result); michael@0: return result.forget(); michael@0: } michael@0: michael@0: nsresult ProbeManager::StartSession() michael@0: { michael@0: return StartSession(mAllProbes); michael@0: } michael@0: michael@0: nsresult ProbeManager::StartSession(nsTArray> &aProbes) michael@0: { michael@0: const size_t probesCount = aProbes.Length(); michael@0: _TRACE_GUID_REGISTRATION* probes = new _TRACE_GUID_REGISTRATION[probesCount]; michael@0: for (unsigned int i = 0; i < probesCount; ++i) { michael@0: const Probe *probe = aProbes[i]; michael@0: const Probe *probeX = static_cast(probe); michael@0: probes[i].Guid = (LPCGUID)&(probeX->mGUID); michael@0: } michael@0: ULONG result = michael@0: RegisterTraceGuids(&ControlCallback michael@0: /*RequestAddress: Sets mSessions appropriately.*/, michael@0: this michael@0: /*RequestContext: Passed to ControlCallback*/, michael@0: (LPGUID)&mApplicationUID michael@0: /*ControlGuid: Tracing GUID michael@0: the cast comes from MSDN examples*/, michael@0: probesCount michael@0: /*GuidCount: Number of probes*/, michael@0: probes michael@0: /*TraceGuidReg: Probes registration*/, michael@0: nullptr michael@0: /*MofImagePath: Must be nullptr, says MSDN*/, michael@0: nullptr michael@0: /*MofResourceName:Must be nullptr, says MSDN*/, michael@0: &mRegistrationHandle michael@0: /*RegistrationHandle: Handler. michael@0: used only for unregistration*/ michael@0: ); michael@0: delete[] probes; michael@0: if (NS_WARN_IF(result != ERROR_SUCCESS)) michael@0: return NS_ERROR_UNEXPECTED; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult ProbeManager::StopSession() michael@0: { michael@0: LOG(("Probes: Stopping measures")); michael@0: if (mSessionHandle != 0) { michael@0: ULONG result = UnregisterTraceGuids(mSessionHandle); michael@0: mSessionHandle = 0; michael@0: if (result != ERROR_SUCCESS) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: } michael@0: }