mult 和 shift

 Reading notes about mult and shift pairs
Author: Yang Honggang(Joseph) <eagle.rtlinux@gmail.com>
Kernel Version: Linux 3.0.4

===================================================================================================================

关于mult和shift这一对儿值,在内核代码中有X处存在。

clocksource,clock_event_device, timekeeper,cyclecounter, clock_data

下面,我们先了解一下它在clocksource中的应用。

clocks_calc_mult_shift()函数用来根据具体应用参数计算mult 和 shift值。我们从这里开始入手分析。

/* clocks_calc_mult_shift - calculatemult/shift factors for scaled math of clocks

* @mult: pointer to mult variable

* @shift: pointer to shift variable

* @from: frequency to convert from

* @to: frequency to convert to

* @maxsec: guaranteed runtimeconversion range in seconds

* The function evaluates theshift/mult pair for the scaled math

* operations of clocksources andclockevents.

* @to and @from are frequency valuesin HZ. For clock sources @to is

* NSEC_PER_SEC == 1GHz and @from isthe counter frequency. For clock

* event @to is the counter frequencyand @from is NSEC_PER_SEC.

* The @maxsec conversion rangeargument controls the time frame in

* seconds which must be covered by theruntime conversion with the

* calculated mult and shift factors.This guarantees that no 64bit

* overflow happens when the inputvalue of the conversion is

* multiplied with the calculated multfactor. Larger ranges may

* reduce the conversion accuracy bychosing smaller mult and shift factors.

*/

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 whichis limiting the conversion

* range:

*/

tmp = ((u64)maxsec * from) >>32; [1]

while (tmp) { ……[*]

tmp >>=1;

sftacc--;

} [-1]

/*

* Find the conversion shift/multpair which has the best

* accuracy and fits the maxsecconversion range:

*/

for (sft = 32; sft > 0; sft--){[2]

tmp = (u64) to << sft;

tmp += from / 2;

do_div(tmp, from);

if ((tmp >> sftacc) ==0)[3]

break;

}

*mult = tmp;

*shift = sft;

}

在分析这段代码的原理之前,先看如下的关系式。

假设时钟频率为freq,那么时钟周期为1/freq秒,即 1/freq * NSEC_PER_SEC 纳秒。

cyc个时钟的ns数为,

ns = cyc *(NSEC_PER_SEC / freq) ……[a]


实际计算时,由于内核不支持浮点运算,只支持整数的除法运算,会带来很大精度损失,所以对上面式子进行变换,如下

ns = (cyc * ((NSEC_PER_SEC << N)/ freq) >> N ……[b]

mult = (NSEC_PER_SEC << N) / freq

N=shift

那么,

ns = (cyc * mult) >> shift ……[c]


下面开始分析上面代码:

下面分析,基于

clocks_calc_mult_shift(&cs->mult,&cs->shift, freq,

NSEC_PER_SEC, sec);

调用实例。


首先,[1]得到可能使用mult,shift来处理的最大的cyc

解释如下,

由式子[a],

因为maxsec为可以用来使用mult,shift转化的最大的时间范围(单位为:秒),这个是已知的。

有,

maxsec= CYC / freq

可以推出,

CYC= maxsec * freq

所以,我们的结论是[1]处代码的作用是得到可以使用mult,shift来转化的最大的cyc值。

[*]处的while循环用来得到CYC最多可以左移多少位,能够保证不出现64位溢出。

结果保存在sftacc中。//ns = ((cyc << N) * NSEC_PER_SEC/freq) >> N


然后,[2]找到能够得到最好转换精度的mult,shift值对。

shift值,在符合32位整数时,越大越好。

解释如下,

tmp = (to << sft) / from

= (NSEC_PER_SEC << sft) /freq

其实,tmp即为mult

但是,可以有多个mult,shift对,但是只有一对是最佳的。

由式子[c]可以找到转化精度好的标准,

如果, mult>> (sftacc+x), x为大于1的整数,那么,显然,cyc的最大限将会减小,

如果, mult>> (sftacc – x), x 为大于1的整数,那么,显然,cyc在数比较小的情况下,经过

[c]转换的结果将为0,那么会影响转换精度。

所以,好的标准就是,

能够满足(mult>> sftacc == 0)的最大mult定位最终的mult,对应的shift也可以得到。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值