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