////////////////////////////////////////////////////////////////////////// // PDH Collector // // Functions from this file collects data from the PDH subsystem and stores // it for later use // *NOTICE* that this is done in a separate thread so threading issues has // to be handled. I handle threading issues in the CounterListener's get/ // set accessors. // // Copyright (c) 2004 MySolutions NORDIC (http://www.medin.nu) // // Date: 2004-03-13 // Author: Michael Medin (mickem@medin.nu) // // This software is provided "AS IS", without a warranty of any kind. // You are free to use/modify this code but leave this header intact. // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "PDHCollector.h" PDHCollector::PDHCollector() : cpu(BACK_INTERVAL*60/CHECK_INTERVAL), hStopEvent_(NULL) { } PDHCollector::~PDHCollector() { if (hStopEvent_) CloseHandle(hStopEvent_); } /** * Thread that collects the data every "CHECK_INTERVAL" seconds. * * @param lpParameter Not used * @return thread exit status * * @author mickem * * @date 03-13-2004 * * @bug As this is now we have to wait for CHECK_INTERVAL seconds before the service terminates (should probably be changed into some form of event) * @bug If we have "custom named" counters ? * @bug This whole concept needs work I think. * */ DWORD PDHCollector::threadProc(LPVOID lpParameter) { PDH::PDHQuery pdh; pdh.addCounter("\\\\.\\Memory\\Commit Limit", &memCmtLim); pdh.addCounter("\\\\.\\Memory\\Committed Bytes", &memCmt); pdh.addCounter("\\\\.\\System\\System Up Time", &upTime); pdh.addCounter("\\\\.\\Processor(_total)\\% Processor Time", &cpu); try { pdh.open(); } catch (const PDH::PDHException &e) { NSC_LOG_ERROR_STD("Failed to open performance counters: " + e.str_); return 0; } hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL); if (!hStopEvent_) { NSC_LOG_ERROR_STD("Create StopEvent failed: " + strEx::itos(GetLastError())); return 0; } do { MutexLock mutex(mutexHandler); if (!mutex.hasMutex()) NSC_LOG_ERROR("Failed to get Mutex!"); else { try { pdh.collect(); } catch (const PDH::PDHException &e) { NSC_LOG_ERROR_STD("Failed to query performance counters: " + e.str_); } } }while (!(WaitForSingleObject(hStopEvent_, CHECK_INTERVAL*1000) == WAIT_OBJECT_0)); if (!CloseHandle(hStopEvent_)) NSC_LOG_ERROR_STD("Failed to close stopEvent handle: " + strEx::itos(GetLastError())); else hStopEvent_ = NULL; try { pdh.close(); } catch (const PDH::PDHException &e) { NSC_LOG_ERROR_STD("Failed to close performance counters: " + e.str_); } return 0; } /** * Request termination of the thread (waiting for thread termination is not handled) */ void PDHCollector::exitThread(void) { if (hStopEvent_ == NULL) NSC_LOG_ERROR("Failed to get Mutex!"); else if (!SetEvent(hStopEvent_)) { NSC_LOG_ERROR_STD("SetStopEvent failed"); } } /** * Get the average CPU usage for "time" * @param backItems * @return average CPU usage */ int PDHCollector::getCPUAvrage(unsigned int backItems) { MutexLock mutex(mutexHandler); if (!mutex.hasMutex()) { NSC_LOG_ERROR("Failed to get Mutex!"); return -1; } return cpu.getAvrage(backItems); } /** * Get uptime from counter * @bug Do we need to collect this all the time ? (perhaps we can collect this in real time ?) * @return uptime for the system * @bug Are we overflow protected here ? (seem to recall some issues with overflow before ?) */ long long PDHCollector::getUptime() { MutexLock mutex(mutexHandler); if (!mutex.hasMutex()) { NSC_LOG_ERROR("Failed to get Mutex!"); return -1; } return upTime.getValue(); } /** * Memory commit limit (your guess is as good as mine to what this is :) * @return Some form of memory check */ long long PDHCollector::getMemCommitLimit() { MutexLock mutex(mutexHandler); if (!mutex.hasMutex()) { NSC_LOG_ERROR("Failed to get Mutex!"); return -1; } return memCmtLim.getValue(); } /** * * Memory committed bytes (your guess is as good as mine to what this is :) * @return Some form of memory check */ long long PDHCollector::getMemCommit() { MutexLock mutex(mutexHandler); if (!mutex.hasMutex()) { NSC_LOG_ERROR("Failed to get Mutex!"); return -1; } return memCmt.getValue(); }