Welcome, guest | Sign In | My Account | Store | Cart
import sys
import threading
import ctypes
from ctypes import byref
from ctypes import Structure, Union
from ctypes.wintypes import * 

# other wintype definition
LPVOID = ctypes.c_void_p
LPCVOID = LPVOID
DWORD_PTR = DWORD
LONGLONG = ctypes.c_longlong
HCOUNTER = HQUERY = HANDLE

# error code
Error_Success = 0

# macro
sleep = ctypes.windll.kernel32.Sleep
pdh = ctypes.windll.pdh

# structure definition
class Sysinfo_Struct(Structure):
    _fields_ = [('wProcessorArchitecture', WORD),
                ('wReserved', WORD)]

class Sysinfo_Union(Union):
    _fields_ = [('dwOemId', DWORD),
                ('struct', Sysinfo_Struct)]

class System_Info(Structure):
    _fields_ = [('union', Sysinfo_Union),
                ('dwPageSize', DWORD),
                ('lpMinimumApplicationAddress', LPVOID),
                ('lpMaximumApplicationAddress', LPVOID),
                ('dwActiveProcessorMask', DWORD_PTR),
                ('dwNumberOfProcessors', DWORD),
                ('dwProcessorType', DWORD),
                ('dwAllocationGranularity', DWORD),
                ('wProcessorLevel', WORD),
                ('wProcessorRevision', WORD)]

class PDH_Counter_Union(Union):
    _fields_ = [('longValue', LONG),
                ('doubleValue', ctypes.c_double),
                ('largeValue', LONGLONG),
                ('AnsiStringValue', LPCSTR),
                ('WideStringValue', LPCWSTR)]

class PDH_FMT_COUNTERVALUE(Structure):
    _fields_ = [('CStatus', DWORD),
                ('union', PDH_Counter_Union),]


# Exception definition
class TargetRateExceedError(Exception):
    pass


def getProcessorNumber():
    si = System_Info()
    ctypes.windll.kernel32.GetSystemInfo(byref(si))
    return si.dwNumberOfProcessors

g_cpu_usage = 0
class QueryCPUUsageThread(threading.Thread):
    def __init__(self):
        super(QueryCPUUsageThread, self).__init__()
        self.hQuery = HQUERY()
        self.hCounter = HCOUNTER()
        if not pdh.PdhOpenQueryW(None, 0, byref(self.hQuery)) == Error_Success:
            raise RuntimeError('[QueryCPUUsageThread] Open query failed')
        if not pdh.PdhAddCounterW(self.hQuery,
                                 u'''\\Processor(_Total)\\% Processor Time''',
                                 0,
                                 byref(self.hCounter)) == Error_Success:
            raise RuntimeError('[QueryCPUUsageThread] Add counter failed')
        
    def run(self):
        while True: 
            usage = self.getCPUUsage()
            global g_cpu_usage
            g_cpu_usage = usage
        
    def getCPUUsage(self):
        if not pdh.PdhCollectQueryData(self.hQuery) == Error_Success:
            raise RuntimeError('[QueryCPUUsageThread] CollectQueryData failed')
        ctypes.windll.kernel32.Sleep(1000)
        if not pdh.PdhCollectQueryData(self.hQuery) == Error_Success:
            raise RuntimeError('[QueryCPUUsageThread] CollectQueryData failed')

        dwType = DWORD(0)
        value = PDH_FMT_COUNTERVALUE()
        if not pdh.PdhGetFormattedCounterValue(self.hCounter,
                                          0x00000100, # PDH_FMT_LONG
                                          byref(dwType),
                                          byref(value)) == Error_Success:
            raise RuntimeError('[QueryCPUUsageThread] Get CounterValue failed')

        return value.union.longValue
                             
def main(targetRateForMainProcess, targetRate):
    timeInterval = 50.0
    busyTime = float(targetRateForMainProcess) * timeInterval / 100.0
    idleTime = timeInterval - busyTime
    TOLERANCE = 2
    while True:
        if len(sys.argv)<=1:
            usage = g_cpu_usage
            if abs(usage - targetRate) < TOLERANCE:
                pass
            elif usage > targetRate:
                busyTime = max(busyTime - 0.1, 1)
                idleTime = timeInterval - busyTime
            else:
                busyTime = min(busyTime + 0.1, 49)
                idleTime = timeInterval - busyTime
            #print busyTime, idleTime
        startTime = ctypes.windll.kernel32.GetTickCount()
        while ctypes.windll.kernel32.GetTickCount() - startTime < int(round(busyTime)):
            pass
        sleep(int(round(idleTime)))

def subpMain():
    while True:
        pass

def inputLoop():
    while True:
        print 'please input target cpu usage: ',
        try:
            rate = float(raw_input().strip())
            if rate >= 100 or rate <=1:
                raise TargetRateExceedError
        except TargetRateExceedError:
            print 'please input a number in range 1-99'
        except Exception:
            print 'please input a target cpu usage rate, e.g. 70'
        else:
            return rate    

if __name__=='__main__':
    if len(sys.argv) <= 1:  # main process
        targetRate = inputLoop()
        nProcessor = getProcessorNumber()
        fullPercentPerProcessor = 100.0 / float(nProcessor)
        targetRateForMainProcess = targetRate
        
        while targetRateForMainProcess > fullPercentPerProcessor:
            from subprocess import Popen            
            obj=Popen([sys.executable, __file__, 'child'])
            targetRateForMainProcess -= fullPercentPerProcessor
            
        queryCpuThread = QueryCPUUsageThread()
        queryCpuThread.start()
        main(targetRateForMainProcess, targetRate)
    else: # subprocess
        subpMain()

History

  • revision 3 (15 years ago)
  • previous revisions are not available