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 *****************************/
14 #include "perfprobe.h"
19 #if defined(MOZ_LOGGING)
20 static LazyLogModule
sProbeLog("SysProbe");
21 # define LOG(x) MOZ_LOG(sProbeLog, mozilla::LogLevel::Debug, x)
27 GUID
CID_to_GUID(const nsCID
& aCID
) {
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
];
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
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
;
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
));
69 case ERROR_INVALID_FLAG_NUMBER
:
71 case ERROR_INVALID_PARAMETER
:
72 rv
= NS_ERROR_INVALID_ARG
;
74 case ERROR_INVALID_HANDLE
:
75 rv
= NS_ERROR_FAILURE
;
77 case ERROR_NOT_ENOUGH_MEMORY
:
78 case ERROR_OUTOFMEMORY
:
79 rv
= NS_ERROR_OUT_OF_MEMORY
;
82 rv
= NS_ERROR_UNEXPECTED
;
87 // Implementation of ProbeManager
89 ProbeManager::~ProbeManager() {
90 // If the manager goes out of scope, stop the session.
91 if (mIsActive
&& mRegistrationHandle
) {
96 ProbeManager::ProbeManager(const nsCID
& aApplicationUID
,
97 const nsACString
& aApplicationName
)
99 mApplicationUID(aApplicationUID
),
100 mApplicationName(aApplicationName
),
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(),
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
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
));
131 } else if (context
->mIsActive
&& context
->mSessionHandle
&&
132 context
->mSessionHandle
!= sessionHandle
) {
134 ("Probes: Can only handle one context at a time, "
135 "ignoring activation"));
136 return ERROR_SUCCESS
;
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
;
151 LOG(("Probes: ControlCallback does not know what to do with %d",
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
;
175 RegisterTraceGuids(&ControlCallback
176 /*RequestAddress: Sets mSessions appropriately.*/,
178 /*RequestContext: Passed to ControlCallback*/,
179 (LPGUID
)&mApplicationUID
180 /*ControlGuid: Tracing GUID
181 the cast comes from MSDN examples*/
184 /*GuidCount: Number of probes*/,
186 /*TraceGuidReg: Probes registration*/,
188 /*MofImagePath: Must be nullptr, says MSDN*/,
190 /*MofResourceName:Must be nullptr, says MSDN*/,
192 /*RegistrationHandle: Handler.
193 used only for unregistration*/
196 if (NS_WARN_IF(result
!= ERROR_SUCCESS
)) {
197 return NS_ERROR_UNEXPECTED
;
202 nsresult
ProbeManager::StopSession() {
203 LOG(("Probes: Stopping measures"));
204 if (mSessionHandle
!= 0) {
205 ULONG result
= UnregisterTraceGuids(mSessionHandle
);
207 if (result
!= ERROR_SUCCESS
) {
208 return NS_ERROR_INVALID_ARG
;
214 } // namespace probes
215 } // namespace mozilla