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