1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "ProfilerCPUFreq.h"
7 #include "nsThreadUtils.h"
9 # include "nsPrintfCString.h"
16 #pragma comment(lib, "advapi32.lib")
18 using namespace mozilla
;
20 ProfilerCPUFreq::ProfilerCPUFreq() {
21 // Query the size of the text data so you can allocate the buffer.
22 DWORD dwBufferSize
= 0;
23 LONG status
= RegQueryValueEx(HKEY_PERFORMANCE_DATA
, L
"Counter 9", NULL
, NULL
,
25 if (ERROR_SUCCESS
!= status
) {
26 NS_WARNING(nsPrintfCString("RegQueryValueEx failed getting required buffer "
27 "size. Error is 0x%lx.\n",
33 // Allocate the text buffer and query the text.
34 LPWSTR pBuffer
= (LPWSTR
)malloc(dwBufferSize
);
36 NS_WARNING("failed to allocate buffer");
39 status
= RegQueryValueEx(HKEY_PERFORMANCE_DATA
, L
"Counter 9", NULL
, NULL
,
40 (LPBYTE
)pBuffer
, &dwBufferSize
);
41 if (ERROR_SUCCESS
!= status
) {
43 nsPrintfCString("RegQueryValueEx failed with 0x%lx.\n", status
).get());
48 LPWSTR pwszCounterText
= pBuffer
; // Used to cycle through the Counter text
50 pwszCounterText
+= (wcslen(pwszCounterText
) + 1);
51 pwszCounterText
+= (wcslen(pwszCounterText
) + 1);
53 for (; *pwszCounterText
; pwszCounterText
+= (wcslen(pwszCounterText
) + 1)) {
54 // Keep a pointer to the counter index, to read the index later if the name
55 // is the one we are looking for.
56 LPWSTR counterIndex
= pwszCounterText
;
57 pwszCounterText
+= (wcslen(pwszCounterText
) + 1); // Skip past index value
59 if (!wcscmp(L
"Processor Information", pwszCounterText
)) {
60 mBlockIndex
= _wcsdup(counterIndex
);
61 } else if (!wcscmp(L
"% Processor Performance", pwszCounterText
)) {
62 mCounterNameIndex
= _wtoi(counterIndex
);
64 // We have found all the indexes we were looking for.
72 NS_WARNING("index of the performance counter block not found");
76 mBuffer
= (LPBYTE
)malloc(mBufferSize
);
78 NS_WARNING("failed to allocate initial buffer");
81 dwBufferSize
= mBufferSize
;
83 // Typically RegQueryValueEx will set the size variable to the required size.
84 // But this does not work when querying object index values, and the buffer
85 // size has to be increased in a loop until RegQueryValueEx no longer returns
87 while (ERROR_MORE_DATA
==
88 (status
= RegQueryValueEx(HKEY_PERFORMANCE_DATA
, mBlockIndex
, NULL
,
89 NULL
, mBuffer
, &dwBufferSize
))) {
91 auto* oldBuffer
= mBuffer
;
92 mBuffer
= (LPBYTE
)realloc(mBuffer
, mBufferSize
);
94 NS_WARNING("failed to reallocate buffer");
98 dwBufferSize
= mBufferSize
;
101 if (ERROR_SUCCESS
!= status
) {
102 NS_WARNING(nsPrintfCString("RegQueryValueEx failed getting required buffer "
103 "size. Error is 0x%lx.\n",
111 PERF_DATA_BLOCK
* dataBlock
= (PERF_DATA_BLOCK
*)mBuffer
;
112 LPBYTE pObject
= mBuffer
+ dataBlock
->HeaderLength
;
113 PERF_OBJECT_TYPE
* object
= (PERF_OBJECT_TYPE
*)pObject
;
114 PERF_COUNTER_DEFINITION
* counter
= nullptr;
116 PERF_COUNTER_DEFINITION
* pCounter
=
117 (PERF_COUNTER_DEFINITION
*)(pObject
+ object
->HeaderLength
);
118 for (DWORD i
= 0; i
< object
->NumCounters
; i
++) {
119 if (mCounterNameIndex
== pCounter
->CounterNameTitleIndex
) {
126 if (!counter
|| !mCPUCounters
.resize(GetNumberOfProcessors())) {
127 NS_WARNING("failing to find counter or resize the mCPUCounters vector");
133 MOZ_ASSERT(counter
->CounterType
== PERF_AVERAGE_BULK
);
134 PERF_COUNTER_DEFINITION
* baseCounter
= counter
+ 1;
135 MOZ_ASSERT((baseCounter
->CounterType
& PERF_COUNTER_BASE
) ==
138 PERF_INSTANCE_DEFINITION
* instanceDef
=
139 (PERF_INSTANCE_DEFINITION
*)(pObject
+ object
->DefinitionLength
);
140 for (LONG i
= 0; i
< object
->NumInstances
; i
++) {
141 PERF_COUNTER_BLOCK
* counterBlock
=
142 (PERF_COUNTER_BLOCK
*)((LPBYTE
)instanceDef
+ instanceDef
->ByteLength
);
144 LPWSTR name
= (LPWSTR
)(((LPBYTE
)instanceDef
) + instanceDef
->NameOffset
);
145 unsigned int cpuId
, coreId
;
146 if (swscanf(name
, L
"%u,%u", &cpuId
, &coreId
) == 2 && cpuId
== 0 &&
147 coreId
< mCPUCounters
.length()) {
148 auto& CPUCounter
= mCPUCounters
[coreId
];
149 CPUCounter
.data
= *(UNALIGNED ULONGLONG
*)((LPBYTE
)counterBlock
+
150 counter
->CounterOffset
);
152 *(DWORD
*)((LPBYTE
)counterBlock
+ baseCounter
->CounterOffset
);
154 // Now get the nominal core frequency.
156 nsAutoString
keyName(
157 L
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\");
158 keyName
.AppendInt(coreId
);
160 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, keyName
.get(), 0, KEY_QUERY_VALUE
,
161 &key
) == ERROR_SUCCESS
) {
165 if (RegQueryValueEx(key
, L
"~Mhz", 0, 0, reinterpret_cast<LPBYTE
>(&data
),
166 &len
) == ERROR_SUCCESS
) {
167 CPUCounter
.nominalFrequency
= data
;
171 instanceDef
= (PERF_INSTANCE_DEFINITION
*)((LPBYTE
)counterBlock
+
172 counterBlock
->ByteLength
);
176 ProfilerCPUFreq::~ProfilerCPUFreq() {
177 RegCloseKey(HKEY_PERFORMANCE_DATA
);
179 mBlockIndex
= nullptr;
184 void ProfilerCPUFreq::Sample() {
185 DWORD dwBufferSize
= mBufferSize
;
187 (ERROR_SUCCESS
!= RegQueryValueEx(HKEY_PERFORMANCE_DATA
, mBlockIndex
,
188 NULL
, NULL
, mBuffer
, &dwBufferSize
))) {
189 NS_WARNING("failed to query performance data");
193 PERF_DATA_BLOCK
* dataBlock
= (PERF_DATA_BLOCK
*)mBuffer
;
194 LPBYTE pObject
= mBuffer
+ dataBlock
->HeaderLength
;
195 PERF_OBJECT_TYPE
* object
= (PERF_OBJECT_TYPE
*)pObject
;
196 PERF_COUNTER_DEFINITION
* counter
= nullptr;
198 PERF_COUNTER_DEFINITION
* pCounter
=
199 (PERF_COUNTER_DEFINITION
*)(pObject
+ object
->HeaderLength
);
200 for (DWORD i
= 0; i
< object
->NumCounters
; i
++) {
201 if (mCounterNameIndex
== pCounter
->CounterNameTitleIndex
) {
209 NS_WARNING("failed to find counter");
213 MOZ_ASSERT(counter
->CounterType
== PERF_AVERAGE_BULK
);
214 PERF_COUNTER_DEFINITION
* baseCounter
= counter
+ 1;
215 MOZ_ASSERT((baseCounter
->CounterType
& PERF_COUNTER_BASE
) ==
218 PERF_INSTANCE_DEFINITION
* instanceDef
=
219 (PERF_INSTANCE_DEFINITION
*)(pObject
+ object
->DefinitionLength
);
220 for (LONG i
= 0; i
< object
->NumInstances
; i
++) {
221 PERF_COUNTER_BLOCK
* counterBlock
=
222 (PERF_COUNTER_BLOCK
*)((LPBYTE
)instanceDef
+ instanceDef
->ByteLength
);
224 LPWSTR name
= (LPWSTR
)(((LPBYTE
)instanceDef
) + instanceDef
->NameOffset
);
225 unsigned int cpuId
, coreId
;
226 if (swscanf(name
, L
"%u,%u", &cpuId
, &coreId
) == 2 && cpuId
== 0 &&
227 coreId
< mCPUCounters
.length()) {
228 auto& CPUCounter
= mCPUCounters
[coreId
];
229 ULONGLONG prevData
= CPUCounter
.data
;
230 DWORD prevBase
= CPUCounter
.base
;
231 CPUCounter
.data
= *(UNALIGNED ULONGLONG
*)((LPBYTE
)counterBlock
+
232 counter
->CounterOffset
);
234 *(DWORD
*)((LPBYTE
)counterBlock
+ baseCounter
->CounterOffset
);
235 if (prevBase
&& prevBase
!= CPUCounter
.base
) {
236 CPUCounter
.freq
= CPUCounter
.nominalFrequency
*
237 (CPUCounter
.data
- prevData
) /
238 (CPUCounter
.base
- prevBase
) / 1000 * 10;
241 instanceDef
= (PERF_INSTANCE_DEFINITION
*)((LPBYTE
)counterBlock
+
242 counterBlock
->ByteLength
);