首页 > 代码库 > 玩转CPU之直线

玩转CPU之直线

最近在看编程之美,看到第一个问题时,一下子就被吸引了,原来在windows 的任务管理器中还可以让CPU舞动起来,再一次的相信了编程中只有想不到没有做不到,对于书中的做法和网上的实现大致都相同,不过在看后面的解法之前,我的解法和书中第一种简单的控制之法相同,而且我还引入了一个实时监测CPU主频的函数,可以移植到其他的PC上。

#include <windows.h>
#include <iostream>

using namespace std;

int size = 0;

int getCPUFrequency()
{
	static int time[2];              //定义一个整型数组time
	int a = 0;                   //定义整形变量a=0(在后面的运算中用来存商)
	int b = 0;                   //定义整形变量b=0(在后面的运算中用来存余数)

	__asm{ 
		rdtsc                        //RDTSC指令,意思是读取时间标记计数器(Read Time-Stamp Counter)
		mov ecx,offset time            //将time的偏移地址存入ecx
		mov [ecx+0],edx              //把TSC的值的高32位存入[ecx+0]中
		mov [ecx+4],eax              //把TSC的值的低32位存入[ecx+4]中
	}

	Sleep(1000);                  //延时1秒

	__asm{
		rdtsc
		mov ebx,offset time            //将time的偏移地址存入ebx
		sub eax,[ebx+4]               //把延时1秒后的TSC值的高32位减去1秒前的TSC值的高32位
		sbb edx,[ebx+0]               //把延时1秒后的TSC值的低32位减去1秒前的TSC值的低32位
		mov ecx,1000000000
		div ecx                      //将2次TSC差值除以1,000,000,000
		mov a,eax                    //将结果中的商赋值于a
		mov b,edx                   //将结果中的余数赋值于b
	}

    b=b/10000000;                              //取余数中的最高2位

    printf("该机CPU主频是: %d.%dGHz\n",a,b);    //打印结果

	return a*1000+b*10;
}

int main()
{
	size = getCPUFrequency()*2/5*1000000;// 解释第一点
	size -= 100000;//解释第二点
	while(1)
	{
		for(int i=0; i < size; i++)
				;
		Sleep(10);//解释第三点
	}
	return 0;
} 

现在来解释第一点:现代CPU每个时钟周期可以执行两条以上的代码,取平均值就是2。CPU的主频表示1秒执行加法的次数,对于除以5的运算,因为在底层的加法实现中,CPU要进行5次运算才可以进行一次加法运算。

next:
mov eax, dword ptr[i]; 将i 的值放入寄存器
add eax, 1;		寄存器加1
mov dword ptr[i], eax;  寄存器赋值回i
cmp eax, dword ptr[n];  比较i 和 n
jl next;    小于n 则继续执行

解释第二点:上述讨论的情况都是在理想的情况下,就是考虑CPU只执行当前这一个程序。而实际中CPU还会花时间运行其他的程序,所以在运行这个程序时需要将运行的次数适当的减少,至于减少的数量依当前OS的运行进程而定。

解释第三点:至于CPU的睡眠时间,10ms 是接近windows的调度时间片。


现在的电脑很难看到单核的CPU了所以在程序的运行过程中在windows的任务管理器中的进程模块中找到程序的运行号,点击鼠标右键,设置相关性,将此运行的程序用一个CPU核心来运行