分析与解法:

看一个简单代码:


while(true)
{
        if(busy)
               i++;
        else
}

怎么样才能让电脑不做事情呢?

当任务管理器报告cpu使用率为0的时候,谁使用cpu?通过任务管理器可以看到,system idle process占用了cpu空闲的时间,操作系统中指出,当程序在等待用户的输入,或者是等待某些事情的发生,如WaitForSingleObject(),或者主动进入休眠状态(Sleep()),cpu的使用状态就会为0.

在一个刷新周期内(一般为1s),cpu忙的时间和刷新周期总时间的比率,就是cpu的占用率,也就是说,任务管理器中显示的是每个刷新周期内cpu占用率的统计平均值,所以写一个程序,让它在刷新周期内一会儿忙,一会儿闲,调节忙、闲的比例,就可以控制任务管理器显示cpu占用率

解法一:简单解法:

可以用死循环来控制忙的时间,用sleep()让cpu空闲

如何控制循环的时间?由汇编入手:

next:

mov eax,i

add eax,1

mov i,eax

cmp i,n

jl next

所以总共需要5条指令。

查看电脑,cpu的主频是3.2Ghz,所以每秒有3.2*10的9次方个时钟周期,而每个时钟周期可以执行两条以上的代码,假设取两条,那么每秒可以执行1280000000个循环,如果简单的将n设为1280000000,然后Sleep(1000)是绝对不行的,波形很有可能是锯齿状——先到达一个峰值,然后跌到一个很低的占用率,原因是因为在刷新周期内要忙忙,要忙闲,这决定是不行的,如图:

zabbix cpu使用率 不使用平均 cpu使用率0_任务管理器


可以降低两个数量级,在10ms内统计,那么在刷新周期内就是50%的比率了,代码如下:


#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
int main()
{
	int i = 0;
	for(;;)
	{
		for(i = 0;i < 5500000;i++);
		Sleep(10);
	}
	return 0;
}

因为系统有其他程序在运行,不断调整n的取值,发现5500000最合适,结果如图:

zabbix cpu使用率 不使用平均 cpu使用率0_zabbix cpu使用率 不使用平均_02

zabbix cpu使用率 不使用平均 cpu使用率0_刷新周期_03

   

此方法有一个很大的缺点:不能适应机器差异性,一旦换一个cpu,又必须重新计算n取值,解法二能够动态了解cpu的运算能力,然后自动调节忙/闲时间


解法二:使用GetTickCount()和Sleep()

GetTickCount:系统启动到现在所经历时间的毫秒值

代码:


#include<iostream>
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
using namespace std;
const int busyTime = 10;
const int idleTime = busyTime*3;
int startTime = 0;
int main()
{
	while(true)
	{
		int startTime = GetTickCount();
		//busy loop
		while((GetTickCount() - startTime) <= busyTime);
		Sleep(idleTime);
	}
}



     


代码中之所以让idleTime = busyTime*3是因为操作系统中有很多程序会同时执行各种各样的任务,如果其他进程占用了10%的cpu,那么我们的程序只能使用40%的cpu

经过调整,让程序的运行时间少一点,与其他程序的运行时间算在一起,差不多50%的利用率。

zabbix cpu使用率 不使用平均 cpu使用率0_zabbix cpu使用率 不使用平均_04

有没有办法能动态适应?系统监视器,因为要用到c#  跳过 直接看解法4,正弦曲线。


解法四:正弦曲线

代码:


#include<iostream>
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
//正弦函数为150+150*sin(x)
//把正弦曲线0-T之间的弧度分为200分进行抽样,计算每个抽样点的振幅
//然后每隔300ms的时间取下一个抽样点,并让cpu工作振幅所对应的时间

const int SAMPLING_COUNT = 200;
const double PI = 3.1415926535;
const int TOTAL_AMPLITUDE = 400;//每个抽样点对应的时间片 取300*2差不多在一个刷新周期内

int main()
{
	int busySpan[SAMPLING_COUNT];
	int amplitude = TOTAL_AMPLITUDE/2;
	double radian = 0.0;//弧度
	double radianIncrement = 0.01;//弧度增量
	for(int i = 0;i < SAMPLING_COUNT;i++)
	{
		busySpan[i] = amplitude + sin(PI*radian)*amplitude;
		radian += radianIncrement;
		printf("%d\t%d\t",busySpan[i],TOTAL_AMPLITUDE-busySpan[i]);
	}
	int startTime = 0;
	//循环
	for(int j = 0;;j = (j + 1) % SAMPLING_COUNT)
	{
		startTime = GetTickCount();
		while( (GetTickCount() - startTime) <= busySpan[j]);
		Sleep((TOTAL_AMPLITUDE-busySpan[j]));
	}
	return 0;
}



曲线:

zabbix cpu使用率 不使用平均 cpu使用率0_#include_05

讨论: