您的位置:首页 > 其它

用户决定Windows的CPU占用率

2013-04-15 21:56 288 查看
题目:写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率。程序越精简越好,计算机语言不限。例如,可以实现下面三种情况:

1. CPU的占用率固定在50%,为一条直线;

2. CPU的占用率为一条直线,但是具体占用率由命令行参数决定(参数范围1~ 100);

3. CPU的占用率状态是一个正弦曲线。

控制CPU占用率,不仅仅是出于好玩而已。以前的某些程序,特别是某些老游戏,在新的机器上运行速度太快,必须先给CPU降速,才能顺利运行那些程序,有个共享软件CPUKiller,就是专门弄这个的。
控制CPU占用率,因为要调用Windows的API,要考虑到多核、超线程的情况,要考虑到不同版本的Windows的计时相关的API的精度不同,使问题变得相当复杂,若再考虑其它程序的CPU占用率,则该问题则变得很烦人。(taskmgr调用了一个未公开的API)。
对CPU核数的判断,书上是调用GetProcessorInfo,其实可以直接调用GetSystemInfo,SYSTEM_INFO结构的dwNumberOfProcessors成员就是核数。不知道超线程对这两种方法有什么影响。
如果不考虑其它程序的CPU占用情况,可以在每个核上开一个线程,运行指定的函数,实现每个核的CPU占用率相同。

要让CPU的占用率,呈函数 y = calc(t) (0 <= y <= 1, t为时间,单位为ms )分布,只要取间隔很短的一系列点,认为在某个间隔内,y值近似不变。
设间隔值为GAP,显然在指定t值附近的GAP这段时间内,
CPU占用时间为:busy = GAP * calc(t),
CPU空闲时间为:idle = GAP – busy
因此,很容易写出下面这个通用函数:


void solve(Func *calc)




{


double tb = 0;




while(1) {


unsigned ta = get_time();


double r = calc(tb);


if (r < 0 || r > 1) r = 1;


DWORD busy = r * GAP;




while(get_time() - ta < busy) {}


Sleep(GAP - busy);


tb += GAP;


}


}



如果CPU占用率曲线不是周期性变化,就要对每个t值都要计算一次,否则,可以只计算第一个周期内的各个t值,其它周期的直接取缓存计算结果。

以CPU占用率为正弦曲线为例,显然:y = 0.5 * (1 + sin(a * t + b))

其周期T = 2 * PI / a (PI = 3.1415927),可以指定T值为60s即60000ms,则

可以确定a值为 2 * PI / T, 若在这60000ms内我们计算200次(c = 200),则GAP值为 T / c = 300ms.也就是说,只要确定了周期和计算次数,其它几个参数也都确定下来。

完整代码如下:


#include<windows.h>


#include<cstdio>


#include<cmath>




const int PERIOD = 60 * 1000; //60,000 ms


const int COUNT = 200;




const double PI = 3.1415926535898;


const double GAP = (double)PERIOD / COUNT;


const double FACTOR = 2 * PI / PERIOD;




typedef double Func(double);




inline DWORD get_time() { return GetTickCount(); }






double calc2(double x) { return (1 + sin(FACTOR * x)) / 2;}




double calc3(double)




{


static double cache[COUNT];


static int count = 0;


static bool first = true;




if (first) {


double x = 0.0;


for (int i = 0; i < COUNT; ++i, x += GAP)


cache[i] = (1.0 + sin(FACTOR * x)) / 2.0;


first = false;


}


if (count >= COUNT) count = 0;


return cache[count++];


}






double calc4(double) { return 0.8;}




void solve(Func *calc)




{


double tb = 0;




while(1) {


unsigned ta = get_time();


double r = calc(tb);


if (r < 0 || r > 1) r = 1;


DWORD busy = r * GAP;




while(get_time() - ta < busy) {}


Sleep(GAP - busy);


tb += GAP;


}


}






void run()




{




Func *func[] = { calc2, calc3, calc4 };


Func *calc = func[1];


const int MAX_CPUS = 32;


HANDLE handle[MAX_CPUS];


DWORD thread_id[MAX_CPUS];


SYSTEM_INFO info;


GetSystemInfo(&info);


const int num = info.dwNumberOfProcessors;




for (int i = 0; i < num; ++i) {


if ( (handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,


(VOID*)calc, 0, &thread_id[i])) != NULL)


SetThreadAffinityMask(handle[i], i + 1);


}


WaitForSingleObject(handle[0],INFINITE);


}






int main()




{


run();


}





稍微优化下:


#include<cstdio>


#include<cmath>


#include<windows.h>




const int PERIOD = 60 * 1000; //60,000 ms


const int COUNT = 300;




const double GAP_LINEAR = 100;




const double PI = 3.1415926535898;


const double GAP = (double)PERIOD / COUNT;


const double FACTOR = 2 * PI / PERIOD;






typedef double Func(double);




inline DWORD get_time() { return GetTickCount(); }






double calc_sin(double x) { return (1 + sin(FACTOR * x)) / 2;}




static double Ratio = 0.7;




void set_ratio()




{


double ret = 0.0;


printf("Ratio:([0,1]) ");


scanf("%lf", &ret);


if (ret < 0.0 || ret > 1.0) ret = 0.5;


Ratio = ret;


}




void solve_nonperiod(Func *calc)




{


double tb = 0;




while(1) {


unsigned ta = get_time();


double r = calc(tb);


if (r < 0 || r > 1) r = 1;


DWORD busy = r * GAP;




while(get_time() - ta < busy) {}


Sleep(GAP - busy);


//tb += GAP;


tb += get_time() - ta;


}


}




void solve_period(Func *calc)




{


double x = 0.0;


double cache[COUNT];


for (int i = 0; i < COUNT; ++i, x += GAP)


cache[i] = calc(x);


int count = 0;




while(1) {


unsigned ta = get_time();


if (count >= COUNT) count = 0;


double r = cache[count++];


DWORD busy = r * GAP;




while(get_time() - ta < busy) {}


Sleep(GAP - busy);


}


}




void solve_linear(Func*)




{


const unsigned BUSY = Ratio * GAP_LINEAR;


const unsigned IDLE = (1 - Ratio) * GAP_LINEAR;




while(1) {


unsigned ta = get_time();




while(get_time() - ta < BUSY) {}


Sleep(IDLE);


}


}






void run(unsigned index = 0, double ratio = -1.0)




{


typedef void Solve(Func *calc);




Func *func[] = { calc_sin};


Func *calc = func[0];




Solve *solve_func[] = { solve_linear, solve_period, solve_nonperiod };


if (index >= sizeof(solve_func) / sizeof(solve_func[0])) index = 0;


Solve *solve = solve_func[index];




if (solve == solve_linear) {


if (ratio >= 0 && ratio <= 1) Ratio = ratio;


else set_ratio();


}


const int MAX_CPUS = 32;


HANDLE handle[MAX_CPUS];


DWORD thread_id[MAX_CPUS];


SYSTEM_INFO info;


GetSystemInfo(&info);


const int num = info.dwNumberOfProcessors;




for (int i = 0; i < num; ++i) {


if ((handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,


(VOID*)calc, 0, &thread_id[i])) != NULL)


SetThreadAffinityMask(handle[i], i + 1);


}


WaitForSingleObject(handle[0],INFINITE);


}






int main()




{


run(0, 0.5);


//run(0);


//run(1);


//run(1);


}
源代码信息:
作者: flyinghearts
出处: http://www.cnblogs.com/flyinghearts/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: