精华内容
下载资源
问答
  • Linux时钟源

    千次阅读 2019-06-18 12:04:47
    查看可用时钟源 cat /sys/devices/system/clocksource/clocksource0/available_clocksource 查看当前使用的时钟源 cat /sys/devices/system/clocksource/clocksource0/current_clocksource 修改时钟源 echo hpet &...

    查看可用时钟源

    cat /sys/devices/system/clocksource/clocksource0/available_clocksource
    

    查看当前使用的时钟源

    cat /sys/devices/system/clocksource/clocksource0/current_clocksource
    

    修改时钟源

    echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource
    

    查看关于时钟源的dmesg日志

    dmesg | grep clock
    

    一般来说tsc时钟源是计算速度最快的选择项,其他都是次选,会导致cpu运行缓慢,导致切换的原因可能是程序bug。
    参考:
    https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/7/html/reference_guide/chap-timestamping

    展开全文
  • linux clk时钟源管理

    2020-12-22 14:17:13
    linux clk时钟源管理 https://www.cnblogs.com/sammei/archive/2012/10/15/3295612.html

    linux clk时钟源管理
    https://www.cnblogs.com/sammei/archive/2012/10/15/3295612.html

    展开全文
  • Linux时间系统:时钟源clocsource

    千次阅读 2017-02-05 12:13:25
    时钟源(clock source)clock source顾名思义就是提供给系统提供时钟的时钟源。 clock source负责读取芯片中按时间增加的值(所谓cycle),并提供给timekeeper,当然也要提供按cycle的值计算时间间隔的内容。 ...

    时钟源(clock source)

    clock source顾名思义就是提供给系统提供时钟的时钟源。
    clock source负责读取芯片中按时间增加的值(所谓cycle),并提供给timekeeper,当然也要提供按cycle的值计算时间间隔的内容。
    clocksource以及timer相关的内容都在kernel/kernel/time目录下面。

    obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
    obj-y += timeconv.o posix-clock.o alarmtimer.o
    
    obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)        += clockevents.o
    obj-$(CONFIG_GENERIC_CLOCKEVENTS)      += tick-common.o
    obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += tick-broadcast.o tick-broadcast-hrtimer.o
    obj-$(CONFIG_GENERIC_SCHED_CLOCK)      += sched_clock.o
    obj-$(CONFIG_TICK_ONESHOT)         += tick-oneshot.o
    obj-$(CONFIG_TICK_ONESHOT)         += tick-sched.o
    obj-$(CONFIG_TIMER_STATS)          += timer_stats.o

    下面来看一下时钟源是怎么注册上去,怎么提供计算时间的内容给timekeeper。

    1. 时钟源注册过程:

    linux可以有很多时钟源,其中一种时钟源是jiffies。还有就是平台相关的时钟源,精度较高。
    当然在注册了很多种时钟源之后,linux内核也用某种方式去选择当前的时钟源来保证最好的精度。
    这里写图片描述

    1)jiffies时钟源注册过程:

    jiffies我们知道就是一秒钟会增加相当于HZ大小的一个变量。
    首先需要根据时钟源,填充clocksource相关数据结构中的成员。

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

    从这个例子,可以看出来 (mult>>shift)*cloclsource->read() 这个读的就是jiffies数。
    当然如果要注册一些更高精度的时钟源,mult和shift要进行小心的计算,以保证其值不会溢出。这个后面再看。

    2. 平台相关的时钟源

    int clocksource_register(struct clocksource *cs)
    {
        /* calculate max adjustment for given mult/shift */
        cs->maxadj = clocksource_max_adjustment(cs); /*计算相当于mult值得11%赋给maxadj*/
        /* calculate max idle time permitted for this clocksource */
        cs->max_idle_ns = clocksource_max_deferment(cs); /*max_idle_ns计算方法看下面*/
        mutex_lock(&clocksource_mutex);
        clocksource_enqueue(cs);  //把注册的clock source 添加到clocksource_list链表中,按rate的降序排序
        clocksource_enqueue_watchdog(cs);
        clocksource_select(); //按rate选择最佳的clocksource,当然这里rate哪个大就选哪
                               个,,
        mutex_unlock(&clocksource_mutex);
        return 0;
    }
    
    
    static u64 clocksource_max_deferment(struct clocksource *cs)
    {
         u64 max_nsecs, max_cycles;
        max_cycles = 1ULL << (63 - (ilog2(cs->mult + cs->maxadj) + 1));
         /* 上面的计算出来就是2的63次方 = max_cycles*(cs->mult + cs->maxadj)  ,也就是说
        这个是在计算2的63次方纳秒对应的cycles,也就是计算最大的cycles,因为时间对应的纳秒不能超
        过2的64次方,因为会溢出
        */
        max_cycles = min_t(u64, max_cycles, (u64) cs->mask); 
    /*max_cycles和cs->mask中的最小值赋值给max_cycles*/
        max_nsecs = clocksource_cyc2ns(max_cycles, cs->mult - cs->maxadj,
                        cs->shift);
    return max_nsecs - (max_nsecs >> 3);
    }
    
    static struct clocksource clocksource_counter = {
    .name   = "arch_sys_counter",
    .rating = 400,
    .read   = arch_counter_read,
    .mask   = CLOCKSOURCE_MASK(56),
    .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
    };
    
    
    static void __init arch_timer_counter_init(void)
    {
        clocksource_register_hz(&clocksource_counter, arch_timer_rate);
        setup_sched_clock(arch_timer_update_sched_clock, 32, arch_timer_rate);
    /* Use the architected timer for the delay loop. */
        arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
        arch_delay_timer.freq = arch_timer_rate;
        register_current_timer_delay(&arch_delay_timer);
    }
    static inline int clocksource_register_hz(struct clocksource *cs, u32 hz)
    {
       return __clocksource_register_scale(cs, 1, hz);
    }
    int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
    {
            /* Initialize mult/shift and max_idle_ns */
        __clocksource_updatefreq_scale(cs, scale, freq); //根据clocksource的频
    
                                率计算mult和shit的值
           /* Add clocksource to the clcoksource list */     
        mutex_lock(&clocksource_mutex);
        clocksource_enqueue(cs);
        clocksource_enqueue_watchdog(cs);
        clocksource_select();
        mutex_unlock(&clocksource_mutex);
            return 0;
    }
    void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq)
    {
        u64 sec;
        sec = (cs->mask - (cs->mask >> 3));
        do_div(sec, freq);
        do_div(sec, scale);
    if (!sec)
            sec = 1;
    else if (sec > 600 && cs->mask > UINT_MAX)
            sec = 600;
        clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
                       NSEC_PER_SEC / scale, sec * scale);
        cs->maxadj = clocksource_max_adjustment(cs);
    while ((cs->mult + cs->maxadj < cs->mult)
    || (cs->mult - cs->maxadj > cs->mult)) {
            cs->mult >>= 1;
            cs->shift--;
            cs->maxadj = clocksource_max_adjustment(cs);
    }
        cs->max_idle_ns = clocksource_max_deferment(cs);
    }
    void
    
    clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
    {
        u64 tmp;
        u32 sft, sftacc= 32;
          tmp = ((u64)maxsec * from) >> 32;
          while (tmp) {
            tmp >>=1;
            sftacc--;
    }
    for (sft = 32; sft > 0; sft--) {
            tmp = (u64) to << sft;
            tmp += from / 2;
            do_div(tmp, from);
    if ((tmp >> sftacc) == 0)
    break;
    }
    *mult = tmp;
    *shift = sft;
    }
    

    kernel用乘法+移位来替换除法:根据cycles来计算过去了多少ns。
    单纯从精度上讲,肯定是mult越大越好,但是计算过程可能溢出,所以mult也不能无限制的大,这个计算中有个magic number 600 :
    这个600的意思是600秒,表示的Timer两次计算当前计数值的差不会超过10分钟。主要考虑的是系统进入IDLE状态之后,时间信息不会被更新,10分钟内只要退出IDLE,clocksource还是可以成功的转换时间。当然了,最后的这个时间不一定就是10分钟,它由clocksource_max_deferment计算并将结果存储在max_idle_ns中
    筒子比较关心的问题是如何计算 ,精度如何,其实我不太喜欢这种计算,Kernel总是因为某些原因把代码写的很蛋疼.反正揣摩代码意图要花不少时间,收益嘛其实也不太大.如何实现我也不解释了,我以TSC为例子我评估下这种mult+shift的精度.

    #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
    >>> 
    我们知道TSC的frequency是2127727000Hz,如果cycle走过2127727000,就意味过去了1秒,或者说10^9(us).按照我们的算法得出的时间是1000000045ns. 这个误差是多大呢,每走10^9秒,误差是45纳秒,换句话说,运行257天,产生1秒的计算误差.考虑到NTP的存在,这个运算精度还可以了.

    3. clocksource watchdog

    clocksource_enqueue_watchdog会将clocksource挂到watchdog链表.watchdog顾名思义,监控所有clocksource:

    #define WATCHDOG_INTERVAL (HZ >> 1)
    #define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)

    如果0.5秒内,误差大于0.0625s,表示这个clocksource精度极差,将rating设成0.

    实际的应用场景

    以高通msm8916为例,除了jiffies,其他clocksource是没有直接使用kernel/kernel/time/clocksource.c文件里边的接口的。
    其他arm_arch_timer.c[/kernel/driver/clocksource/arm_arch_timer.c]
    arch_timer.c [kernel/arch/arm/kernel/arch_timer.c] 两个都是使用
    sched_clock.c[/kernel/kernel/time/sched_clock.c]文件里边的
    sched_clock_register()来进行注册,并使用sched_clock_32()函数读取当前时间。

    展开全文
  • linux 时钟源初步分析

    千次阅读 2010-10-25 20:12:00
    初步概念: 看datasheet的关于时钟与定时器的部分, FCLK供给cpu, HCLK供给AHB总线设备(存储器控制器,中断控制器、LCD控制器、DMA、USB主机控制器等), PCLK供给APB总线上的设备...

    初步概念: 看datasheet的关于时钟与定时器的部分,

    FCLK供给cpu,

    HCLK供给AHB总线设备(存储器控制器,中断控制器、LCD控制器、DMA、USB主机控制器等),

    PCLK供给APB总线上的设备(watchdog、IIS、i2c、 pwm、定时器、ADC、uart、gpio、rtc、spi)

    上电时 fclk的时钟等于外部时钟fin, 然后等待LOCKTIME后, 依照MPLLCON寄存器的设置,倍频到高频。

    UPLLCON专用于USB同于MPLLCON。

     

    关于分频: CLKDIVN寄存器设置fclk、hclk、pclk的分频比。

     

    时钟控制寄存器CLOCK CONTROL REGISTER (CLKCON)

    寄存器的每一位大部分控制一个硬件模块的时钟源,这个功能将被用于内核控制硬件模块的方式,首先内核定义了

    static struct clk init_clocks[] = {
    {
      .name  = "dma",
      .id  = 0,
      .parent  = &clk_h,
      .enable  = s3c2412_clkcon_enable,
      .ctrlbit = S3C2412_CLKCON_DMA0,
     }, {
      .name  = "dma",
      .id  = 1,
      .parent  = &clk_h,
      .enable  = s3c2412_clkcon_enable,
      .ctrlbit = S3C2412_CLKCON_DMA1,
     },

    ......

    ......

    { .name    = "adc",
          .id       = -1,
          .parent  = &clk_p,
          .enable  = s3c24xx_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_ADC
        },

     

    }(其中的每一项为clock结构体)

    结构体,其中ctrlbit对应于CLKCON的每一位, 其中每一项的编号是通过 name来识别, 操作函数都为s3c24xx_clkcon_enable, 其中parent项表示该模块的时钟来源。

    在内核里面有时候我们需要自己手动的开启硬件模块,方法如下:

     static struct clk *adc_clock;
    定义一个clock时钟,这个结构体代表一个时钟的抽象。

    adc_clock = clk_get(NULL, "adc");
     if (!adc_clock) {
      printk(KERN_ERR "failed to get adc clock source/n");
      return -ENOENT;
     }

    获取相应模块所对应的clock结构体(存于static struct clk init_clocks中), clk_get函数是通过 name去 init_clocks结构体中遍历找到相应的clock,进而获得了硬件模块相应的clock结构体。

     clk_enable(adc_clock);
    使能clock,即使能CLKCON中硬件模块相对应的位,从而实现了硬件模块的时钟源使能。clk_enable函数使用递归方式使能相应的CLKCON位,这个意思也就是说这个函数调用同时也会将这个时钟源的上一级时钟源同样使能,一直往上推保证这条时钟线ok,这个是主要的意思,具体涉及到上级时钟源的设置还需要另外的机制控制,可以参照源码分析。

    展开全文
  • clock source用于为linux内核提供一个时间基线,如果你用linux的date命令获取当前...时钟源是内核计时的基础,系统启动时,内核通过硬件RTC获得当前时间,在这以后,在大多数情况下,内核通过选定的时钟源更新实时时
  • Linux-C时钟传送程序代码,程序中有发送端和接收端,实现不同主机时钟传送
  • yum -y install chronyd vi /etc/chrony.conf : ...systemctl enable chronyd.service ...查看时间同步: chronyc sources -v 立即手工同步 chronyc -a makestep   查看时间同步状态: chronyc sourcestats -v   设
  • Linux内核时间管理子系统——时钟源

    千次阅读 2014-08-27 22:17:13
    Linux内核中有两种不同的clock设备,一种是clock source设备,另一种是clock event设备。
  • 设置HPET为当前时钟源 echo 'tsc' > /sys/devices/system/clocksource/clocksource0/current_clocksource   查看timer信息: cat /proc/timer_list 转载于:https://blog.51cto.com/singler/1919188
  • 为了解决kvm虚拟机内部分软件计时不准确的问题,准备使用kvm-clock时钟源,但是几台redhat系统的服务器都未支持kvmclock时钟源。请有了解这部分知识的人讲解一下,谢谢
  • linux系统时钟

    2015-04-06 16:19:56
    硬件上,一个soc上面有:时钟源、定时器。时钟源用于产生不同频率的clock,用于不同的模块,比如ahb和apb总线的频率不同;以及用于不同的cpu模式下,比如低功耗模式下的clock的频率更低。定时器是时钟clock作为输入...
  • $ dmesg | grep clock [0.000000] OMAP clocksource: GPTIMER1 at 24000000 Hz [0.000000] sched_clock: 32 bits at 24MHz, resolution 41ns,wraps every 178956ms 这里的精度是41ns ...
  • Linux内核代码导读-陈香兰-中国科学技术大学-时钟和定时测量

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,059
精华内容 14,423
关键字:

时钟源linux

linux 订阅