/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: THROTTLE.CPP Abstract: see throttle.h History: 24-Oct-200 ivanbrug created. --*/ #include "precomp.h" #include #include #include #include typedef NTSTATUS (NTAPI * fnNtQuerySystemInformation )( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); fnNtQuerySystemInformation MyNtQuerySystemInformation = NULL; HRESULT POLARITY Throttle(DWORD dwFlags, DWORD IdleMSec, // in MilliSeconds DWORD IoIdleBytePerSec, // in BytesPerSec DWORD SleepLoop, // in MilliSeconds DWORD MaxWait) // in MilliSeconds // // This function will wait until one of this two/three things have happened: // - the system has been idle for at least IdleMSec milliseconds // (no user input within IdleMSec milliseconds) // - the Number of bytes per seconds passed through // the IO system is below a threashold // - the MaxWait time has elapsed // // Reasonable Params are // 3000-5000 millisecond with THROTTLE_USER // 300.000 - 500.000 bytes/second with THROTTLE_IO // 200 - 500 milliseconds for SleepLoop // several minutes for MaxWait // // remarks: // - the function will SUCCEDED(Throttle), no matter // - if the MaxWait has been reached or if the Idle conditions // have been met the function will fail in any other case // - the function is 'precise' within the range if a System Tick // (15ms on professional) // - in the case of an IO throttling, there will always be a Sleep(150) // { // // init static and globals // if (!MyNtQuerySystemInformation) { HMODULE hDll = GetModuleHandleW(L"ntdll.dll"); if (hDll){ MyNtQuerySystemInformation = (fnNtQuerySystemInformation)GetProcAddress(hDll,"NtQuerySystemInformation"); if ( MyNtQuerySystemInformation == NULL ) { return WBEM_E_FAILED; } } else { return WBEM_E_FAILED; } } static DWORD TimeInc = 0; if (!TimeInc) { BOOL bIsValid; DWORD dwAdj; if (!GetSystemTimeAdjustment(&dwAdj,&TimeInc,&bIsValid)) { return WBEM_E_FAILED; } } static DWORD PageSize = 0; if (!PageSize) { SYSTEM_INFO SysInfo; GetSystemInfo(&SysInfo); PageSize = SysInfo.dwPageSize; } // // param validation // if ((dwFlags & ~THROTTLE_ALLOWED_FLAGS) || (0 == SleepLoop)) return WBEM_E_INVALID_PARAMETER; DWORD nTimes = MaxWait/SleepLoop; // user input structures LASTINPUTINFO LInInfo; LInInfo.cbSize = sizeof(LASTINPUTINFO); DWORD i; DWORD Idle100ns = 10000*IdleMSec; // conversion from 1ms to 100ns // io throttling SYSTEM_PERFORMANCE_INFORMATION SPI[2]; BOOL bFirstIOSampleDone = FALSE; DWORD dwWhich = 0; DWORD cbIO = 1+IoIdleBytePerSec; DWORD cbIOOld = 0; // boolean logic BOOL bCnd1 = FALSE; BOOL bCnd2 = FALSE; // registry stuff for wmisvc to force exit from this function HKEY hKey = NULL; LONG lRes; DWORD dwType; DWORD dwLen = sizeof(DWORD); DWORD dwVal; lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, HOME_REG_PATH, 0, KEY_READ, &hKey); if (ERROR_SUCCESS != lRes) return WBEM_E_FAILED; CRegCloseMe cm_(hKey); if (dwFlags & THROTTLE_IO) { NTSTATUS Status; Status = MyNtQuerySystemInformation(SystemPerformanceInformation, &SPI[dwWhich], sizeof(SYSTEM_PERFORMANCE_INFORMATION), 0); if (0 != Status) { return WBEM_E_FAILED; } dwWhich = (dwWhich+1)%2; Sleep(150); } for (i=0;i= Idle100ns) { if (0 == (dwFlags & ~THROTTLE_USER)) { return THROTTLE_USER_IDLE; } else { bCnd1 = TRUE; }; } } // // avoid checking the second condition // if the first is FALSE // if (((dwFlags & (THROTTLE_IO|THROTTLE_USER)) == (THROTTLE_IO|THROTTLE_USER)) && !bCnd1) { goto sleep_label; } // // check the io idleness // if (dwFlags & THROTTLE_IO) { NTSTATUS Status; Status = MyNtQuerySystemInformation(SystemPerformanceInformation, &SPI[dwWhich], sizeof(SYSTEM_PERFORMANCE_INFORMATION), 0); if (0 == Status){ cbIOOld = cbIO; cbIO = (DWORD)((SPI[dwWhich].IoReadTransferCount.QuadPart - SPI[(dwWhich-1)%2].IoReadTransferCount.QuadPart) + (SPI[dwWhich].IoWriteTransferCount.QuadPart - SPI[(dwWhich-1)%2].IoWriteTransferCount.QuadPart) + (SPI[dwWhich].IoOtherTransferCount.QuadPart - SPI[(dwWhich-1)%2].IoOtherTransferCount.QuadPart) + ((SPI[dwWhich].PageReadCount - SPI[(dwWhich-1)%2].PageReadCount) + (SPI[dwWhich].CacheReadCount - SPI[(dwWhich-1)%2].CacheReadCount) + (SPI[dwWhich].DirtyPagesWriteCount - SPI[(dwWhich-1)%2].DirtyPagesWriteCount) + (SPI[dwWhich].MappedPagesWriteCount - SPI[(dwWhich-1)%2].MappedPagesWriteCount)) * PageSize); cbIO = (cbIO * 1000)/SleepLoop; //DBG_PRINTFA((pBuff,"%d - ",cbIO)); cbIO = (cbIOOld+cbIO)/2; dwWhich = (dwWhich+1)%2; //DBG_PRINTFA((pBuff,"%d < %d\n",cbIO,IoIdleBytePerSec)); if (cbIO < IoIdleBytePerSec) { if (0 == (dwFlags & ~THROTTLE_IO)) { return THROTTLE_IO_IDLE; } else { bCnd2 = TRUE; }; } } else { return WBEM_E_FAILED; } } // // check the combined condition // if (dwFlags & (THROTTLE_IO|THROTTLE_USER)) { if (bCnd1 && bCnd2) { return (THROTTLE_IO_IDLE|THROTTLE_USER_IDLE); } else { bCnd1 = FALSE; bCnd2 = FALSE; } } sleep_label: Sleep(SleepLoop); } return THROTTLE_MAX_WAIT; }