欢迎来到天天文库
浏览记录
ID:39497448
大小:44.00 KB
页数:5页
时间:2019-07-04
《教你玩转CPU——控制CPU占用率曲线》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、教你玩转CPU----随心所欲控制CPU占用率曲线走向我想大家都知道电脑的任务管理器里面有个CPU占用率曲线吧,他根据系统使用资源的不同实时显示,那能不能使这个曲线按照自己的思想显示呢,如使他一直保持一个固定的值,如50%,或者正弦曲线,听起来好像很难,但如果是让你用C、C++或java等语言写一个最简短的程序,你会不会觉得更难呢,不错,这曾经是微软亚洲研究院(MicrosoftResearchAsia,MSRA)的一道面试题,据说这道题就淘汰了当批接受面试的85%的人,他的原题如下:1、CPU的占用率固定为50%,为一条直线;2、
2、CPU的占用率为一条直线,但是具体占用率由命令行参数决定(参数范围1~100);3、CPU的占用率状态是一个正弦曲线。看来这并不是不可能完成的任务。然我们仔细回想一下写程序时曾经碰到的问题,如果我们不小心写了一个死循环,CPU占用率就会跳到最高,并且一直保持100%。我们也可以打开任务管理器,实际观测一下它是怎样变动的。凭肉眼观察,它大约是每一秒钟更新一次。一般情况下,CPU的占用率很低。但是当用户运行一个程序时,执行一些复杂的操作时,CPU的使用率会急剧增加。当用户鼠标晃动时,CPU的使用率也会有小幅度的变化。那么当任务管理器报告
3、CPU的使用率为0的时候,谁在使用CPU呢?通过任务管理器的“进程(Process)”一栏可以看到,SystemIdleProcess占用了CPU空闲的时间----这时候大家该回忆起在“操作系统原理”这门课上学到的一些知识了吧。系统中有那么多的进程,他们什么时候能“闲下来”呢?答案很简单,这些程序在等待用户的输入,或者在等待某些事件的发生,或者主动进入休眠状态。在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率,也就是说,任务管理器显示的是每个刷新周期内CPU占用率的统计平均值。因
4、此,我们写了一个程序,让他在任务管理器的刷新期内一会儿忙,一会儿闲,然后通过调节忙闲比例,就可以控制任务管理器中显示的CPU占用率。要操纵CPU的使用率曲线,就需要使CPU在一段时间内(更具TaskManager的采样率)跑busy和idle两个不同的循环(loop),从而通过不同的时间比例,来调节CPU使用率。busyloop可以通过执行空循环来实现,idle可以通过Sleep()实现。问题的关键在于如何控制两个loop时间,我们先实验一下Sleep一段时间,然后循环n次,估算n的值。那么对于一个空循环for(i=0;i5、++);又该如何来估算这个最合适的n值呢?我们都知道CPU执行的是机器指令,而最接近机器指令的语言是汇编语言,所以我们可以先把这个空循环简单的写成如下汇编代码后再进行分析:loop:movdxi;将i置入dx寄存器incdx;将dx寄存器加1movidx;将dx中的值赋回icmpin;比较i和nj1loop;1小于n时则重复循环假设这段代码要运行的CPU是P42.4GHz(2.4*10的9次方个时钟周期每秒)。现代CPU每个时钟周期可以执行两条以上的代码,呢么我们就取平均值两条,于是让(2400000000*2)/5=96000006、00(循环/秒),也就是说CPU1秒钟可以运行这个空循环960000000次。不过我们还是不能简单的将n=960000000,然后Sleep(1000)了事。如果我们让CPU工作1秒钟,然后休息1秒钟,波形很可能就是锯齿状的----先达到一个峰值(>50%),然后跌倒一个很低的占用率。我们尝试降低两个数量级,令n=9600000而睡眠时间相应改为10毫秒(Sleep(10))。用10毫秒是因为它不大也不小,比较接近Windows的调度时间片。如果选得太小(比如1毫秒),则会造成线程频繁的被唤醒和挂起,无形中友增加了内核时间的不确定性7、影响。最后我们得到如下代码:intmain(){for(;;){for(inti=0;i<9600000;i++);Sleep(10);}return0;}在VC中用Sleep前面要加上#include"windows.h",在不断调整9600000的参数后,我们就可以在一台指定的机器上获得一条大致稳定50%CPU占用率曲线使用这种方法要注意两点影响:1、尽量减少sleep/awake的频率,减少操作系统内核调度程序的干扰。2、尽量不要调用systemcall(比如I/O这些privilegeinstruction),因为它也会导致8、很多不可控的内核运行时间。3、上面的程序是针对单核CPU的,如果是多核CPU,那么CPU占用率曲线有好几个,如果自定义指定哪个或哪几个显示呢,可以在for(;;)前面加上SetProcessAffinityMask()函数,BOOLS
5、++);又该如何来估算这个最合适的n值呢?我们都知道CPU执行的是机器指令,而最接近机器指令的语言是汇编语言,所以我们可以先把这个空循环简单的写成如下汇编代码后再进行分析:loop:movdxi;将i置入dx寄存器incdx;将dx寄存器加1movidx;将dx中的值赋回icmpin;比较i和nj1loop;1小于n时则重复循环假设这段代码要运行的CPU是P42.4GHz(2.4*10的9次方个时钟周期每秒)。现代CPU每个时钟周期可以执行两条以上的代码,呢么我们就取平均值两条,于是让(2400000000*2)/5=9600000
6、00(循环/秒),也就是说CPU1秒钟可以运行这个空循环960000000次。不过我们还是不能简单的将n=960000000,然后Sleep(1000)了事。如果我们让CPU工作1秒钟,然后休息1秒钟,波形很可能就是锯齿状的----先达到一个峰值(>50%),然后跌倒一个很低的占用率。我们尝试降低两个数量级,令n=9600000而睡眠时间相应改为10毫秒(Sleep(10))。用10毫秒是因为它不大也不小,比较接近Windows的调度时间片。如果选得太小(比如1毫秒),则会造成线程频繁的被唤醒和挂起,无形中友增加了内核时间的不确定性
7、影响。最后我们得到如下代码:intmain(){for(;;){for(inti=0;i<9600000;i++);Sleep(10);}return0;}在VC中用Sleep前面要加上#include"windows.h",在不断调整9600000的参数后,我们就可以在一台指定的机器上获得一条大致稳定50%CPU占用率曲线使用这种方法要注意两点影响:1、尽量减少sleep/awake的频率,减少操作系统内核调度程序的干扰。2、尽量不要调用systemcall(比如I/O这些privilegeinstruction),因为它也会导致
8、很多不可控的内核运行时间。3、上面的程序是针对单核CPU的,如果是多核CPU,那么CPU占用率曲线有好几个,如果自定义指定哪个或哪几个显示呢,可以在for(;;)前面加上SetProcessAffinityMask()函数,BOOLS
此文档下载收益归作者所有