source: nscp/trunk/modules/CheckSystem/PDHCollector.cpp @ ed754fe

Last change on this file since ed754fe was ed754fe, checked in by Michael Medin <michael@…>, 5 years ago

2007-12-11 MickeM

+ Added support for index-lookups of PDH counters (hopefully *all* local problems are now fixed (yeah right))

2007-12-10 MickeM

+ Added intial draft for LUA module

  • Property mode set to 100644
File size: 10.1 KB
Line 
1//////////////////////////////////////////////////////////////////////////
2// PDH Collector
3//
4// Functions from this file collects data from the PDH subsystem and stores
5// it for later use
6// *NOTICE* that this is done in a separate thread so threading issues has
7// to be handled. I handle threading issues in the CounterListener's get/
8// set accessors.
9//
10// Copyright (c) 2004 MySolutions NORDIC (http://www.medin.nu)
11//
12// Date: 2004-03-13
13// Author: Michael Medin - <michael@medin.name>
14//
15// This software is provided "AS IS", without a warranty of any kind.
16// You are free to use/modify this code but leave this header intact.
17//
18//////////////////////////////////////////////////////////////////////////
19
20#include "stdafx.h"
21#include "PDHCollector.h"
22#include <Settings.h>
23#include <sysinfo.h>
24
25
26PDHCollector::PDHCollector() : hStopEvent_(NULL) {
27        checkIntervall_ = NSCModuleHelper::getSettingsInt(C_SYSTEM_SECTION_TITLE, C_SYSTEM_CHECK_RESOLUTION, C_SYSTEM_CHECK_RESOLUTION_DEFAULT);
28        std::wstring s = NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_CPU_BUFFER_TIME, C_SYSTEM_CPU_BUFFER_TIME_DEFAULT);
29        unsigned int i = strEx::stoui_as_time(s, checkIntervall_*100);
30        cpu.resize(i/(checkIntervall_*100));
31}
32
33PDHCollector::~PDHCollector()
34{
35        if (hStopEvent_)
36                CloseHandle(hStopEvent_);
37}
38
39/**
40* Thread that collects the data every "CHECK_INTERVAL" seconds.
41*
42* @param lpParameter Not used
43* @return thread exit status
44*
45* @author mickem
46*
47* @date 03-13-2004               
48*
49* @bug If we have "custom named" counters ?
50* @bug This whole concept needs work I think.
51*
52*/
53DWORD PDHCollector::threadProc(LPVOID lpParameter) {
54        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
55        if (!hStopEvent_) {
56                NSC_LOG_ERROR_STD(_T("Create StopEvent failed: ") + error::lookup::last_error());
57                return 0;
58        }
59        PDH::PDHQuery pdh;
60
61
62        if (NSCModuleHelper::getSettingsInt(C_SYSTEM_SECTION_TITLE, C_SYSTEM_AUTODETECT_PDH, C_SYSTEM_AUTODETECT_PDH_DEFAULT) == 1) {
63
64                SettingsT settings;
65                std::wstring prefix;
66                settings.setFile(NSCModuleHelper::getBasePath(),  _T("counters.defs"), true);
67                std::wstring section = NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_FORCE_LANGUAGE, C_SYSTEM_FORCE_LANGUAGE_DEFAULT);
68                bool bUseIndex = false;
69
70                try {
71                        OSVERSIONINFO osVer = systemInfo::getOSVersion();
72                        if (!systemInfo::isNTBased(osVer)) {
73                                NSC_LOG_ERROR_STD(_T("Detected Windows 3.x or Windows 9x, PDH will be disabled."));
74                                NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
75                                return 0;
76                        }
77
78                        LANGID langId = -1;
79                        if (systemInfo::isBelowNT4(osVer)) {
80                                NSC_DEBUG_MSG_STD(_T("Autodetected NT4, using NT4 PDH counters."));
81                                prefix = _T("NT4");
82                                bUseIndex = false;
83                                langId = systemInfo::GetSystemDefaultLangID();
84                        } else if (systemInfo::isAboveW2K(osVer)) {
85                                NSC_DEBUG_MSG_STD(_T("Autodetected w2k or later, using w2k PDH counters."));
86                                bUseIndex = true;
87                                prefix = _T("W2K");
88                                langId = systemInfo::GetSystemDefaultUILanguage();
89                        } else {
90                                NSC_LOG_ERROR_STD(_T("Unknown OS detected, PDH will be disabled."));
91                                NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
92                                return 0;
93                        }
94
95                        if (!section.empty()) {
96                                NSC_DEBUG_MSG_STD(_T("Overriding language with: ") + section);
97                        } else {
98                                section = _T("0000") + strEx::ihextos(langId);
99                                section = _T("0x") + section.substr(section.length()-4);
100                        }
101                        if (settings.getString(section, _T("Description"), _T("_NOT_FOUND")) == _T("_NOT_FOUND")) {
102                                NSC_LOG_ERROR_STD(_T("Detected language: ") + section + _T(" but it could not be found in: counters.defs"));
103                                NSC_LOG_ERROR_STD(_T("You need to manually configure performance counters!"));
104                                return 0;
105                        }
106                        NSC_DEBUG_MSG_STD(_T("Detected language: ") + settings.getString(section, _T("Description"), _T("Not found")) + _T(" (") + section + _T(")"));
107                } catch (const systemInfo::SystemInfoException &e) {
108                        NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
109                        NSC_LOG_ERROR_STD(_T("The Error: ") + e.getError());
110                        return -1;
111                }
112
113                try {
114                        std::wstring proc;
115                        std::wstring uptime;
116                        std::wstring memCl;
117                        std::wstring memCb;
118                        if (bUseIndex) {
119                                NSC_DEBUG_MSG_STD(_T("Using index to retrive counternames"));
120                                proc = _T("\\") + pdh.lookupIndex(238) + _T("(_total)\\") + pdh.lookupIndex(6);
121                                uptime = _T("\\") + pdh.lookupIndex(2) + _T("\\") + pdh.lookupIndex(674);
122                                memCl = _T("\\") + pdh.lookupIndex(4) + _T("\\") + pdh.lookupIndex(30);
123                                memCb = _T("\\") + pdh.lookupIndex(4) + _T("\\") + pdh.lookupIndex(26);
124                        } else {
125                                proc = settings.getString(section, prefix + _T("_") + C_SYSTEM_CPU, C_SYSTEM_MEM_CPU_DEFAULT);
126                                uptime = settings.getString(section, prefix + _T("_") + C_SYSTEM_UPTIME, C_SYSTEM_UPTIME_DEFAULT);
127                                memCl = settings.getString(section, prefix + _T("_") + C_SYSTEM_MEM_PAGE_LIMIT, C_SYSTEM_MEM_PAGE_LIMIT_DEFAULT);
128                                memCb = settings.getString(section, prefix + _T("_") + C_SYSTEM_MEM_PAGE, C_SYSTEM_MEM_PAGE_DEFAULT);
129                        }
130                        NSC_DEBUG_MSG_STD(_T("Found counternames: CPU:    ") + proc);
131                        NSC_DEBUG_MSG_STD(_T("Found counternames: UPTIME: ") + uptime);
132                        NSC_DEBUG_MSG_STD(_T("Found counternames: MCL:    ") + memCl);
133                        NSC_DEBUG_MSG_STD(_T("Found counternames: MCB:    ") + memCb);
134                        pdh.addCounter(proc, &cpu);
135                        pdh.addCounter(uptime, &upTime);
136                        pdh.addCounter(memCl, &memCmtLim);
137                        pdh.addCounter(memCb, &memCmt);
138                        pdh.open();
139                } catch (const PDH::PDHException &e) {
140                        NSC_LOG_ERROR_STD(_T("Failed to open performance counters: ") + e.getError());
141                        pdh.removeAllCounters();
142                        NSC_LOG_ERROR_STD(_T("Trying to use default (English) counters"));
143                        SetThreadLocale(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT));
144                        pdh.addCounter(C_SYSTEM_MEM_PAGE_LIMIT_DEFAULT, &memCmtLim);
145                        pdh.addCounter(C_SYSTEM_MEM_PAGE_DEFAULT, &memCmt);
146                        pdh.addCounter(C_SYSTEM_UPTIME_DEFAULT, &upTime);
147                        pdh.addCounter(C_SYSTEM_MEM_CPU_DEFAULT, &cpu);
148                        try {
149                                pdh.open();
150                        } catch (const PDH::PDHException &e) {
151                                NSC_LOG_ERROR_STD(_T("Failed to open default (English) performance counters: ") + e.getError());
152                                NSC_LOG_ERROR_STD(_T("We will now terminate the collection thread!"));
153                                return 0;
154                        }
155                }
156        } else {
157                pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_MEM_PAGE_LIMIT, C_SYSTEM_MEM_PAGE_LIMIT_DEFAULT), &memCmtLim);
158                pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_MEM_PAGE, C_SYSTEM_MEM_PAGE_DEFAULT), &memCmt);
159                pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_UPTIME, C_SYSTEM_UPTIME_DEFAULT), &upTime);
160                pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_CPU, C_SYSTEM_MEM_CPU_DEFAULT), &cpu);
161
162                try {
163                        pdh.open();
164                } catch (const PDH::PDHException &e) {
165                        NSC_LOG_ERROR_STD(_T("Failed to open performance counters: ") + e.getError());
166                        return 0;
167                }
168        }
169
170        DWORD waitStatus = 0;
171        bool first = true;
172        do {
173                MutexLock mutex(mutexHandler);
174                if (!mutex.hasMutex())
175                        NSC_LOG_ERROR(_T("Failed to get Mutex!"));
176                else {
177                        try {
178                                pdh.gatherData();
179                        } catch (const PDH::PDHException &e) {
180                                if (first) {    // If this is the first run an error will be thrown since the data is not yet avalible
181                                                                // This is "ok" but perhaps another solution would be better, but this works :)
182                                        first = false;
183                                } else {
184                                        NSC_LOG_ERROR_STD(_T("Failed to query performance counters: ") + e.getError());
185                                }
186                        }
187                }
188        } while (((waitStatus = WaitForSingleObject(hStopEvent_, checkIntervall_*100)) == WAIT_TIMEOUT));
189        if (waitStatus != WAIT_OBJECT_0) {
190                NSC_LOG_ERROR(_T("Something odd happened, terminating PDH collection thread!"));
191        }
192
193        {
194                MutexLock mutex(mutexHandler);
195                if (!mutex.hasMutex()) {
196                        NSC_LOG_ERROR(_T("Failed to get Mute when closing thread!"));
197                }
198
199                if (!CloseHandle(hStopEvent_)) {
200                        NSC_LOG_ERROR_STD(_T("Failed to close stopEvent handle: ") + error::lookup::last_error());
201                } else
202                        hStopEvent_ = NULL;
203                try {
204                        pdh.close();
205                } catch (const PDH::PDHException &e) {
206                        NSC_LOG_ERROR_STD(_T("Failed to close performance counters: ") + e.getError());
207                }
208        }
209        return 0;
210}
211
212
213/**
214* Request termination of the thread (waiting for thread termination is not handled)
215*/
216void PDHCollector::exitThread(void) {
217        if (hStopEvent_ == NULL)
218                NSC_LOG_ERROR(_T("Stop event is not created!"));
219        else
220                if (!SetEvent(hStopEvent_)) {
221                        NSC_LOG_ERROR_STD(_T("SetStopEvent failed"));
222                }
223}
224/**
225* Get the average CPU usage for "time"
226* @param time Time to check
227* @return average CPU usage
228*/
229int PDHCollector::getCPUAvrage(std::wstring time) {
230        unsigned int mseconds = strEx::stoui_as_time(time, checkIntervall_*100);
231        MutexLock mutex(mutexHandler);
232        if (!mutex.hasMutex()) {
233                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
234                return -1;
235        }
236        return static_cast<int>(cpu.getAvrage(mseconds / (checkIntervall_*100)));
237}
238/**
239* Get uptime from counter
240* @bug Do we need to collect this all the time ? (perhaps we can collect this in real time ?)
241* @return uptime for the system
242* @bug Are we overflow protected here ? (seem to recall some issues with overflow before ?)
243*/
244long long PDHCollector::getUptime() {
245        MutexLock mutex(mutexHandler);
246        if (!mutex.hasMutex()) {
247                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
248                return -1;
249        }
250        return upTime.getValue();
251}
252/**
253* Memory commit limit (your guess is as good as mine to what this is :)
254* @return Some form of memory check
255*/
256unsigned long long PDHCollector::getMemCommitLimit() {
257        MutexLock mutex(mutexHandler);
258        if (!mutex.hasMutex()) {
259                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
260                return -1;
261        }
262        return memCmtLim.getValue();
263}
264/**
265*
266* Memory committed bytes (your guess is as good as mine to what this is :)
267* @return Some form of memory check
268*/
269unsigned long long PDHCollector::getMemCommit() {
270        MutexLock mutex(mutexHandler);
271        if (!mutex.hasMutex()) {
272                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
273                return -1;
274        }
275        return memCmt.getValue();
276}
Note: See TracBrowser for help on using the repository browser.