内核检测CPU的时钟频率
2011-05-10 21:10
253 查看
要想测出CPU的时钟频率,首先得了解TSC的意义,在CPU内部有一个64位的寄存器,每来一个CPU的时钟信号,tsc计数器的值加一,因此可以用以下方法来确认cpu的始终频率:通过计算一定时间内的tsc计数器的增值,可以得出1S钟tsc增值,这个增值就是CPU的时钟频率。下面就
以一个看过的实时hypervisor的获取频率例子来解释:
上述代码获得一个1/x,在下面的代码里面就正式求出cpu始终频率了。
具体的过程已经在上面的代码做了注释,具体的关于LATCH等概念,可以参考我之前写的linux的几种时钟比较,或者可以google或者百度。
以一个看过的实时hypervisor的获取频率例子来解释:
/*假设时钟频率是100HZ,那么一个滴答数就是10ms。*/ #define CALIBRATE_LATCH (5 * LATCH) /*下面会把这个值写入8254的第二个计数器,这时需要50ms计数器的值归零*/ #define CALIBRATE_TIME (5 * 1000020/HZ) /*约等于5000000/1000=5000,也就是5ms*/ static unsigned long calibrate_tsc(void) { /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); /* * Now let's take care of CTC channel 2 * * Set the Gate high, program CTC channel 2 for mode 0, * (interrupt on terminal count mode), binary count, * load 5 * LATCH count, (LSB and MSB) to begin countdown. * * Some devices need a delay here. */ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ { unsigned long startlow, starthigh; unsigned long endlow, endhigh; unsigned long count = 0; rdtsc(startlow,starthigh); do { count++; } while ((inb_p(0x61) & 0x20) == 0); rdtsc(endlow,endhigh); /*上面这段代码是5ms里面tsc增值,因为5ms到时,8254的第二个计数器值归0*/ /* Error: ECTCNEVERSET */ if (count <= 1) goto bad_ctc; /* 64-bit subtract - gcc just messes up with long longs */ __asm__("subl %2,%0/n/t" "sbbl %3,%1" :"=a" (endlow), "=d" (endhigh) :"g" (startlow), "g" (starthigh), "0" (endlow), "1" (endhigh)); /* Error: ECPUTOOFAST */ if (endhigh) goto bad_ctc; /* Error: ECPUTOOSLOW */ if (endlow <= CALIBRATE_TIME) goto bad_ctc; __asm__("divl %2" :"=a" (endlow), "=d" (endhigh) :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME)); /*上面这段汇编是用5ms=5000微秒/tsc增值,得到的endlow代表一个增值耗费微秒数,假设5000/tsc增值=X,则一微秒发生的tsc个数为1/X,那么1秒则为1000000/x,这个就是cpu始终频率*/ return endlow; } /* * The CTC wasn't reliable: we got a hit on the very first read, * or the CPU was so fast/slow that the quotient wouldn't fit in * 32 bits.. */ bad_ctc: return 0; }
上述代码获得一个1/x,在下面的代码里面就正式求出cpu始终频率了。
static int init_tsc (void) { unsigned long tsc_quotient = calibrate_tsc (); unsigned int cpu_khz = get_cpu_khz (tsc_quotient); printk("<XtratuM> Detected %u.%03u MHz processor./n", cpu_khz / 1000, cpu_khz % 1000); hw_hz = cpu_hz = (unsigned long long)cpu_khz * 1000; return 0; } ''''' ''' static unsigned int get_cpu_khz (unsigned long tsc_quotient) { unsigned int cpu_khz; unsigned long eax=0, edx=1000; __asm__("divl %2" :"=a" (cpu_khz), "=d" (edx) :"r" (tsc_quotient), "0" (eax), "1" (edx)); /*上面汇编是求千赫兹,在之前的calibrate_tsc里面得到一微秒发生1/x个tsc增量,calibrate_tsc返回的是x,则知道CPU时钟频率是1000000/x,则1000/x肯定是KHZ了,同理1/x为MHZ了*/ return cpu_khz; }
具体的过程已经在上面的代码做了注释,具体的关于LATCH等概念,可以参考我之前写的linux的几种时钟比较,或者可以google或者百度。
相关文章推荐
- 2.6.11内核CPU频率(khz)的计算
- 时钟频率,最大不会超过3000MHz;字长,可以是32位或64位;核数,可以是单核、双核、或四核;是否支持超线路。各项信息要求使用位域来表示。通过输出sizeof(CPU)来观察该类所占的字节数
- 如何获取 Android 设备的CPU核数、时钟频率以及内存大小
- TX2440 看手册学习2440-CPU时钟频率的设置(ADS1.2编译)
- 为什么CPU时钟频率在过去5年里没有增加?
- Android获取设备CPU核数、时钟频率以及内存大小的方法
- [置顶] C#利用开源库OpenHardwareMonitor获取CPU或显卡温度、使用率、时钟频率
- cpu时钟频率和MIPS
- 如何获取 Android 设备的CPU核数、时钟频率以及内存大小
- CPU的时钟频率
- 编译内核时出现 警告:检测到时钟错误。您的创建可能是不完整的。
- 关于虚拟机中cpu时钟频率的问题
- 如何获取 Android 设备的CPU核数、时钟频率以及内存大小
- AVRStudio 6 设置F_CPU时钟频率
- 如何获取 Android 设备的CPU核数、时钟频率以及内存大小
- TQ2440开发板学习纪实(3)--- 设置时钟频率,让CPU运行的更快
- solaris下查看cpu频率,内存大小等硬件的基本配置
- 如何检测移动端 CPU 以及内存占用率
- 检测您的CPU是否支持RemoteFX(SLAT二级地址转换)
- 简单验证K60内部时钟运行频率 .