Linux内核中一般不使用除法运算,原因在于kernel搞个除法不太方便,应该是效率比较低,涉及到一系列的浮点运算
下面是在学习Linux内核中时间管理时见到的一个算法,特摘出来留个念想......
先贴算法:
void
clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec)
{
u64 tmp;
u32 sft, sftacc= 32;
/*
* Calculate the shift factor which is limiting the conversion
* range:
*/
tmp = ((u64)minsec * from) >> 32;
while (tmp) {
tmp >>=1;
sftacc--;
}
/*
* Find the conversion shift/mult pair which has the best
* accuracy and fits the maxsec conversion range:
*/
for (sft = 32; sft > 0; sft--) {
tmp = (u64) to << sft;
do_div(tmp, from);
if ((tmp >> sftacc) == 0)
break;
}
*mult = tmp;
*shift = sft;
}
精髓是这样的:
将
- times_elapse = cycles_interval / frequency
-
- 转化为:
- times_elapse = cycles_interval * mult >> shift
参数释义:
u32 *mult <span style="white-space:pre"> </span>存放获取到的mult的值
u32 *shift<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">存放获取到的shift的值</span>
u32 from<span style="white-space:pre"> </span>frequency的值
u32 to<span style="white-space:pre"> </span>
u32 minsec
demo:
#include<stdio.h>
#include<stdlib.h>
typedef unsigned int u32;
typedef unsigned long long u64;
#define NSEC_PER_SEC 1000000000L
void
clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
{
u64 tmp;
u32 sft, sftacc= 32;
/*
* * Calculate the shift factor which is limiting the conversion
* * range:
* */
tmp = ((u64)maxsec * from) >> 32;
while (tmp) {
tmp >>=1;
sftacc--;
}
/*
* * Find the conversion shift/mult pair which has the best
* * accuracy and fits the maxsec conversion range:
* */
for (sft = 32; sft > 0; sft--) {
tmp = (u64) to << sft;
tmp += from / 2;
//do_div(tmp, from);
tmp = tmp/from;
if ((tmp >> sftacc) == 0)
break;
}
*mult = tmp;
*shift = sft;
}
int main()
{
u32 tsc_mult;
u32 tsc_shift ;
u32 tsc_frequency = 2127727000/1000; //TSC frequency(KHz)
clocks_calc_mult_shift(&tsc_mult,&tsc_shift,tsc_frequency,NSEC_PER_SEC/1000,600*1000); //NSEC_PER_SEC/1000是因为TSC的注册是clocksource_register_khz
fprintf(stderr,"mult = %d shift = %d\n",tsc_mult,tsc_shift);
return 0;
}
600是根据TSC clocksource的MASK算出来的的入参,感兴趣可以自己推算看下结果:
- mult = 7885042 shift = 24
root@manu:~/code/c/self/time# python
Python 2.7.3 (default, Apr 10 2013, 05:46:21)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> (2127727000*7885042)>>24 - 1000000045L
>>>