[IMX6DL]do_gettimeofday()的精度分析

Platform: IMX6DL
OS: Android 4.4
Kernel branch: 3.0.35


网上有很多不同版本说 do_gettimeofday()精度是ms,有的又说是us,那么正确答案到底是什么呢?
还有,系统的tick只有ms的精度,如果是us精度,那么它又是如何做到的呢?

先看do_gettimeofday()源代码:

do_gettimeofday ->    //timekeeping.c
    getnstimeofday ->
        timekeeping_get_ns    //先获取ns,再转换成us.

static inline s64 timekeeping_get_ns(void)
{
    cycle_t cycle_now, cycle_delta;
    struct clocksource *clock;

    /* read clocksource: */
    clock = timekeeper.clock;
    /*读取当前时间*/
    cycle_now = clock->read(clock);
    /*计算上一次和现在的时间差。*/
    /* calculate the delta since the last update_wall_time: */
    cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;

    /* return delta convert to nanoseconds using ntp adjusted mult. */
    return clocksource_cyc2ns(cycle_delta, timekeeper.mult,
                  timekeeper.shift);
}

timerkeeper是什么?
可以把timerkeeper看成时间的管理者~

timekeeper.clock是什么?
系统有很多种clock,例如jiffies, RTC, OSC等,不同时钟源的精度不一样,
这也就导致最终得到的时间精度不一样,到这里大概知道系统的us以及ns精度是如何来的了,继续往下分析。

timekeeper.clock的初始化在哪里完成的?
开机有:
start_kernel ->    //main.c
    timekeeping_init ->    //timekeeping.c
        clocksource_default_clock ->    //jiffies.c

struct clocksource * __init __weak clocksource_default_clock(void)
{
    return &clocksource_jiffies;
}

struct clocksource clocksource_jiffies = {
    .name        = "jiffies",
    .rating        = 1, /* lowest valid rating*/
    .read        = jiffies_read,
    .mask        = 0xffffffff, /*32bits*/
    .mult        = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
    .shift        = JIFFIES_SHIFT,
};

对应的read()实现就是jiffies_read()了!
static cycle_t jiffies_read(struct clocksource *cs)
{
    return (cycle_t) jiffies;
}

当系统没有其他的clock source可选时,就会使用默认jiffies作为clock source, 所以它的精度只能到ms级。
那么当有更高精度的clock source时如何替换呢,答案如下:
mx6_tek_timer_init ->    //board-mx6-tek.c
    mx6_clocks_init(32768, 24000000, 0, 0); ->    //clock.c 注意第一个参数是RTC,为32.768KHz, 第二个参数是osc,为24MHz.
        oscillator_reference = osc;
        mxc_timer_init(&gpt_clk[0], timer_base, MXC_INT_GPT); ->    //time.c 注意第一个参数,一会会说到
            mxc_clocksource_init ->
                c = clk_get_rate(timer_clk);    //获取对应的clock,如果获取不到,会获取parent对应的clock,依次向上获取。
                clocksource_mmio_init ->
                    clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
                clocksource_mmio_readl_up);     ->    //c为clock,clocksource_mmio_readl_up()为read()函数。
                        clocksource_register_hz
                            __clocksource_register_scale ->
                                clocksource_select ->    //系统可能会同时多个clock source, 找到最佳
                                    timekeeping_notify ->
                                        change_clocksource ->
                                            old = timekeeper.clock;    //这里就会替换原有的clock source,本例是替换jiffies
也就是说timer_clk变量对应的是&gpt_clk[0],对应的parent为osc_clk
static struct clk gpt_clk[] = {
    {
    __INIT_CLK_DEBUG(gpt_clk)
     .parent = &osc_clk,
......
};

static struct clk osc_clk = {
    __INIT_CLK_DEBUG(osc_clk)
    .get_rate = get_oscillator_reference_clock_rate,
};

static unsigned long get_oscillator_reference_clock_rate(struct clk *clk)
{
    return oscillator_reference;
}

而oscillator_reference的值就是osc,为24000000Hz,能达到ns精度 , 也就是说do_gettimeofday()的精度能达到us级了!


24MHz的OSC硬件图如下:



参考:

http://blog.csdn.net/droidphone/article/details/7989566


你可能感兴趣的:(cloc,do_gettimeofday)