Bug 1839316: part 5) Guard the "fetchpriority" attribute behind a pref. r=kershaw...
[gecko.git] / xpcom / build / perfprobe.cpp
blobd5a82be59d4fe8e0f506aff0269a5a3f48b0ee04
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*****************************
8 Windows implementation of probes, using xperf
9 *****************************/
10 #include <windows.h>
11 #include <wmistr.h>
12 #include <evntrace.h>
14 #include "perfprobe.h"
16 namespace mozilla {
17 namespace probes {
19 #if defined(MOZ_LOGGING)
20 static LazyLogModule sProbeLog("SysProbe");
21 # define LOG(x) MOZ_LOG(sProbeLog, mozilla::LogLevel::Debug, x)
22 #else
23 # define LOG(x)
24 #endif
26 // Utility function
27 GUID CID_to_GUID(const nsCID& aCID) {
28 GUID result;
29 result.Data1 = aCID.m0;
30 result.Data2 = aCID.m1;
31 result.Data3 = aCID.m2;
32 for (int i = 0; i < 8; ++i) {
33 result.Data4[i] = aCID.m3[i];
35 return result;
38 // Implementation of Probe
40 Probe::Probe(const nsCID& aGUID, const nsACString& aName,
41 ProbeManager* aManager)
42 : mGUID(CID_to_GUID(aGUID)), mName(aName), mManager(aManager) {}
44 nsresult Probe::Trigger() {
45 if (!(mManager->mIsActive)) {
46 // Do not trigger if there is no session
47 return NS_OK;
50 _EVENT_TRACE_HEADER event;
51 ZeroMemory(&event, sizeof(event));
52 event.Size = sizeof(event);
53 event.Flags = WNODE_FLAG_TRACED_GUID;
54 event.Guid = (const GUID)mGUID;
55 event.Class.Type = 1;
56 event.Class.Version = 0;
57 event.Class.Level = TRACE_LEVEL_INFORMATION;
59 ULONG result = TraceEvent(mManager->mSessionHandle, &event);
61 LOG(("Probes: Triggered %s, %s, %ld", mName.Data(),
62 result == ERROR_SUCCESS ? "success" : "failure", result));
64 nsresult rv;
65 switch (result) {
66 case ERROR_SUCCESS:
67 rv = NS_OK;
68 break;
69 case ERROR_INVALID_FLAG_NUMBER:
70 case ERROR_MORE_DATA:
71 case ERROR_INVALID_PARAMETER:
72 rv = NS_ERROR_INVALID_ARG;
73 break;
74 case ERROR_INVALID_HANDLE:
75 rv = NS_ERROR_FAILURE;
76 break;
77 case ERROR_NOT_ENOUGH_MEMORY:
78 case ERROR_OUTOFMEMORY:
79 rv = NS_ERROR_OUT_OF_MEMORY;
80 break;
81 default:
82 rv = NS_ERROR_UNEXPECTED;
84 return rv;
87 // Implementation of ProbeManager
89 ProbeManager::~ProbeManager() {
90 // If the manager goes out of scope, stop the session.
91 if (mIsActive && mRegistrationHandle) {
92 StopSession();
96 ProbeManager::ProbeManager(const nsCID& aApplicationUID,
97 const nsACString& aApplicationName)
98 : mIsActive(false),
99 mApplicationUID(aApplicationUID),
100 mApplicationName(aApplicationName),
101 mSessionHandle(0),
102 mRegistrationHandle(0),
103 mInitialized(false) {
104 #if defined(MOZ_LOGGING)
105 char cidStr[NSID_LENGTH];
106 aApplicationUID.ToProvidedString(cidStr);
107 LOG(("ProbeManager::Init for application %s, %s", aApplicationName.Data(),
108 cidStr));
109 #endif
112 // Note: The Windows API is just a little bit scary there.
113 // The only way to obtain the session handle is to
114 //- ignore the session handle obtained from RegisterTraceGuids
115 //- pass a callback
116 //- in that callback, request the session handle through
117 // GetTraceLoggerHandle and some opaque value received by the callback
119 ULONG WINAPI ControlCallback(WMIDPREQUESTCODE aRequestCode, PVOID aContext,
120 ULONG* aReserved, PVOID aBuffer) {
121 ProbeManager* context = (ProbeManager*)aContext;
122 switch (aRequestCode) {
123 case WMI_ENABLE_EVENTS: {
124 context->mIsActive = true;
125 TRACEHANDLE sessionHandle = GetTraceLoggerHandle(aBuffer);
126 // Note: We only accept one handle
127 if ((HANDLE)sessionHandle == INVALID_HANDLE_VALUE) {
128 ULONG result = GetLastError();
129 LOG(("Probes: ControlCallback failed, %lu", result));
130 return result;
131 } else if (context->mIsActive && context->mSessionHandle &&
132 context->mSessionHandle != sessionHandle) {
133 LOG(
134 ("Probes: Can only handle one context at a time, "
135 "ignoring activation"));
136 return ERROR_SUCCESS;
137 } else {
138 context->mSessionHandle = sessionHandle;
139 LOG(("Probes: ControlCallback activated"));
140 return ERROR_SUCCESS;
144 case WMI_DISABLE_EVENTS:
145 context->mIsActive = false;
146 context->mSessionHandle = 0;
147 LOG(("Probes: ControlCallback deactivated"));
148 return ERROR_SUCCESS;
150 default:
151 LOG(("Probes: ControlCallback does not know what to do with %d",
152 aRequestCode));
153 return ERROR_INVALID_PARAMETER;
157 already_AddRefed<Probe> ProbeManager::GetProbe(const nsCID& aEventUID,
158 const nsACString& aEventName) {
159 RefPtr<Probe> result(new Probe(aEventUID, aEventName, this));
160 mAllProbes.AppendElement(result);
161 return result.forget();
164 nsresult ProbeManager::StartSession() { return StartSession(mAllProbes); }
166 nsresult ProbeManager::StartSession(nsTArray<RefPtr<Probe>>& aProbes) {
167 const size_t probesCount = aProbes.Length();
168 _TRACE_GUID_REGISTRATION* probes = new _TRACE_GUID_REGISTRATION[probesCount];
169 for (unsigned int i = 0; i < probesCount; ++i) {
170 const Probe* probe = aProbes[i];
171 const Probe* probeX = static_cast<const Probe*>(probe);
172 probes[i].Guid = (LPCGUID)&probeX->mGUID;
174 ULONG result =
175 RegisterTraceGuids(&ControlCallback
176 /*RequestAddress: Sets mSessions appropriately.*/,
177 this
178 /*RequestContext: Passed to ControlCallback*/,
179 (LPGUID)&mApplicationUID
180 /*ControlGuid: Tracing GUID
181 the cast comes from MSDN examples*/
183 probesCount
184 /*GuidCount: Number of probes*/,
185 probes
186 /*TraceGuidReg: Probes registration*/,
187 nullptr
188 /*MofImagePath: Must be nullptr, says MSDN*/,
189 nullptr
190 /*MofResourceName:Must be nullptr, says MSDN*/,
191 &mRegistrationHandle
192 /*RegistrationHandle: Handler.
193 used only for unregistration*/
195 delete[] probes;
196 if (NS_WARN_IF(result != ERROR_SUCCESS)) {
197 return NS_ERROR_UNEXPECTED;
199 return NS_OK;
202 nsresult ProbeManager::StopSession() {
203 LOG(("Probes: Stopping measures"));
204 if (mSessionHandle != 0) {
205 ULONG result = UnregisterTraceGuids(mSessionHandle);
206 mSessionHandle = 0;
207 if (result != ERROR_SUCCESS) {
208 return NS_ERROR_INVALID_ARG;
211 return NS_OK;
214 } // namespace probes
215 } // namespace mozilla