免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8757 | 回复: 4
打印 上一主题 下一主题

不同系统执行上clock_getres为什么有如此大的差异 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-06 08:54 |只看该作者 |倒序浏览
10可用积分
[root@localhost ttimer]# cat time.c
#include <stdio.h>  
#include <time.h>  
   
int main()  
{  
     clockid_t clocks[]= {  
          CLOCK_REALTIME,  
         CLOCK_MONOTONIC,  
          CLOCK_PROCESS_CPUTIME_ID,  
          CLOCK_THREAD_CPUTIME_ID,  
         (clockid_t) -1,  
      };  
   
      int i;  
      for(i=0;clocks != (clockid_t) -1;i++)  
     {  
         struct timespec res;  
         int ret;  
         ret = clock_getres(clocks,&res);  
         if(ret)  
             perror("clock_getres");  
         else  
             printf("clock = [%d],sec = [%ld],nsec = [%ld]\n",clocks,res.tv_sec,res.tv_nsec);  
     }  
     return 1;  
}  
同样的代码,在不同的系统上执行结果完全不同:
我的pc机:
Linux localhost.localdomain 2.6.29.4-167.fc11.i686.PAE #1 SMP Wed May 27 17:28:22 EDT 2009 i686 i686 i386 GNU/Linux
执行结果:
clock = [0],sec = [0],nsec = [1]
clock = [1],sec = [0],nsec = [1]
clock = [2],sec = [0],nsec = [1]
clock = [3],sec = [0],nsec = [1]
我的开发版上的系统:
2.6.25.8-rt7 #133 PREEMPT RT Thu Nov 5 22:44:34 CST 2009 armv4tl unknown
执行结果:
/var/other1> ./time
clock = [0],sec = [0],nsec = [1250000]
clock = [1],sec = [0],nsec = [1250000]
clock = [2],sec = [0],nsec = [1]
clock   [3],sec = [0],nsec = [1]
看起来,好像在我的开发版上的执行结果比较合理,CLOCK_REALTIME描述的是我系统时钟周期的间隔,但在pc机上的执行结果是什么意思呢?
还有这跟我的系统硬件有关系么?
请大家多多指教哈

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
2 [报告]
发表于 2009-11-06 13:51 |只看该作者

回复 #1 jinxinxin163 的帖子

问一下LZ执行上面的程序要用到什么库吗?
我想试一下,可是系统说没有找到clock_getres

另搜了一篇说明,不知道有没有用:
http://www.opengroup.org/onlinep ... /clock_gettime.html

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
3 [报告]
发表于 2009-11-06 14:04 |只看该作者

回复 #1 jinxinxin163 的帖子

我似乎要将代码改一下才能运行:

  1. #include <stdio.h>  
  2. #include <time.h>  
  3.    
  4. int main()  
  5. {  
  6.         clockid_t clocks[]= {  
  7.                         CLOCK_REALTIME,  
  8.                         CLOCK_MONOTONIC,  
  9.                         CLOCK_PROCESS_CPUTIME_ID,  
  10.                         CLOCK_THREAD_CPUTIME_ID,  
  11.                         (clockid_t) -1,  
  12.         };  
  13.    
  14.         int i;  
  15.         for(i = 0; clocks[i] != (clockid_t) -1; i++) {  
  16.                 struct timespec res;  
  17.                 int ret;  
  18.                 ret = clock_getres(clocks[i], &res);  
  19.                 if (ret)  
  20.                         perror("clock_getres");  
  21.                 else
  22.                         printf("clock = [%d],sec = [%ld],nsec = [%ld]\n",
  23.                                         i, res.tv_sec, res.tv_nsec);  
  24.         }  
  25.      
  26.         return 0;  
  27. }  
复制代码


