Commit | Line | Data |
---|---|---|
5039dede AK |
1 | /* |
2 | ** Windows Performance NetXMS subagent | |
3 | ** Copyright (C) 2004, 2005, 2006, 2007 Victor Kirhenshtein | |
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 | ||
111 | if (!NxGetParameterArg(pszParam, 1, szBuffer, 16)) | |
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 | { | |
187 | if ((!NxGetParameterArg(pszParam, 1, szCounter, MAX_PATH)) || | |
188 | (!NxGetParameterArg(pszParam, 2, szBuffer, 16))) | |
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 | { | |
206 | ReportPdhError(szFName, _T("PdhAddCounter"), rc); | |
207 | PdhCloseQuery(hQuery); | |
208 | return SYSINFO_RC_UNSUPPORTED; | |
209 | } | |
210 | ||
211 | // Get first sample | |
212 | if ((rc = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS) | |
213 | { | |
214 | ReportPdhError(szFName, _T("PdhCollectQueryData"), rc); | |
215 | PdhCloseQuery(hQuery); | |
216 | return SYSINFO_RC_ERROR; | |
217 | } | |
218 | PdhGetRawCounterValue(hCounter, &dwType, &rawData1); | |
219 | ||
220 | // Get second sample if required | |
221 | if (bUseTwoSamples) | |
222 | { | |
223 | Sleep(1000); // We will take second sample after one second | |
224 | if ((rc = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS) | |
225 | { | |
226 | ReportPdhError(szFName, _T("PdhCollectQueryData"), rc); | |
227 | PdhCloseQuery(hQuery); | |
228 | return SYSINFO_RC_ERROR; | |
229 | } | |
230 | PdhGetRawCounterValue(hCounter, NULL, &rawData2); | |
231 | } | |
232 | ||
233 | if (dwType & PERF_SIZE_LARGE) | |
234 | { | |
235 | if (bUseTwoSamples) | |
236 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LARGE, | |
237 | &rawData2, &rawData1, &counterValue); | |
238 | else | |
239 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LARGE, | |
240 | &rawData1, NULL, &counterValue); | |
241 | ret_int64(pValue, counterValue.largeValue); | |
242 | } | |
243 | else | |
244 | { | |
245 | if (bUseTwoSamples) | |
246 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LONG, | |
247 | &rawData2, &rawData1, &counterValue); | |
248 | else | |
249 | PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_LONG, | |
250 | &rawData1, NULL, &counterValue); | |
251 | ret_int(pValue, counterValue.longValue); | |
252 | } | |
253 | PdhCloseQuery(hQuery); | |
254 | return SYSINFO_RC_SUCCESS; | |
255 | } | |
256 | ||
257 | ||
258 | // | |
259 | // List of available performance objects | |
260 | // | |
261 | ||
262 | static LONG H_PdhObjects(const TCHAR *pszParam, const TCHAR *pArg, NETXMS_VALUES_LIST *pValue) | |
263 | { | |
264 | TCHAR *pszObject, *pszObjList, szHostName[256]; | |
265 | LONG iResult = SYSINFO_RC_ERROR; | |
266 | PDH_STATUS rc; | |
267 | DWORD dwSize; | |
268 | ||
269 | dwSize = 256; | |
270 | if (GetComputerName(szHostName, &dwSize)) | |
271 | { | |
272 | dwSize = 256000; | |
273 | pszObjList = (TCHAR *)malloc(sizeof(TCHAR) * dwSize); | |
274 | if ((rc = PdhEnumObjects(NULL, szHostName, pszObjList, &dwSize, | |
275 | PERF_DETAIL_WIZARD, TRUE)) == ERROR_SUCCESS) | |
276 | { | |
277 | for(pszObject = pszObjList; *pszObject != 0; pszObject += _tcslen(pszObject) + 1) | |
278 | NxAddResultString(pValue, pszObject); | |
279 | iResult = SYSINFO_RC_SUCCESS; | |
280 | } | |
281 | else | |
282 | { | |
283 | ReportPdhError(_T("H_PdhObjects"), _T("PdhEnumObjects"), rc); | |
284 | } | |
285 | free(pszObjList); | |
286 | } | |
287 | return iResult; | |
288 | } | |
289 | ||
290 | ||
291 | // | |
292 | // List of available performance items for given object | |
293 | // | |
294 | ||
295 | static LONG H_PdhObjectItems(const TCHAR *pszParam, const TCHAR *pArg, NETXMS_VALUES_LIST *pValue) | |
296 | { | |
297 | TCHAR *pszElement, *pszCounterList, *pszInstanceList, szHostName[256], szObject[256]; | |
298 | LONG iResult = SYSINFO_RC_ERROR; | |
299 | DWORD dwSize1, dwSize2; | |
300 | PDH_STATUS rc; | |
301 | ||
302 | NxGetParameterArg(pszParam, 1, szObject, 256); | |
303 | if (szObject[0] != 0) | |
304 | { | |
305 | dwSize1 = 256; | |
306 | if (GetComputerName(szHostName, &dwSize1)) | |
307 | { | |
308 | dwSize1 = dwSize2 = 256000; | |
309 | pszCounterList = (TCHAR *)malloc(sizeof(TCHAR) * dwSize1); | |
310 | pszInstanceList = (TCHAR *)malloc(sizeof(TCHAR) * dwSize2); | |
311 | rc = PdhEnumObjectItems(NULL, szHostName, szObject, | |
312 | pszCounterList, &dwSize1, pszInstanceList, &dwSize2, | |
313 | PERF_DETAIL_WIZARD, 0); | |
314 | if ((rc == ERROR_SUCCESS) || (rc == PDH_MORE_DATA)) | |
315 | { | |
316 | for(pszElement = (pArg[0] == _T('C')) ? pszCounterList : pszInstanceList; | |
317 | *pszElement != 0; pszElement += _tcslen(pszElement) + 1) | |
318 | NxAddResultString(pValue, pszElement); | |
319 | iResult = SYSINFO_RC_SUCCESS; | |
320 | } | |
321 | else | |
322 | { | |
323 | ReportPdhError(_T("H_PdhObjectItems"), _T("PdhEnumObjectItems"), rc); | |
324 | } | |
325 | free(pszCounterList); | |
326 | free(pszInstanceList); | |
327 | } | |
328 | } | |
329 | else | |
330 | { | |
331 | iResult = SYSINFO_RC_UNSUPPORTED; | |
332 | } | |
333 | return iResult; | |
334 | } | |
335 | ||
336 | ||
337 | // | |
338 | // Value of specific performance parameter, which is mapped one-to-one to | |
339 | // performance counter. Actually, it's an alias for PDH.CounterValue(xxx) parameter. | |
340 | // | |
341 | ||
342 | static LONG H_CounterAlias(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue) | |
343 | { | |
344 | return H_PdhCounterValue(NULL, pArg, pValue); | |
345 | } | |
346 | ||
347 | ||
348 | // | |
349 | // Initialize subagent | |
350 | // | |
351 | ||
352 | static BOOL SubAgentInit(TCHAR *pszConfigFile) | |
353 | { | |
354 | // Create shutdown condition object | |
355 | g_hCondShutdown = CreateEvent(NULL, TRUE, FALSE, NULL); | |
356 | StartCollectorThreads(); | |
357 | return TRUE; | |
358 | } | |
359 | ||
360 | ||
361 | // | |
362 | // Handler for subagent unload | |
363 | // | |
364 | ||
365 | static void SubAgentShutdown(void) | |
366 | { | |
367 | if (g_hCondShutdown != NULL) | |
368 | SetEvent(g_hCondShutdown); | |
369 | Sleep(500); | |
370 | } | |
371 | ||
372 | ||
373 | // | |
374 | // Subagent information | |
375 | // | |
376 | ||
377 | static NETXMS_SUBAGENT_PARAM m_parameters[] = | |
378 | { | |
379 | { _T("PDH.CounterValue(*)"), H_PdhCounterValue, NULL, DCI_DT_INT, _T("") }, | |
380 | { _T("PDH.Version"), H_PdhVersion, NULL, DCI_DT_UINT, _T("Version of PDH.DLL") }, | |
381 | { _T("System.CPU.Usage(*)"), H_CPUUsage, "1", DCI_DT_INT, "Average CPU {instance} utilization for last minute" }, | |
382 | { _T("System.CPU.Usage5(*)"), H_CPUUsage, "2", DCI_DT_INT, "Average CPU {instance} utilization for last 5 minutes" }, | |
383 | { _T("System.CPU.Usage15(*)"), H_CPUUsage, "3", DCI_DT_INT, "Average CPU {instance} utilization for last 15 minutes" }, | |
384 | { _T("System.ThreadCount"), H_CounterAlias, _T("\\System\\Threads"), DCI_DT_INT, _T("Total number of threads") }, | |
385 | { _T("System.Uptime"), H_CounterAlias, _T("\\System\\System Up Time"), DCI_DT_UINT, _T("System uptime") } | |
386 | }; | |
387 | static NETXMS_SUBAGENT_ENUM m_enums[] = | |
388 | { | |
389 | { _T("PDH.ObjectCounters(*)"), H_PdhObjectItems, _T("C") }, | |
390 | { _T("PDH.ObjectInstances(*)"), H_PdhObjectItems, _T("I") }, | |
391 | { _T("PDH.Objects"), H_PdhObjects, NULL } | |
392 | }; | |
393 | ||
394 | static NETXMS_SUBAGENT_INFO m_info = | |
395 | { | |
396 | NETXMS_SUBAGENT_INFO_MAGIC, | |
397 | _T("WinPerf"), _T(NETXMS_VERSION_STRING) _T(DEBUG_SUFFIX), | |
398 | SubAgentInit, SubAgentShutdown, NULL, // handlers | |
399 | 0, NULL, // parameters | |
400 | sizeof(m_enums) / sizeof(NETXMS_SUBAGENT_ENUM), | |
401 | m_enums, | |
402 | 0, NULL // actions | |
403 | }; | |
404 | ||
405 | ||
406 | // | |
407 | // Add new parameter to list | |
408 | // | |
409 | ||
410 | BOOL AddParameter(TCHAR *pszName, LONG (* fpHandler)(const TCHAR *, const TCHAR *, TCHAR *), | |
411 | TCHAR *pArg, int iDataType, TCHAR *pszDescription) | |
412 | { | |
413 | DWORD i; | |
414 | ||
415 | for(i = 0; i < m_info.dwNumParameters; i++) | |
416 | if (!_tcsicmp(pszName, m_info.pParamList[i].szName)) | |
417 | break; | |
418 | ||
419 | if (i == m_info.dwNumParameters) | |
420 | { | |
421 | // Extend list | |
422 | m_info.dwNumParameters++; | |
423 | m_info.pParamList = | |
424 | (NETXMS_SUBAGENT_PARAM *)realloc(m_info.pParamList, | |
425 | sizeof(NETXMS_SUBAGENT_PARAM) * m_info.dwNumParameters); | |
426 | } | |
427 | ||
428 | nx_strncpy(m_info.pParamList[i].szName, pszName, MAX_PARAM_NAME); | |
429 | m_info.pParamList[i].fpHandler = fpHandler; | |
430 | m_info.pParamList[i].pArg = pArg; | |
431 | m_info.pParamList[i].iDataType = iDataType; | |
432 | nx_strncpy(m_info.pParamList[i].szDescription, pszDescription, MAX_DB_STRING); | |
433 | ||
434 | return TRUE; | |
435 | } | |
436 | ||
437 | ||
438 | // | |
439 | // Add predefined counters | |
440 | // | |
441 | ||
442 | static void AddPredefinedCounters(void) | |
443 | { | |
444 | DWORD i; | |
445 | WINPERF_COUNTER *pCnt; | |
446 | SYSTEM_INFO sysInfo; | |
447 | TCHAR szBuffer[MAX_PATH]; | |
448 | ||
449 | for(i = 0; m_counterList[i].pszParamName != NULL; i++) | |
450 | { | |
451 | pCnt = AddCounter(m_counterList[i].pszCounterName, m_counterList[i].iClass, | |
452 | m_counterList[i].iNumSamples, m_counterList[i].iDataType); | |
453 | if (pCnt != NULL) | |
454 | AddParameter(m_counterList[i].pszParamName, H_CollectedCounterData, | |
455 | (TCHAR *)pCnt, m_counterList[i].iDCIDataType, | |
456 | m_counterList[i].pszDescription); | |
457 | } | |
458 | ||
459 | // Add CPU utilization counters | |
460 | GetSystemInfo(&sysInfo); | |
461 | m_dwNumCPU = sysInfo.dwNumberOfProcessors; | |
462 | for(i = 0; i < m_dwNumCPU; i++) | |
463 | { | |
464 | _sntprintf(szBuffer, MAX_PATH, _T("\\Processor(%d)\\%% Processor Time"), i); | |
465 | m_pProcessorCounters[i] = AddCounter(szBuffer, 0, 60, COUNTER_TYPE_INT32); | |
466 | m_pProcessorCounters5[i] = AddCounter(szBuffer, 0, 300, COUNTER_TYPE_INT32); | |
467 | m_pProcessorCounters15[i] = AddCounter(szBuffer, 0, 900, COUNTER_TYPE_INT32); | |
468 | } | |
469 | } | |
470 | ||
471 | ||
472 | // | |
473 | // Configuration file template | |
474 | // | |
475 | ||
476 | static TCHAR *m_pszCounterList = NULL; | |
477 | static NX_CFG_TEMPLATE cfgTemplate[] = | |
478 | { | |
479 | { _T("Counter"), CT_STRING_LIST, _T('\n'), 0, 0, 0, &m_pszCounterList }, | |
480 | { _T("EnableDefaultCounters"), CT_BOOLEAN, 0, 0, WPF_ENABLE_DEFAULT_COUNTERS, 0, &m_dwFlags }, | |
481 | { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL } | |
482 | }; | |
483 | ||
484 | ||
485 | // | |
486 | // Entry point for NetXMS agent | |
487 | // | |
488 | ||
489 | extern "C" BOOL __declspec(dllexport) __cdecl | |
490 | NxSubAgentRegister(NETXMS_SUBAGENT_INFO **ppInfo, TCHAR *pszConfigFile) | |
491 | { | |
492 | DWORD i, dwResult, dwBufferSize, dwBytes, dwType, dwStatus; | |
493 | TCHAR *pBuffer, *newName; | |
494 | ||
495 | if (m_info.pParamList != NULL) | |
496 | return FALSE; // Most likely another instance of WINPERF subagent already loaded | |
497 | ||
498 | // Read performance counter indexes | |
499 | pBuffer = NULL; | |
500 | dwBufferSize = 0; | |
501 | do | |
502 | { | |
503 | dwBufferSize += 8192; | |
504 | pBuffer = (TCHAR *)realloc(pBuffer, dwBufferSize); | |
505 | dwBytes = dwBufferSize; | |
506 | dwStatus = RegQueryValueEx(HKEY_PERFORMANCE_DATA, _T("Counter 009"), NULL, &dwType, (BYTE *)pBuffer, &dwBytes); | |
507 | } while(dwStatus == ERROR_MORE_DATA); | |
508 | if (dwStatus == ERROR_SUCCESS) | |
509 | { | |
510 | CreateCounterIndex(pBuffer); | |
511 | } | |
512 | safe_free(pBuffer); | |
513 | ||
514 | // Init parameters list | |
515 | m_info.dwNumParameters = sizeof(m_parameters) / sizeof(NETXMS_SUBAGENT_PARAM); | |
516 | m_info.pParamList = (NETXMS_SUBAGENT_PARAM *)nx_memdup(m_parameters, sizeof(m_parameters)); | |
517 | ||
518 | // Check counter names for H_CounterAlias | |
519 | for(i = 0; i < m_info.dwNumParameters; i++) | |
520 | { | |
521 | if (m_info.pParamList[i].fpHandler == H_CounterAlias) | |
522 | { | |
523 | CheckCounter(m_info.pParamList[i].pArg, &newName); | |
524 | if (newName != NULL) | |
525 | m_info.pParamList[i].pArg = newName; | |
526 | } | |
527 | } | |
528 | ||
529 | // Load configuration | |
530 | dwResult = NxLoadConfig(pszConfigFile, _T("WinPerf"), cfgTemplate, FALSE); | |
531 | if (dwResult == NXCFG_ERR_OK) | |
532 | { | |
533 | TCHAR *pItem, *pEnd; | |
534 | ||
535 | // Parse counter list | |
536 | if (m_pszCounterList != NULL) | |
537 | { | |
538 | for(pItem = m_pszCounterList; *pItem != 0; pItem = pEnd + 1) | |
539 | { | |
540 | pEnd = _tcschr(pItem, _T('\n')); | |
541 | if (pEnd != NULL) | |
542 | *pEnd = 0; | |
543 | StrStrip(pItem); | |
544 | if (!AddCounterFromConfig(pItem)) | |
545 | NxWriteAgentLog(EVENTLOG_WARNING_TYPE, | |
546 | _T("Unable to add counter from configuration file. ") | |
547 | _T("Original configuration record: %s"), pItem); | |
548 | } | |
549 | free(m_pszCounterList); | |
550 | } | |
551 | ||
552 | if (m_dwFlags & WPF_ENABLE_DEFAULT_COUNTERS) | |
553 | AddPredefinedCounters(); | |
554 | } | |
555 | else | |
556 | { | |
557 | safe_free(m_pszCounterList); | |
558 | } | |
559 | *ppInfo = &m_info; | |
560 | return dwResult == NXCFG_ERR_OK; | |
561 | } | |
562 | ||
563 | ||
564 | // | |
565 | // DLL entry point | |
566 | // | |
567 | ||
568 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) | |
569 | { | |
570 | if (dwReason == DLL_PROCESS_ATTACH) | |
571 | DisableThreadLibraryCalls(hInstance); | |
572 | return TRUE; | |
573 | } |