summaryrefslogtreecommitdiff
path: root/plugins/AutoShutdown/src/cpuusage.cpp
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-07-05 11:34:19 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-07-05 11:34:19 +0000
commitf4ca33472b18027cdcf38c2569e1efbb116bd2a1 (patch)
tree56060e4103980528a5cf8c3534514988b1f8798a /plugins/AutoShutdown/src/cpuusage.cpp
parent9ee9547340e785ca4eb38294d975d6e1a3a567f2 (diff)
AutoShutdown: folder structure change
git-svn-id: http://svn.miranda-ng.org/main/trunk@767 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AutoShutdown/src/cpuusage.cpp')
-rw-r--r--plugins/AutoShutdown/src/cpuusage.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/plugins/AutoShutdown/src/cpuusage.cpp b/plugins/AutoShutdown/src/cpuusage.cpp
new file mode 100644
index 0000000000..d99be4a6fe
--- /dev/null
+++ b/plugins/AutoShutdown/src/cpuusage.cpp
@@ -0,0 +1,210 @@
+/*
+
+'AutoShutdown'-Plugin for Miranda IM
+
+Copyright 2004-2007 H. Herkenrath
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program (Shutdown-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "common.h"
+
+/************************* Stat Switch ********************************/
+
+#define Li2Double(x) ((double)((x).HighPart)*4.294967296E9+(double)((x).LowPart))
+
+static BOOL WinNT_PerfStatsSwitch(TCHAR *pszServiceName,BOOL fDisable)
+{
+ HKEY hKeyServices,hKeyService,hKeyPerf;
+ DWORD dwData,dwDataSize;
+ BOOL fSwitched=FALSE;
+ /* Win2000+ */
+ if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("System\\CurrentControlSet\\Services"),0,KEY_QUERY_VALUE|KEY_SET_VALUE,&hKeyServices)) {
+ if(!RegOpenKeyEx(hKeyServices,pszServiceName,0,KEY_QUERY_VALUE|KEY_SET_VALUE,&hKeyService)) {
+ if(!RegOpenKeyEx(hKeyService,_T("Performance"),0,KEY_QUERY_VALUE|KEY_SET_VALUE,&hKeyPerf)) {
+ dwDataSize=sizeof(DWORD);
+ if(!RegQueryValueEx(hKeyPerf,_T("Disable Performance Counters"),NULL,NULL,(BYTE*)&dwData,&dwDataSize))
+ if((dwData!=0)!=fDisable)
+ fSwitched=!RegSetValueEx(hKeyPerf,_T("Disable Performance Counters"),0,REG_DWORD,(BYTE*)&fDisable,dwDataSize);
+ RegCloseKey(hKeyPerf);
+ }
+ RegCloseKey(hKeyService);
+ }
+ RegCloseKey(hKeyServices);
+ }
+ return fSwitched;
+}
+
+/************************* Poll Thread ********************************/
+struct CpuUsageThreadParams {
+ DWORD dwDelayMillis;
+ CPUUSAGEAVAILPROC pfnDataAvailProc;
+ LPARAM lParam;
+ HANDLE hFirstEvent;
+ DWORD *pidThread;
+};
+
+static BOOL CallBackAndWait(struct CpuUsageThreadParams *param,BYTE nCpuUsage)
+{
+ if(param->hFirstEvent!=NULL) {
+ /* return value for PollCpuUsage() */
+ *param->pidThread=GetCurrentThreadId();
+ SetEvent(param->hFirstEvent);
+ param->hFirstEvent=NULL;
+ /* lower priority after first call */
+ SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE);
+ }
+ if(!param->pfnDataAvailProc(nCpuUsage,param->lParam)) return FALSE;
+ SleepEx(param->dwDelayMillis,TRUE);
+ return !Miranda_Terminated();
+}
+
+static void WinNT_PollThread(void *vparam)
+{
+ CpuUsageThreadParams *param = (CpuUsageThreadParams*)vparam;
+
+ DWORD dwBufferSize=0,dwCount;
+ BYTE *pBuffer=NULL;
+ PERF_DATA_BLOCK *pPerfData=NULL;
+ LONG res,lCount;
+ PERF_OBJECT_TYPE *pPerfObj;
+ PERF_COUNTER_DEFINITION *pPerfCounter;
+ PERF_INSTANCE_DEFINITION *pPerfInstance;
+ PERF_COUNTER_BLOCK *pPerfCounterBlock;
+ DWORD dwObjectId,dwCounterId;
+ WCHAR wszValueName[11],*pwszInstanceName;
+ BYTE nCpuUsage;
+ BOOL fSwitched,fFound,fIsFirst=FALSE;
+ LARGE_INTEGER liPrevCounterValue={0},liCurrentCounterValue={0},liPrevPerfTime100nSec={0};
+
+ /* init */
+ if(IsWinVer2000Plus()) { /* Win2000+: */
+ dwObjectId=238; /*'Processor' object */
+ dwCounterId=6; /* '% processor time' counter */
+ pwszInstanceName=L"_Total"; /* '_Total' instance */
+ } else { /* WinNT4: */
+ dwObjectId=2; /* 'System' object */
+ dwCounterId=240; /* '% Total processor time' counter */
+ pwszInstanceName=NULL;
+ }
+ _itot_s(dwObjectId, wszValueName, 10);
+ fSwitched = WinNT_PerfStatsSwitch(_T("PerfOS"), FALSE);
+
+ /* poll */
+ for(;;) {
+ /* retrieve data for given object */
+ res=RegQueryValueExW(HKEY_PERFORMANCE_DATA,wszValueName,NULL,NULL,(BYTE*)pPerfData,&dwBufferSize);
+ while(!pBuffer || res==ERROR_MORE_DATA) {
+ pBuffer=(BYTE*)mir_realloc(pPerfData,dwBufferSize+=256);
+ if(!pBuffer) break;
+ pPerfData=(PERF_DATA_BLOCK*)pBuffer;
+ res=RegQueryValueExW(HKEY_PERFORMANCE_DATA,wszValueName,NULL,NULL,pBuffer,&dwBufferSize);
+ }
+ if(res!=ERROR_SUCCESS) break;
+
+ /* find object in data */
+ fFound=FALSE;
+ /* first object */
+ pPerfObj=(PERF_OBJECT_TYPE*)((BYTE*)pPerfData+pPerfData->HeaderLength);
+ for(dwCount=0;dwCount<pPerfData->NumObjectTypes;++dwCount) {
+ if(pPerfObj->ObjectNameTitleIndex==dwObjectId) {
+ /* find counter in object data */
+ /* first counter */
+ pPerfCounter=(PERF_COUNTER_DEFINITION*)((BYTE*)pPerfObj+pPerfObj->HeaderLength);
+ for(dwCount=0;dwCount<(pPerfObj->NumCounters);++dwCount) {
+ if(pPerfCounter->CounterNameTitleIndex==dwCounterId) {
+ /* find instance in counter data */
+ if(pPerfObj->NumInstances==PERF_NO_INSTANCES) {
+ pPerfCounterBlock=(PERF_COUNTER_BLOCK*)((BYTE*)pPerfObj+pPerfObj->DefinitionLength);
+ liCurrentCounterValue=*(LARGE_INTEGER*)((BYTE*)pPerfCounterBlock+pPerfCounter->CounterOffset);
+ fFound=TRUE;
+ }
+ else {
+ /* first instance */
+ pPerfInstance=(PERF_INSTANCE_DEFINITION*)((BYTE*)pPerfObj+pPerfObj->DefinitionLength);
+ for(lCount=0;lCount<(pPerfObj->NumInstances);++lCount) {
+ pPerfCounterBlock=(PERF_COUNTER_BLOCK*)((BYTE*)pPerfInstance+pPerfInstance->ByteLength);
+ if(!lstrcmpiW(pwszInstanceName,(WCHAR*)((BYTE*)pPerfInstance+pPerfInstance->NameOffset)) || !pwszInstanceName) {
+ liCurrentCounterValue=*(LARGE_INTEGER*)((BYTE*)pPerfCounterBlock+pPerfCounter->CounterOffset);
+ fFound=TRUE;
+ break;
+ }
+ /* next instance */
+ pPerfInstance=(PPERF_INSTANCE_DEFINITION)((BYTE*)pPerfCounterBlock+pPerfCounterBlock->ByteLength);
+ }
+ }
+ break;
+ }
+ /* next counter */
+ pPerfCounter=(PERF_COUNTER_DEFINITION*)((BYTE*)pPerfCounter+pPerfCounter->ByteLength);
+ }
+ break;
+ }
+ /* next object */
+ pPerfObj=(PERF_OBJECT_TYPE*)((BYTE*)pPerfObj+pPerfObj->TotalByteLength);
+ }
+ if(!fFound) break;
+
+ /* calc val from data, we need two samplings
+ * counter type: PERF_100NSEC_TIMER_INV
+ * calc: time base=100Ns, value=100*(1-(data_diff)/(100NsTime_diff)) */
+ if(!fIsFirst) {
+ nCpuUsage=(BYTE)((1.0-(Li2Double(liCurrentCounterValue)-Li2Double(liPrevCounterValue))/(Li2Double(pPerfData->PerfTime100nSec)-Li2Double(liPrevPerfTime100nSec)))*100.0+0.5);
+ if(!CallBackAndWait(param,nCpuUsage)) break;
+ }
+ else fIsFirst=FALSE;
+ /* store current sampling for next */
+ CopyMemory(&liPrevCounterValue,&liCurrentCounterValue,sizeof(LARGE_INTEGER));
+ CopyMemory(&liPrevPerfTime100nSec,&pPerfData->PerfTime100nSec,sizeof(LARGE_INTEGER));
+ }
+
+ /* uninit */
+ if(pPerfData) mir_free(pPerfData);
+ if(fSwitched) WinNT_PerfStatsSwitch(_T("PerfOS"),TRUE);
+
+ /* return error for PollCpuUsage() if never succeeded */
+ if(param->hFirstEvent!=NULL) SetEvent(param->hFirstEvent);
+ mir_free(param);
+}
+
+/************************* Start Thread *******************************/
+
+// returns poll thread id on success
+DWORD PollCpuUsage(CPUUSAGEAVAILPROC pfnDataAvailProc,LPARAM lParam,DWORD dwDelayMillis)
+{
+ struct CpuUsageThreadParams *param;
+ DWORD idThread=0;
+ HANDLE hFirstEvent;
+
+ /* init params */
+ param=(struct CpuUsageThreadParams*)mir_alloc(sizeof(struct CpuUsageThreadParams));
+ if(param==NULL) return FALSE;
+ param->dwDelayMillis=dwDelayMillis;
+ param->pfnDataAvailProc=pfnDataAvailProc;
+ param->lParam=lParam;
+ param->pidThread=&idThread;
+ param->hFirstEvent=hFirstEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ if(hFirstEvent==NULL) {
+ mir_free(param);
+ return 0;
+ }
+ /* start thread */
+ if((int)mir_forkthread(WinNT_PollThread, param) != -1)
+ WaitForSingleObject(hFirstEvent,INFINITE); /* wait for first success */
+ else
+ mir_free(param); /* thread not started */
+ CloseHandle(hFirstEvent);
+ return idThread;
+}