我跑了一下, PC机上跟LZ类似
结果如下:

  1. **********:~$ gcc -lrt time.c -o time
  2. **********:~$ ./time
  3. clock = [0],sec = [0],nsec = [1]
  4. clock = [1],sec = [0],nsec = [1]
  5. clock = [2],sec = [0],nsec = [1]
  6. clock = [3],sec = [0],nsec = [1]
  7. **********:~$ uname -a
  8. Linux openspace 2.6.26-1-686 #1 SMP Sat Jan 10 18:29:31 UTC 2009 i686 GNU/Linux

复制代码

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
4 [报告]
发表于 2009-11-06 14:47 |只看该作者
http://www.javaeye.com/topic/309744
这样看PC系统时钟频率为1GHz

PS:刚从lxr.linux.no上搜了一下
       sys_clock_getres到2.6.28内核中还有定义,在kernel/posix-timers.c
       从2.6.28.1开始就找不到定义了
       具体在哪也找不到,严重怀疑只剩一个空壳了,所以返回都是1
       要不LZ装个早版本的内核,试试PC上的运行情况

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
5 [报告]
发表于 2009-11-06 16:18 |只看该作者
刚看了一下,简单理清了思路,希望对LZ有用

让我们先来看一下clock_getres的实现

  1. 2.6.31/kernel/posix-timers.c

  2. 这里有两种方式,一直是common_clock_getres,直接访问posix_clocks[which_clock].res;另一种是使用
  3. 939行定义的函数,其间接调用了posix_clocks[clock].clock_getres

  4. ……
  5. 134static struct k_clock posix_clocks[MAX_CLOCKS];
  6. ……
  7. 158#define CLOCK_DISPATCH(clock, call, arglist) \
  8. 159        ((clock) < 0 ? posix_cpu_##call arglist : \
  9. 160         (posix_clocks[clock].call != NULL \
  10. 161          ? (*posix_clocks[clock].call) arglist : common_##call arglist))
  11. ……
  12. 171static inline int common_clock_getres(const clockid_t which_clock,
  13. 172                                      struct timespec *tp)
  14. 173{
  15. 174        tp->tv_sec = 0;
  16. 175        tp->tv_nsec = posix_clocks[which_clock].res;
  17. 176        return 0;
  18. 177}
  19. ……
  20. 939SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
  21. 940                struct timespec __user *, tp)
  22. 941{
  23. 942        struct timespec rtn_tp;
  24. 943        int error;
  25. 944
  26. 945        if (invalid_clockid(which_clock))
  27. 946                return -EINVAL;
  28. 947
  29. 948        error = CLOCK_DISPATCH(which_clock, clock_getres,
  30. 949                               (which_clock, &rtn_tp));
  31. 950
  32. 951        if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) {
  33. 952                error = -EFAULT;
  34. 953        }
  35. 954
  36. 955        return error;
  37. 956}
复制代码


走到这里,目标都集中到posix_clocks上。来看一下posix_clocks的定义

  1. 2.6.31/kernel/posix-timers.c

  2. 134static struct k_clock posix_clocks[MAX_CLOCKS];
  3.   
  4. 2.6.31/include/linux/posix-timers.h

  5.   69struct k_clock {
  6.   70        int res;                /* in nanoseconds */
  7.   71        int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
  8.   72        int (*clock_set) (const clockid_t which_clock, struct timespec * tp);
  9.   73        int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
  10.   74        int (*timer_create) (struct k_itimer *timer);
  11.   75        int (*nsleep) (const clockid_t which_clock, int flags,
  12.   76                       struct timespec *, struct timespec __user *);
  13.   77        long (*nsleep_restart) (struct restart_block *restart_block);
  14.   78        int (*timer_set) (struct k_itimer * timr, int flags,
  15.   79                          struct itimerspec * new_setting,
  16.   80                          struct itimerspec * old_setting);
  17.   81        int (*timer_del) (struct k_itimer * timr);
  18.   82#define TIMER_RETRY 1
  19.   83        void (*timer_get) (struct k_itimer * timr,
  20.   84                           struct itimerspec * cur_setting);
  21.   85};
复制代码


