From 49566229022ee6e96eac0888f9c0501fcd92033b Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Tue, 3 Jul 2012 17:21:34 +0000 Subject: AutoShutdown: renamed to .cpp git-svn-id: http://svn.miranda-ng.org/main/trunk@736 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/AutoShutdown/cpuusage.cpp | 257 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 plugins/AutoShutdown/cpuusage.cpp (limited to 'plugins/AutoShutdown/cpuusage.cpp') diff --git a/plugins/AutoShutdown/cpuusage.cpp b/plugins/AutoShutdown/cpuusage.cpp new file mode 100644 index 0000000000..1270fe02ec --- /dev/null +++ b/plugins/AutoShutdown/cpuusage.cpp @@ -0,0 +1,257 @@ +/* + +'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; +} + +#if !defined(_UNICODE) +static void Win9x_PerfStatsSwitch(HKEY hKey,char *pszAction,char *pszName) +{ + DWORD dwData,dwSize; + dwSize=sizeof(dwData); + if(!RegOpenKeyExA(hKey,pszAction,0,KEY_QUERY_VALUE,&hKey)) { + /* a simple query does the trick (data and size must not be NULL!) */ + RegQueryValueExA(hKey,pszName,NULL,NULL,(BYTE*)&dwData,&dwSize); + RegCloseKey(hKey); + } +} +#endif + +/************************* 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(); +} + +#if !defined(_UNICODE) +static void Win9x_PollThread(struct CpuUsageThreadParams *param) +{ + HKEY hKeyStats,hKeyData; + DWORD dwBufferSize,dwData; + + if(!RegOpenKeyExA(HKEY_DYN_DATA,"PerfStats",0,KEY_QUERY_VALUE,&hKeyStats)) { + /* start query */ + /* not needed for kernel + * Win9x_PerfStatsSwitch(hKeyStats,"StartSrv","KERNEL"); */ + Win9x_PerfStatsSwitch(hKeyStats,"StartStat","KERNEL\\CPUUsage"); + /* retrieve cpu usage */ + if(!RegOpenKeyExA(hKeyStats,"StatData",0,KEY_QUERY_VALUE,&hKeyData)) { + dwBufferSize=sizeof(dwData); + while(!RegQueryValueExA(hKeyData,"KERNEL\\CPUUsage",NULL,NULL,(BYTE*)&dwData,&dwBufferSize)) { + dwBufferSize=sizeof(dwData); + if(!CallBackAndWait(param,(BYTE)dwData)) break; + } + RegCloseKey(hKeyData); + } + /* stop query */ + Win9x_PerfStatsSwitch(hKeyStats,"StopStat","KERNEL\\CPUUsage"); + /* not needed for kernel + * Win9x_PerfStatsSwitch(hKeyStats,"StopSrv","KERNEL"); */ + RegCloseKey(hKeyStats); + } + /* return error for PollCpuUsage() if never succeeded */ + if(param->hFirstEvent!=NULL) SetEvent(param->hFirstEvent); + mir_free(param); +} +#endif /* !_UNICODE */ + +static void WinNT_PollThread(struct CpuUsageThreadParams *param) +{ + 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; + } + _itow(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;dwCountNumObjectTypes;++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 defined(_UNICODE) + if(mir_forkthread(WinNT_PollThread,param)!=-1) +#else + if(mir_forkthread(IsWinVerNT()?WinNT_PollThread:Win9x_PollThread,param)!=-1) +#endif + WaitForSingleObject(hFirstEvent,INFINITE); /* wait for first success */ + else mir_free(param); /* thread not started */ + CloseHandle(hFirstEvent); + return idThread; +} -- cgit v1.2.3