- Implemented collector thread
[public/netxms.git] / src / agent / subagents / winperf / collect.cpp
1 /*
2 ** Windows Performance NetXMS subagent
3 ** Copyright (C) 2004 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 ** $module: collect.cpp
20 **
21 **/
22
23 #include "winperf.h"
24
25
26 //
27 // Static data
28 //
29
30 WINPERF_COUNTER_SET m_cntSet[3] =
31 {
32 { 1000, 0, NULL, _T('A') },
33 { 5000, 0, NULL, _T('B') },
34 { 60000, 0, NULL, _T('C') }
35 };
36
37
38 //
39 // Check that counter's name is valid and determine counter's type
40 //
41
42 static int CheckCounter(TCHAR *pszName)
43 {
44 HQUERY hQuery;
45 HCOUNTER hCounter;
46 PDH_STATUS rc;
47 PDH_COUNTER_INFO ci;
48 DWORD dwSize;
49 static TCHAR szFName[] = _T("CheckCounter");
50
51 if ((rc = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS)
52 {
53 ReportPdhError(szFName, _T("PdhOpenQuery"), rc);
54 return -1;
55 }
56
57 if ((rc = PdhAddCounter(hQuery, pszName, 0, &hCounter)) != ERROR_SUCCESS)
58 {
59 ReportPdhError(szFName, _T("PdhAddCounter"), rc);
60 PdhCloseQuery(hQuery);
61 return -1;
62 }
63
64 dwSize = sizeof(ci);
65 if ((rc = PdhGetCounterInfo(hCounter, FALSE, &dwSize, &ci)) != ERROR_SUCCESS)
66 {
67 ReportPdhError(szFName, _T("PdhGetCounterInfo"), rc);
68 PdhCloseQuery(hQuery);
69 return -1;
70 }
71
72 PdhCloseQuery(hQuery);
73 return (ci.dwType & PERF_SIZE_LARGE) ? COUNTER_TYPE_INT64 : COUNTER_TYPE_INT32;
74 }
75
76
77 //
78 // Add counter to set
79 //
80
81 WINPERF_COUNTER *AddCounter(TCHAR *pszName, int iClass, int iNumSamples, int iDataType)
82 {
83 WINPERF_COUNTER *pCnt;
84 int iType;
85
86 // Check for valid class
87 if ((iClass < 0) || (iClass > 2))
88 return NULL;
89
90 // Check counter's name and get it's type
91 iType = CheckCounter(pszName);
92 if (iType == -1)
93 return NULL;
94
95 // Create new counter
96 pCnt = (WINPERF_COUNTER *)malloc(sizeof(WINPERF_COUNTER));
97 memset(pCnt, 0, sizeof(WINPERF_COUNTER));
98 pCnt->pszName = _tcsdup(pszName);
99 pCnt->wType = (iDataType == COUNTER_TYPE_AUTO) ? iType : iDataType;
100 pCnt->wNumSamples = iNumSamples;
101 pCnt->pRawValues = (PDH_RAW_COUNTER *)malloc(sizeof(PDH_RAW_COUNTER) * iNumSamples);
102 memset(pCnt->pRawValues, 0, sizeof(PDH_RAW_COUNTER) * iNumSamples);
103 switch(pCnt->wType)
104 {
105 case COUNTER_TYPE_INT32:
106 pCnt->dwFormat = PDH_FMT_LONG;
107 break;
108 case COUNTER_TYPE_INT64:
109 pCnt->dwFormat = PDH_FMT_LARGE;
110 break;
111 case COUNTER_TYPE_FLOAT:
112 pCnt->dwFormat = PDH_FMT_DOUBLE;
113 break;
114 }
115
116 // Add counter to set
117 m_cntSet[iClass].dwNumCounters++;
118 m_cntSet[iClass].ppCounterList =
119 (WINPERF_COUNTER **)realloc(m_cntSet[iClass].ppCounterList, sizeof(WINPERF_COUNTER *) * m_cntSet[iClass].dwNumCounters);
120 m_cntSet[iClass].ppCounterList[m_cntSet[iClass].dwNumCounters - 1] = pCnt;
121
122 return pCnt;
123 }
124
125
126 //
127 // Add custom counter from configuration file
128 //
129
130 BOOL AddCounterFromConfig(TCHAR *pszStr)
131 {
132 return FALSE;
133 }
134
135
136 //
137 // Collector thread
138 //
139
140 static THREAD_RESULT THREAD_CALL CollectorThread(WINPERF_COUNTER_SET *pSet)
141 {
142 HQUERY hQuery;
143 PDH_STATUS rc;
144 PDH_STATISTICS statData;
145 DWORD i, dwOKCounters = 0;
146 TCHAR szFName[] = _T("CollectorThread_X");
147
148 szFName[16] = pSet->cClass;
149 if (pSet->dwNumCounters == 0)
150 {
151 NxWriteAgentLog(EVENTLOG_INFORMATION_TYPE, "Counter set %c is empty, "
152 "collector thread for that set will not start",
153 pSet->cClass);
154 return 0;
155 }
156
157 if ((rc = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS)
158 {
159 ReportPdhError(szFName, _T("PdhOpenQuery"), rc);
160 return -1;
161 }
162
163 // Add counters to query
164 for(i = 0; i < pSet->dwNumCounters; i++)
165 if ((rc = PdhAddCounter(hQuery, pSet->ppCounterList[i]->pszName,
166 0, &pSet->ppCounterList[i]->handle)) != ERROR_SUCCESS)
167 {
168 TCHAR szBuffer[1024];
169
170 NxWriteAgentLog(EVENTLOG_WARNING_TYPE, _T("%s: Unable to add counter \"%s\" to query (%s)"),
171 szFName, pSet->ppCounterList[i]->pszName, GetPdhErrorText(rc, szBuffer, 1024));
172 pSet->ppCounterList[i]->handle = NULL;
173 }
174 else
175 {
176 dwOKCounters++;
177 }
178
179 // Check if we was able to add at least one counter
180 if (dwOKCounters == 0)
181 {
182 PdhCloseQuery(hQuery);
183 NxWriteAgentLog(EVENTLOG_WARNING_TYPE, "Failed to add any counter to query for counter set %c, "
184 "collector thread for that set will not start",
185 pSet->cClass);
186 return 0;
187 }
188
189 // Main collection loop
190 while(1)
191 {
192 if (WaitForSingleObject(g_hCondShutdown, pSet->dwInterval) != WAIT_TIMEOUT)
193 break; // We got a signal
194
195 // Collect data
196 if ((rc = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS)
197 ReportPdhError(szFName, _T("PdhCollectQueryData"), rc);
198
199 // Get raw values for each counter and compute average value
200 for(i = 0; i < pSet->dwNumCounters; i++)
201 if (pSet->ppCounterList[i]->handle != NULL)
202 {
203 // Get raw value into buffer
204 PdhGetRawCounterValue(pSet->ppCounterList[i]->handle, NULL,
205 &pSet->ppCounterList[i]->pRawValues[pSet->ppCounterList[i]->dwBufferPos]);
206 pSet->ppCounterList[i]->dwBufferPos++;
207 if (pSet->ppCounterList[i]->dwBufferPos == (DWORD)pSet->ppCounterList[i]->wNumSamples)
208 pSet->ppCounterList[i]->dwBufferPos = 0;
209
210 // Calculate mean value
211 if ((rc = PdhComputeCounterStatistics(pSet->ppCounterList[i]->handle,
212 pSet->ppCounterList[i]->dwFormat,
213 pSet->ppCounterList[i]->dwBufferPos,
214 pSet->ppCounterList[i]->wNumSamples,
215 pSet->ppCounterList[i]->pRawValues,
216 &statData)) != ERROR_SUCCESS)
217 {
218 ReportPdhError(szFName, _T("PdhComputeCounterStatistics"), rc);
219 }
220
221 // Update mean value in counter set
222 switch(pSet->ppCounterList[i]->wType)
223 {
224 case COUNTER_TYPE_INT32:
225 pSet->ppCounterList[i]->value.iLong = statData.mean.longValue;
226 break;
227 case COUNTER_TYPE_INT64:
228 pSet->ppCounterList[i]->value.iLarge = statData.mean.largeValue;
229 break;
230 case COUNTER_TYPE_FLOAT:
231 pSet->ppCounterList[i]->value.dFloat = statData.mean.doubleValue;
232 break;
233 default:
234 break;
235 }
236 }
237 }
238
239 // Cleanup
240 PdhCloseQuery(hQuery);
241 NxWriteAgentLog(EVENTLOG_INFORMATION_TYPE, "Collector thread for counter set %c terminated", pSet->cClass);
242
243 return 0;
244 }
245
246
247 //
248 // Start collector threads
249 //
250
251 void StartCollectorThreads(void)
252 {
253 int i;
254
255 for(i = 0; i < 3; i++)
256 ThreadCreate((THREAD_RESULT (THREAD_CALL *)(void *))CollectorThread, 0, &m_cntSet[i]);
257 }