接下来我们看一下posix_clocks的初始化

  1. 2.6.31/kernel/posix-timers.c

  2. 245/*
  3. 246 * Initialize everything, well, just everything in Posix clocks/timers ;)
  4. 247 */
  5. 248static __init int init_posix_timers(void)
  6. 249{
  7. 250        struct k_clock clock_realtime = {
  8. 251                .clock_getres = hrtimer_get_res,
  9. 252        };
  10. 253        struct k_clock clock_monotonic = {
  11. 254                .clock_getres = hrtimer_get_res,
  12. 255                .clock_get = posix_ktime_get_ts,
  13. 256                .clock_set = do_posix_clock_nosettime,
  14. 257        };
  15. 258        struct k_clock clock_monotonic_raw = {
  16. 259                .clock_getres = hrtimer_get_res,
  17. 260                .clock_get = posix_get_monotonic_raw,
  18. 261                .clock_set = do_posix_clock_nosettime,
  19. 262                .timer_create = no_timer_create,
  20. 263                .nsleep = no_nsleep,
  21. 264        };
  22. 265
  23. 266        register_posix_clock(CLOCK_REALTIME, &clock_realtime);
  24. 267        register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
  25. 268        register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
  26. 269
  27. 270        posix_timers_cache = kmem_cache_create("posix_timers_cache",
  28. 271                                        sizeof (struct k_itimer), 0, SLAB_PANIC,
  29. 272                                        NULL);
  30. 273        idr_init(&posix_timers_id);
  31. 274        return 0;
  32. 275}
  33. 276
  34. 277__initcall(init_posix_timers);
复制代码

看到CLOCK_REALTIME和CLOCK_MONOTONIC了没,是不是感觉很熟悉。可以看到,要获取精度,都会调用hrtimer_get_res,这 就可以解释为什么CLOCK_REALTIME和CLOCK_MONOTONIC的输出相同了

我们跟踪一下hrtimer_get_res的实现

  1. 2.6.31/kernel/hrtimer.c

  2. 1189int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
  3. 1190{
  4. 1191        struct hrtimer_cpu_base *cpu_base;
  5. 1192
  6. 1193        cpu_base = &__raw_get_cpu_var(hrtimer_bases);
  7. 1194        *tp = ktime_to_timespec(cpu_base->clock_base[which_clock].resolution);
  8. 1195
  9. 1196        return 0;
  10. 1197}
  11. 1198EXPORT_SYMBOL_GPL(hrtimer_get_res);
复制代码


目标成了hrtimer_bases和hrtimer_cpu_base了,这里可以猜出hrtimer_bases是一个Per CPU变量,用于记录每个CPU的
hrtimer_cpu_base,这里先关注hrtimer_cpu_base

  1. 2.6.31/include/linux/hrtimer.h

  2. 172struct hrtimer_cpu_base {
  3. 173        spinlock_t                      lock;
  4. 174        struct hrtimer_clock_base       clock_base[HRTIMER_MAX_CLOCK_BASES];
  5. 175#ifdef CONFIG_HIGH_RES_TIMERS
  6. 176        ktime_t                         expires_next;
  7. 177        int                             hres_active;
  8. 178        unsigned long                   nr_events;
  9. 179#endif
  10. 180};
复制代码


目标转为hrtimer_cpu_base,看看它如何设置clock_base。先看一下struct hrtimer_clock_base的定义

  1. 2.6.31/include/linux/hrtimer.h

  2. 131/**
  3. 132 * struct hrtimer_clock_base - the timer base for a specific clock
  4. 133 * @cpu_base:           per cpu clock base
  5. 134 * @index:              clock type index for per_cpu support when moving a
  6. 135 *                      timer to a base on another cpu.
  7. 136 * @active:             red black tree root node for the active timers
  8. 137 * @first:              pointer to the timer node which expires first
  9. 138 * @resolution:         the resolution of the clock, in nanoseconds
  10. 139 * @get_time:           function to retrieve the current time of the clock
  11. 140 * @softirq_time:       the time when running the hrtimer queue in the softirq
  12. 141 * @offset:             offset of this clock to the monotonic base
  13. 142 */
  14. 143struct hrtimer_clock_base {
  15. 144        struct hrtimer_cpu_base *cpu_base;
  16. 145        clockid_t               index;
  17. 146        struct rb_root          active;
  18. 147        struct rb_node          *first;
  19. 148        ktime_t                 resolution;
  20. 149        ktime_t                 (*get_time)(void);
  21. 150        ktime_t                 softirq_time;
  22. 151#ifdef CONFIG_HIGH_RES_TIMERS
  23. 152        ktime_t                 offset;
  24. 153#endif
  25. 154};
