diff options
author | Kirill Volinsky <mataes2007@gmail.com> | 2012-07-03 17:21:34 +0000 |
---|---|---|
committer | Kirill Volinsky <mataes2007@gmail.com> | 2012-07-03 17:21:34 +0000 |
commit | 49566229022ee6e96eac0888f9c0501fcd92033b (patch) | |
tree | e042351915fb94e82bae985c7e2c9f122c39abbb /plugins/AutoShutdown/cpuusage.cpp | |
parent | 78f8991554dd09d2e7f7efcdd9dcacf18f75f428 (diff) |
AutoShutdown:
renamed to .cpp
git-svn-id: http://svn.miranda-ng.org/main/trunk@736 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AutoShutdown/cpuusage.cpp')
-rw-r--r-- | plugins/AutoShutdown/cpuusage.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
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;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 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;
+}
|