Commit | Line | Data |
---|---|---|
5039dede AK |
1 | /* |
2 | ** Windows Performance NetXMS subagent | |
aed55395 | 3 | ** Copyright (C) 2004-2012 Victor Kirhenshtein |
5039dede AK |
4 | ** |
5 | ** This program is free software; you can redistribute it and/or modify | |
6 | ** it under the terms of the GNU General Public License as published by | |
7 | ** the Free Software Foundation; either version 2 of the License, or | |
8 | ** (at your option) any later version. | |
9 | ** | |
10 | ** This program is distributed in the hope that it will be useful, | |
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | ** GNU General Public License for more details. | |
14 | ** | |
15 | ** You should have received a copy of the GNU General Public License | |
16 | ** along with this program; if not, write to the Free Software | |
17 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | ** | |
19 | ** File: winperf.cpp | |
20 | ** | |
21 | **/ | |
22 | ||
23 | #include "winperf.h" | |
24 | ||
25 | ||
26 | // | |
27 | // Constants | |
28 | // | |
29 | ||
30 | #define MAX_CPU_COUNT 64 | |
31 | ||
32 | #define WPF_ENABLE_DEFAULT_COUNTERS 0x0001 | |
33 | ||
34 | ||
35 | // | |
36 | // Global variables | |
37 | // | |
38 | ||
39 | HANDLE g_hCondShutdown = NULL; | |
40 | ||
41 | ||
42 | // | |
43 | // Static variables | |
44 | // | |
45 | ||
46 | static DWORD m_dwFlags = WPF_ENABLE_DEFAULT_COUNTERS; | |
47 | static DWORD m_dwNumCPU = 1; | |
48 | static WINPERF_COUNTER *m_pProcessorCounters[MAX_CPU_COUNT]; | |
49 | static WINPERF_COUNTER *m_pProcessorCounters5[MAX_CPU_COUNT]; | |
50 | static WINPERF_COUNTER *m_pProcessorCounters15[MAX_CPU_COUNT]; | |
51 | ||
52 | ||
53 | // | |
54 | // List of predefined performance counters | |
55 | // | |
56 | static struct | |
57 | { | |
58 | TCHAR *pszParamName; | |
59 | TCHAR *pszCounterName; | |
60 | int iClass; | |
61 | int iNumSamples; | |
62 | int iDataType; | |
63 | TCHAR *pszDescription; | |
64 | int iDCIDataType; | |
65 | } m_counterList[] = | |
66 | { | |
67 | { _T("System.CPU.LoadAvg"), _T("\\System\\Processor Queue Length"), 0, | |
68 | 60, COUNTER_TYPE_FLOAT, _T("Average CPU load for last minute"), DCI_DT_FLOAT }, | |
69 | { _T("System.CPU.LoadAvg5"), _T("\\System\\Processor Queue Length"), 0, | |
70 | 300, COUNTER_TYPE_FLOAT, _T("Average CPU load for last 5 minutes"), DCI_DT_FLOAT }, | |
71 | { _T("System.CPU.LoadAvg15"), _T("\\System\\Processor Queue Length"), 0, | |
72 | 900, COUNTER_TYPE_FLOAT, _T("Average CPU load for last 15 minutes"), DCI_DT_FLOAT }, | |
73 | { _T("System.CPU.Usage"), _T("\\Processor(_Total)\\% Processor Time"), 0, | |
74 | 60, COUNTER_TYPE_INT32, _T("Average CPU utilization for last minute"), DCI_DT_INT }, | |
75 | { _T("System.CPU.Usage5"), _T("\\Processor(_Total)\\% Processor Time"), 0, | |
76 | 300, COUNTER_TYPE_INT32, _T("Average CPU utilization for last 5 minutes"), DCI_DT_INT }, | |
77 | { _T("System.CPU.Usage15"), _T("\\Processor(_Total)\\% Processor Time"), 0, | |
78 | 900, COUNTER_TYPE_INT32, _T("Average CPU utilization for last 15 minutes"), DCI_DT_INT }, | |
79 | { _T("System.IO.DiskQueue"), _T("\\PhysicalDisk(_Total)\\Avg. Disk Queue Length"), 0, | |
80 | 60, COUNTER_TYPE_FLOAT, _T("Average disk queue length for last minute"), DCI_DT_FLOAT }, | |
81 | { _T("System.IO.DiskTime"), _T("\\PhysicalDisk(_Total)\\% Disk Time"), 0, | |
82 | 60, COUNTER_TYPE_FLOAT, _T("Average disk busy time for last minute"), DCI_DT_FLOAT }, | |
83 | { NULL, NULL, 0, 0, 0, NULL, 0 } | |
84 | }; | |
85 | ||
86 | ||
87 | // | |
88 | // Value of given performance counter | |
89 | // | |
90 | ||
91 | static LONG H_PdhVersion(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue) | |
92 | { | |
93 | DWORD dwVersion; | |
94 | ||
95 | if (PdhGetDllVersion(&dwVersion) != ERROR_SUCCESS) | |
96 | return SYSINFO_RC_ERROR; | |
97 | ret_uint(pValue, dwVersion); | |
98 | return SYSINFO_RC_SUCCESS; | |
99 | } | |
100 | ||
101 | ||
102 | // | |
103 | // Value of CPU utilization counter | |
104 | // | |
105 | ||
106 | static LONG H_CPUUsage(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue) | |
107 | { | |
108 | LONG nProcessor, nRet = SYSINFO_RC_SUCCESS; | |
109 | TCHAR *pEnd, szBuffer[16]; | |
110 | ||
6173bea8 | 111 | if (!AgentGetParameterArg(pszParam, 1, szBuffer, 16)) |
5039dede AK |
112 | return SYSINFO_RC_UNSUPPORTED; |
113 | ||
114 | nProcessor = _tcstol(szBuffer, &pEnd, 0); | |
115 | if ((*pEnd != 0) || (nProcessor < 0) || (nProcessor >= (LONG)m_dwNumCPU)) | |
116 | return SYSINFO_RC_UNSUPPORTED; | |
117 | ||
118 | switch(pArg[0]) | |
119 | { | |
120 | case _T('1'): // System.CPU.Usage(*) | |
121 | if (m_pProcessorCounters[nProcessor] != NULL) | |
122 | ret_int(pValue, m_pProcessorCounters[nProcessor]->value.iLong); | |
123 | else | |
124 | nRet = SYSINFO_RC_ERROR; | |
125 | break; | |
126 | case _T('2'): // System.CPU.Usage5(*) | |
127 | if (m_pProcessorCounters5[nProcessor] != NULL) | |
128 | ret_int(pValue, m_pProcessorCounters5[nProcessor]->value.iLong); | |
129 | else | |
130 | nRet = SYSINFO_RC_ERROR; | |
131 | break; | |
132 | case _T('3'): // System.CPU.Usage15(*) | |
133 | if (m_pProcessorCounters15[nProcessor] != NULL) | |
134 | ret_int(pValue, m_pProcessorCounters15[nProcessor]->value.iLong); | |
135 | else | |
136 | nRet = SYSINFO_RC_ERROR; | |
137 | break; | |
138 | default: | |
139 | nRet = SYSINFO_RC_UNSUPPORTED; | |
140 | break; | |
141 | } | |
142 | ||
143 | return nRet; | |
144 | } | |
145 | ||
146 | ||
147 | // | |
148 | // Value of given counter collected by one of the collector threads | |
149 | // | |
150 | ||
151 | LONG H_CollectedCounterData(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue) | |
152 | { | |
153 | switch(((WINPERF_COUNTER *)pArg)->wType) | |
154 | { | |
155 | case COUNTER_TYPE_INT32: | |
156 | ret_int(pValue, ((WINPERF_COUNTER *)pArg)->value.iLong); | |
157 | break; | |
158 | case COUNTER_TYPE_INT64: | |
159 | ret_int64(pValue, ((WINPERF_COUNTER *)pArg)->value.iLarge); | |
160 | break; | |
161 | case COUNTER_TYPE_FLOAT: | |
162 | ret_double(pValue, ((WINPERF_COUNTER *)pArg)->value.dFloat); | |
163 | break; | |
164 | } | |
165 | return SYSINFO_RC_SUCCESS; | |
166 | } | |
167 | ||
168 | ||
169 | // | |
170 | // Value of given performance counter | |
171 | // | |
172 | ||
173 | static LONG H_PdhCounterValue(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue) | |
174 | { | |
175 | HQUERY hQuery; | |
176 | HCOUNTER hCounter; | |
177 | PDH_RAW_COUNTER rawData1, rawData2; | |
178 | PDH_FMT_COUNTERVALUE counterValue; | |
179 | PDH_STATUS rc; | |
180 | TCHAR szCounter[MAX_PATH], szBuffer[16]; | |
181 | DWORD dwType; | |
182 | BOOL bUseTwoSamples = FALSE; | |
183 | static TCHAR szFName[] = _T("H_PdhCounterValue"); | |
184 | ||
185 | if (pArg == NULL) // Normal call | |
186 | { | |
6173bea8 VK |
187 | if ((!AgentGetParameterArg(pszParam, 1, szCounter, MAX_PATH)) || |
188 | (!AgentGetParameterArg(pszParam, 2, szBuffer, 16))) | |
5039dede AK |
189 | return SYSINFO_RC_UNSUPPORTED; |
190 | ||
191 | bUseTwoSamples = _tcstol(szBuffer, NULL, 0) ? TRUE : FALSE; | |
192 | } | |
193 | else // Call from H_CounterAlias | |
194 | { | |
195 | nx_strncpy(szCounter, pArg, MAX_PATH); | |
196 | } | |
197 | ||
198 | if ((rc = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS) | |
199 | { | |
200 | ReportPdhError(szFName, _T("PdhOpenQuery"), rc); | |
201 | return SYSINFO_RC_ERROR; | |
202 | } | |
203 | ||
204 | if ((rc = PdhAddCounter(hQuery, szCounter, 0, &hCounter)) != ERROR_SUCCESS) | |
205 | { | |
aed55395 VK |
206 | // Attempt to translate counter name |
207 | if ((rc == PDH_CSTATUS_NO_COUNTER) || (rc == PDH_CSTATUS_NO_OBJECT)) | |
208 | { | |
209 | TCHAR *newName = (TCHAR *)malloc(_tcslen(szCounter) * sizeof(TCHAR) * 4); | |
210 | if (TranslateCounterName(szCounter, newName)) | |
211 | { | |
212 | AgentWriteDebugLog(2, _T("WINPERF: Counter translated: %s ==> %s"), szCounter, newName); | |
213 | rc = PdhAddCounter(hQuery, newName, 0, &hCounter); | |
214 | } | |
215 | free(newName); | |
216 | } | |
217 | if (rc != ERROR_SUCCESS) | |
218 | { | |
219 | ReportPdhError(szFName, _T("PdhAddCounter"), rc); | |
220 | PdhCloseQuery(hQuery); | |
221 | return SYSINFO_RC_UNSUPPORTED; | |
222 | } | |
5039dede AK |
223 | } |
224 | ||
225 | // Get first sample | |
226 | if ((rc = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS) | |
227 | { | |
228 | ReportPdhError(szFName, _T("PdhCollectQueryData"), rc); | |
229 | PdhCloseQuery(hQuery); | |
230 | return SYSINFO_RC_ERROR; | |
231 | } | |
232 | PdhGetRawCounterValue(hCounter, &dwType, &rawData1); | |
233 | ||
234 | // Get second sample if required | |
235 | if (bUseTwoSamples) | |
236 | { | |
237 | Sleep(1000); // We will take second sample after one second | |
238 | if ((rc = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS) | |
239 | { | |
240 | ReportPdhError(szFName, _T("PdhCollectQueryData"), rc); | |
241 | PdhCloseQuery(hQuery); | |
242 | return SYSINFO_RC_ERROR; | |
243 | } | |
244 | PdhGetRawCounterValue(hCounter, NULL, &rawData2); | |
245 | } | |
246 | ||
247 | if (dwType & PERF_SIZE_LARGE) | |
248 | { | |
249 | if (bUseTwoSamples) | |
250 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LARGE, | |
251 | &rawData2, &rawData1, &counterValue); | |
252 | else | |
253 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LARGE, | |
254 | &rawData1, NULL, &counterValue); | |
255 | ret_int64(pValue, counterValue.largeValue); | |
256 | } | |
257 | else | |
258 | { | |
259 | if (bUseTwoSamples) | |
260 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LONG, | |
261 | &rawData2, &rawData1, &counterValue); | |
262 | else | |
263 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LONG, | |
264 | &rawData1, NULL, &counterValue); | |
265 | ret_int(pValue, counterValue.longValue); | |
266 | } | |
267 | PdhCloseQuery(hQuery); | |
268 | return SYSINFO_RC_SUCCESS; | |
269 | } | |
270 | ||
271 | ||
272 | // | |
273 | // List of available performance objects | |
274 | // | |
275 | ||
6173bea8 | 276 | static LONG H_PdhObjects(const TCHAR *pszParam, const TCHAR *pArg, StringList *value) |
5039dede AK |
277 | { |
278 | TCHAR *pszObject, *pszObjList, szHostName[256]; | |
279 | LONG iResult = SYSINFO_RC_ERROR; | |
280 | PDH_STATUS rc; | |
281 | DWORD dwSize; | |
282 | ||
283 | dwSize = 256; | |
284 | if (GetComputerName(szHostName, &dwSize)) | |
285 | { | |
286 | dwSize = 256000; | |
287 | pszObjList = (TCHAR *)malloc(sizeof(TCHAR) * dwSize); | |
288 | if ((rc = PdhEnumObjects(NULL, szHostName, pszObjList, &dwSize, | |
289 | PERF_DETAIL_WIZARD, TRUE)) == ERROR_SUCCESS) | |
290 | { | |
291 | for(pszObject = pszObjList; *pszObject != 0; pszObject += _tcslen(pszObject) + 1) | |
6173bea8 | 292 | value->add(pszObject); |
5039dede AK |
293 | iResult = SYSINFO_RC_SUCCESS; |
294 | } | |
295 | else | |
296 | { | |
297 | ReportPdhError(_T("H_PdhObjects"), _T("PdhEnumObjects"), rc); | |
298 | } | |
299 | free(pszObjList); | |
300 | } | |
301 | return iResult; | |
302 | } | |
303 | ||
304 | ||
305 | // | |
306 | // List of available performance items for given object | |
307 | // | |
308 | ||
6173bea8 | 309 | static LONG H_PdhObjectItems(const TCHAR *pszParam, const TCHAR *pArg, StringList *value) |
5039dede AK |
310 | { |
311 | TCHAR *pszElement, *pszCounterList, *pszInstanceList, szHostName[256], szObject[256]; | |
312 | LONG iResult = SYSINFO_RC_ERROR; | |
313 | DWORD dwSize1, dwSize2; | |
314 | PDH_STATUS rc; | |
315 | ||
6173bea8 | 316 | AgentGetParameterArg(pszParam, 1, szObject, 256); |
5039dede AK |
317 | if (szObject[0] != 0) |
318 | { | |
319 | dwSize1 = 256; | |
320 | if (GetComputerName(szHostName, &dwSize1)) | |
321 | { | |
322 | dwSize1 = dwSize2 = 256000; | |
323 | pszCounterList = (TCHAR *)malloc(sizeof(TCHAR) * dwSize1); | |
324 | pszInstanceList = (TCHAR *)malloc(sizeof(TCHAR) * dwSize2); | |
325 | rc = PdhEnumObjectItems(NULL, szHostName, szObject, | |
326 | pszCounterList, &dwSize1, pszInstanceList, &dwSize2, | |
327 | PERF_DETAIL_WIZARD, 0); | |
328 | if ((rc == ERROR_SUCCESS) || (rc == PDH_MORE_DATA)) | |
329 | { | |
330 | for(pszElement = (pArg[0] == _T('C')) ? pszCounterList : pszInstanceList; | |
331 | *pszElement != 0; pszElement += _tcslen(pszElement) + 1) | |
6173bea8 | 332 | value->add(pszElement); |
5039dede AK |
333 | iResult = SYSINFO_RC_SUCCESS; |
334 | } | |
335 | else | |
336 | { | |
337 | ReportPdhError(_T("H_PdhObjectItems"), _T("PdhEnumObjectItems"), rc); | |
338 | } | |
339 | free(pszCounterList); | |
340 | free(pszInstanceList); | |
341 | } | |
342 | } | |
343 | else | |
344 | { | |
345 | iResult = SYSINFO_RC_UNSUPPORTED; | |
346 | } | |
347 | return iResult; | |
348 | } | |
349 | ||
350 | ||
351 | // | |
352 | // Value of specific performance parameter, which is mapped one-to-one to | |
353 | // performance counter. Actually, it's an alias for PDH.CounterValue(xxx) parameter. | |
354 | // | |
355 | ||
356 | static LONG H_CounterAlias(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue) | |
357 | { | |
358 | return H_PdhCounterValue(NULL, pArg, pValue); | |
359 | } | |
360 | ||
361 | ||
362 | // | |
363 | // Initialize subagent | |
364 | // | |
365 | ||
ff175e91 | 366 | static BOOL SubAgentInit(Config *config) |
5039dede AK |
367 | { |
368 | // Create shutdown condition object | |
369 | g_hCondShutdown = CreateEvent(NULL, TRUE, FALSE, NULL); | |
370 | StartCollectorThreads(); | |
371 | return TRUE; | |
372 | } | |
373 | ||
374 | ||
375 | // | |
376 | // Handler for subagent unload | |
377 | // | |
378 | ||
379 | static void SubAgentShutdown(void) | |
380 | { | |
381 | if (g_hCondShutdown != NULL) | |
382 | SetEvent(g_hCondShutdown); | |
383 | Sleep(500); | |
384 | } | |
385 | ||
386 | ||
387 | // | |
388 | // Subagent information | |
389 | // | |
390 | ||
391 | static NETXMS_SUBAGENT_PARAM m_parameters[] = | |
392 | { | |
393 | { _T("PDH.CounterValue(*)"), H_PdhCounterValue, NULL, DCI_DT_INT, _T("") }, | |
394 | { _T("PDH.Version"), H_PdhVersion, NULL, DCI_DT_UINT, _T("Version of PDH.DLL") }, | |
7ee7f8bc VK |
395 | { _T("System.CPU.Usage(*)"), H_CPUUsage, _T("1"), DCI_DT_INT, DCIDESC_SYSTEM_CPU_USAGE_EX }, |
396 | { _T("System.CPU.Usage5(*)"), H_CPUUsage, _T("2"), DCI_DT_INT, DCIDESC_SYSTEM_CPU_USAGE5_EX }, | |
397 | { _T("System.CPU.Usage15(*)"), H_CPUUsage, _T("3"), DCI_DT_INT, DCIDESC_SYSTEM_CPU_USAGE15_EX }, | |
398 | { _T("System.ThreadCount"), H_CounterAlias, _T("\\System\\Threads"), DCI_DT_UINT, DCIDESC_SYSTEM_THREADCOUNT }, | |
399 | { _T("System.Uptime"), H_CounterAlias, _T("\\System\\System Up Time"), DCI_DT_UINT, DCIDESC_SYSTEM_UPTIME } | |
5039dede | 400 | }; |
f1a20e8d | 401 | static NETXMS_SUBAGENT_LIST m_enums[] = |
5039dede AK |
402 | { |
403 | { _T("PDH.ObjectCounters(*)"), H_PdhObjectItems, _T("C") }, | |
404 | { _T("PDH.ObjectInstances(*)"), H_PdhObjectItems, _T("I") }, | |
405 | { _T("PDH.Objects"), H_PdhObjects, NULL } | |
406 | }; | |
407 | ||
408 | static NETXMS_SUBAGENT_INFO m_info = | |
409 | { | |
410 | NETXMS_SUBAGENT_INFO_MAGIC, | |
7ee7f8bc | 411 | _T("WinPerf"), NETXMS_VERSION_STRING, |
5039dede AK |
412 | SubAgentInit, SubAgentShutdown, NULL, // handlers |
413 | 0, NULL, // parameters | |
f1a20e8d | 414 | sizeof(m_enums) / sizeof(NETXMS_SUBAGENT_LIST), |
5039dede | 415 | m_enums, |
f1a20e8d VK |
416 | 0, NULL, // tables |
417 | 0, NULL, // actions | |
418 | 0, NULL // push parameters | |
5039dede AK |
419 | }; |
420 | ||
421 | ||
422 | // | |
423 | // Add new parameter to list | |
424 | // | |
425 | ||
426 | BOOL AddParameter(TCHAR *pszName, LONG (* fpHandler)(const TCHAR *, const TCHAR *, TCHAR *), | |
427 | TCHAR *pArg, int iDataType, TCHAR *pszDescription) | |
428 | { | |
429 | DWORD i; | |
430 | ||
f1a20e8d VK |
431 | for(i = 0; i < m_info.numParameters; i++) |
432 | if (!_tcsicmp(pszName, m_info.parameters[i].name)) | |
5039dede AK |
433 | break; |
434 | ||
f1a20e8d | 435 | if (i == m_info.numParameters) |
5039dede AK |
436 | { |
437 | // Extend list | |
f1a20e8d VK |
438 | m_info.numParameters++; |
439 | m_info.parameters = | |
440 | (NETXMS_SUBAGENT_PARAM *)realloc(m_info.parameters, | |
441 | sizeof(NETXMS_SUBAGENT_PARAM) * m_info.numParameters); | |
5039dede AK |
442 | } |
443 | ||
f1a20e8d VK |
444 | nx_strncpy(m_info.parameters[i].name, pszName, MAX_PARAM_NAME); |
445 | m_info.parameters[i].handler = fpHandler; | |
446 | m_info.parameters[i].arg = pArg; | |
447 | m_info.parameters[i].dataType = iDataType; | |
448 | nx_strncpy(m_info.parameters[i].description, pszDescription, MAX_DB_STRING); | |
5039dede AK |
449 | |
450 | return TRUE; | |
451 | } | |
452 | ||
453 | ||
454 | // | |
455 | // Add predefined counters | |
456 | // | |
457 | ||
f1a20e8d | 458 | static void AddPredefinedCounters() |
5039dede AK |
459 | { |
460 | DWORD i; | |
461 | WINPERF_COUNTER *pCnt; | |
462 | SYSTEM_INFO sysInfo; | |
463 | TCHAR szBuffer[MAX_PATH]; | |
464 | ||
465 | for(i = 0; m_counterList[i].pszParamName != NULL; i++) | |
466 | { | |
467 | pCnt = AddCounter(m_counterList[i].pszCounterName, m_counterList[i].iClass, | |
468 | m_counterList[i].iNumSamples, m_counterList[i].iDataType); | |
469 | if (pCnt != NULL) | |
470 | AddParameter(m_counterList[i].pszParamName, H_CollectedCounterData, | |
471 | (TCHAR *)pCnt, m_counterList[i].iDCIDataType, | |
472 | m_counterList[i].pszDescription); | |
473 | } | |
474 | ||
475 | // Add CPU utilization counters | |
476 | GetSystemInfo(&sysInfo); | |
477 | m_dwNumCPU = sysInfo.dwNumberOfProcessors; | |
478 | for(i = 0; i < m_dwNumCPU; i++) | |
479 | { | |
480 | _sntprintf(szBuffer, MAX_PATH, _T("\\Processor(%d)\\%% Processor Time"), i); | |
481 | m_pProcessorCounters[i] = AddCounter(szBuffer, 0, 60, COUNTER_TYPE_INT32); | |
482 | m_pProcessorCounters5[i] = AddCounter(szBuffer, 0, 300, COUNTER_TYPE_INT32); | |
483 | m_pProcessorCounters15[i] = AddCounter(szBuffer, 0, 900, COUNTER_TYPE_INT32); | |
484 | } | |
485 | } | |
486 | ||
487 | ||
488 | // | |
489 | // Configuration file template | |
490 | // | |
491 | ||
492 | static TCHAR *m_pszCounterList = NULL; | |
ff175e91 | 493 | static NX_CFG_TEMPLATE m_cfgTemplate[] = |
5039dede AK |
494 | { |
495 | { _T("Counter"), CT_STRING_LIST, _T('\n'), 0, 0, 0, &m_pszCounterList }, | |
496 | { _T("EnableDefaultCounters"), CT_BOOLEAN, 0, 0, WPF_ENABLE_DEFAULT_COUNTERS, 0, &m_dwFlags }, | |
497 | { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL } | |
498 | }; | |
499 | ||
500 | ||
501 | // | |
502 | // Entry point for NetXMS agent | |
503 | // | |
504 | ||
505 | extern "C" BOOL __declspec(dllexport) __cdecl | |
ff175e91 | 506 | NxSubAgentRegister(NETXMS_SUBAGENT_INFO **ppInfo, Config *config) |
5039dede | 507 | { |
ff175e91 | 508 | DWORD i, dwBufferSize, dwBytes, dwType, dwStatus; |
5039dede AK |
509 | TCHAR *pBuffer, *newName; |
510 | ||
f1a20e8d | 511 | if (m_info.parameters != NULL) |
5039dede AK |
512 | return FALSE; // Most likely another instance of WINPERF subagent already loaded |
513 | ||
514 | // Read performance counter indexes | |
515 | pBuffer = NULL; | |
516 | dwBufferSize = 0; | |
517 | do | |
518 | { | |
519 | dwBufferSize += 8192; | |
520 | pBuffer = (TCHAR *)realloc(pBuffer, dwBufferSize); | |
521 | dwBytes = dwBufferSize; | |
522 | dwStatus = RegQueryValueEx(HKEY_PERFORMANCE_DATA, _T("Counter 009"), NULL, &dwType, (BYTE *)pBuffer, &dwBytes); | |
523 | } while(dwStatus == ERROR_MORE_DATA); | |
524 | if (dwStatus == ERROR_SUCCESS) | |
525 | { | |
526 | CreateCounterIndex(pBuffer); | |
527 | } | |
528 | safe_free(pBuffer); | |
529 | ||
530 | // Init parameters list | |
f1a20e8d VK |
531 | m_info.numParameters = sizeof(m_parameters) / sizeof(NETXMS_SUBAGENT_PARAM); |
532 | m_info.parameters = (NETXMS_SUBAGENT_PARAM *)nx_memdup(m_parameters, sizeof(m_parameters)); | |
5039dede AK |
533 | |
534 | // Check counter names for H_CounterAlias | |
f1a20e8d | 535 | for(i = 0; i < m_info.numParameters; i++) |
5039dede | 536 | { |
f1a20e8d | 537 | if (m_info.parameters[i].handler == H_CounterAlias) |
5039dede | 538 | { |
f1a20e8d | 539 | CheckCounter(m_info.parameters[i].arg, &newName); |
5039dede | 540 | if (newName != NULL) |
f1a20e8d | 541 | m_info.parameters[i].arg = newName; |
5039dede AK |
542 | } |
543 | } | |
544 | ||
545 | // Load configuration | |
97a92859 | 546 | bool success = config->parseTemplate(_T("WinPerf"), m_cfgTemplate); |
ff175e91 | 547 | if (success) |
5039dede AK |
548 | { |
549 | TCHAR *pItem, *pEnd; | |
550 | ||
551 | // Parse counter list | |
552 | if (m_pszCounterList != NULL) | |
553 | { | |
554 | for(pItem = m_pszCounterList; *pItem != 0; pItem = pEnd + 1) | |
555 | { | |
556 | pEnd = _tcschr(pItem, _T('\n')); | |
557 | if (pEnd != NULL) | |
558 | *pEnd = 0; | |
559 | StrStrip(pItem); | |
560 | if (!AddCounterFromConfig(pItem)) | |
6173bea8 | 561 | AgentWriteLog(EVENTLOG_WARNING_TYPE, |
5039dede AK |
562 | _T("Unable to add counter from configuration file. ") |
563 | _T("Original configuration record: %s"), pItem); | |
564 | } | |
565 | free(m_pszCounterList); | |
566 | } | |
567 | ||
568 | if (m_dwFlags & WPF_ENABLE_DEFAULT_COUNTERS) | |
569 | AddPredefinedCounters(); | |
570 | } | |
571 | else | |
572 | { | |
573 | safe_free(m_pszCounterList); | |
574 | } | |
575 | *ppInfo = &m_info; | |
ff175e91 | 576 | return success; |
5039dede AK |
577 | } |
578 | ||
579 | ||
580 | // | |
581 | // DLL entry point | |
582 | // | |
583 | ||
584 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) | |
585 | { | |
586 | if (dwReason == DLL_PROCESS_ATTACH) | |
587 | DisableThreadLibraryCalls(hInstance); | |
588 | return TRUE; | |
589 | } |