复制代码


看来最后的目标是查看hrtimer_clock_base的设置和初始化化了

  1.   91DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
  2.   92{
  3.   93
  4.   94        .clock_base =
  5.   95        {
  6.   96                {
  7.   97                        .index = CLOCK_REALTIME,
  8.   98                        .get_time = &ktime_get_real,
  9.   99                        .resolution = KTIME_LOW_RES,
  10. 100                },
  11. 101                {
  12. 102                        .index = CLOCK_MONOTONIC,
  13. 103                        .get_time = &ktime_get,
  14. 104                        .resolution = KTIME_LOW_RES,
  15. 105                },
  16. 106        }
  17. 107};
复制代码

跟踪一下KTIME_LOW_RES的定义

  1. 2.6.31/include/linux/ktime.h

  2. 321#define LOW_RES_NSEC            TICK_NSEC
  3. 322#define KTIME_LOW_RES           (ktime_t){ .tv64 = LOW_RES_NSEC }

  4.   2.6.31/include/linux/jiffies.h
  5.   42/* LATCH is used in the interval timer and ftape setup. */
  6.   43#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)  /* For divider */
  7.   44
  8.   45/* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, then we can
  9.   46 * improve accuracy by shifting LSH bits, hence calculating:
  10.   47 *     (NOM << LSH) / DEN
  11.   48 * This however means trouble for large NOM, because (NOM << LSH) may no
  12.   49 * longer fit in 32 bits. The following way of calculating this gives us
  13.   50 * some slack, under the following conditions:
  14.   51 *   - (NOM / DEN) fits in (32 - LSH) bits.
  15.   52 *   - (NOM % DEN) fits in (32 - LSH) bits.
  16.   53 */
  17.   54#define SH_DIV(NOM,DEN,LSH) (   (((NOM) / (DEN)) << (LSH))              \
  18.   55                             + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
  19.   56
  20.   57/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
  21.   58#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
  22.   59
  23.   60/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
  24.   61#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
复制代码


看看HZ的值是多少

  1. 2.6.31/arch/x86/include/asm/param.h

  2.   10#ifndef HZ
  3.   11#define HZ 100
  4.   12#endif

  5. 2.6.31/arch/ia64/include/asm/param.h

  6.   30# define HZ 1024

  7. 2.6.31/arch/arm/include/asm/param.h

  8.   13#ifdef __KERNEL__
  9.   14# define HZ             CONFIG_HZ       /* Internal kernel timer frequency */
  10.   15# define USER_HZ        100             /* User interfaces are in "ticks" */
  11.   16# define CLOCKS_PER_SEC (USER_HZ)       /* like times() */
  12.   17#else
  13.   18# define HZ             100
  14.   19#endif
  15.   20
复制代码


====================================================================
整理的有些乱,自己对这块也不熟悉。给LZ提供一个思路吧
一路看多来,感觉还是跟系统硬件有关系的,终归编译内核时候的配置选项会根据硬件来做,HZ就会有变化了
另外 KTIME_LOW_RES仅仅是初始化值,具体在后面运行中是否会发生变化也不一定,这样可能通过系统调用得到的
值与单纯自己根据这个流程得到的值会不一样
还有一点,配置不同也会影响初始化时调用的函数,我这里没有细看,LZ可以自己看看不同配置会有什么影响
LZ可以自己看看/kernel/hrtimer.c文件

[ 本帖最后由 openspace 于 2009-11-6 16:22 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP