CPU利用率问题:操作系统原理和API

问题的提出:写一个程序,使得CPU的占用率可以听从用户的安排,第一种情况,CPU的占用率固定在50%,第二种情况,CPU的占用率为一条直线,具体占用率用参数表示;第三种情况,CPU的占用率状态是一条正弦曲线。

分析:这个问题,不了解操作系统原理和内核代码的人看起来很玄乎。但此问题的本质是操作系统原理,即操作系统如何分配资源给用户程序。进而分析到应用程序级别可得,CPU忙的时间和CPU休眠的时间相等时,根据刷新出来的图像便保持在50%左右。写应用程序,会用到Windows的API。

思路一:根据CPU的主频,计算每秒钟执行的指令条数,将循环用汇编代码表示,求得需要循环执行的次数。并且休眠同样的时间。

核心的API:Sleep()  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
long GetCPUFreq()//获取CPU频率,单位: MHZ
{
     int start1,start2;
     _asm rdtsc
     _asm mov start1,eax
      Sleep(50);
     _asm rdtsc
     _asm mov start2,eax
     return ((start2-start1)/50)/(1024);
}
 
 
//1-1
void SimpleCpu()
{
    while(true)
    {
        //busy
        for(int i=0;i<1181600000;i++)
            ;
        //idle
        Sleep(10);
    }
}//simplecpu

思路二:使用GetTickCount()和Sleep()

使用GetTickCount获得系统启动以来的时间,然后根据需要休眠的时间确定忙循环要做的时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/GetTickCount和Sleep
void GetSleepCpu()
{
    const DWORD busyTime=100;   //10毫秒
    const DWORD idleTime=busyTime; //忙的时间和休眠的时间大致相当
 
    INT64 startTime=0;
    while(true)
    {
        DWORD startTime=GetTickCount();
        //bust loop
        while((GetTickCount()-startTime)<busyTime)
            ;
        //idle loop
        Sleep(idleTime);
    }
}//GetSleepCpu

思路三:正弦曲线问题

把2Pi等分,计算振幅,然后让CPU工作在相应的振幅处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void SineGraph()
{
    SetThreadAffinityMask(GetCurrentThread(), 1);  
    //将0-2Pi之间等分成200份进行抽样,计算每个抽样点的振幅
    //300ms是近似的值 6.28/200
    const int SAMPLINE_COUNT=200;   //抽样点数量
    const double PI=3.1415926535;  
    const int TOTAL_AMPLITUDE=300;  //每个抽样点对应的时间片
 
    DWORD busySpan[SAMPLINE_COUNT];
    int apmlitude=TOTAL_AMPLITUDE; 
    double radian=0.0;
    double radianIncrement=(2.0*PI)/(double)SAMPLINE_COUNT; //增量
 
    //计算每个抽样点的振幅
    for(int i=0;i<SAMPLINE_COUNT;i++)
    {
        busySpan[i]=(DWORD)(apmlitude+(sin(PI*radian)*apmlitude));
        radian+=radianIncrement;
    }
 
    DWORD startTime=0;
    for(int j=0;;j=(j+1)%SAMPLINE_COUNT)
    {
        startTime=GetTickCount();
        while((GetTickCount()-startTime)<=busySpan[j])
            ;
        Sleep(TOTAL_AMPLITUDE-busySpan[j]);
    }
 
}//SineGraph
 
int _tmain(int argc, _TCHAR* argv[])
{
    int c;
    cin>>c;
     
    switch(c)
    {
    case 1:
        SimpleCpu();    //56%
        break;
    case 2:
        GetSleepCpu();  //51% 52%
        break;
    case 3:
        SineGraph();    //正弦曲线
        break;
    }
    return 0;
}

多核CPU的情况下,程序是不一样的写法,此处不讨论。这道题主要考察对操作系统的理解。

posted @ 2019-07-18 18:11  天涯海角路  阅读(348)  评论(0)    收藏  举报