找回密码
 注册
查看: 2627|回复: 7

有关精确计时的探讨

[复制链接]
发表于 2004-11-9 12:51:54 | 显示全部楼层 |阅读模式
这里讨论的是计算时间间隔的计时。

大部分情况下gettimeofday是够用的,这里我说的是一种不通过系统调用的方法。

奔腾和它后继的CPU里有一个叫Time Stamp Counter ,TSC的64位寄存器,晶振每振一次它就会加1,例如一个400MHz的芯片,那么它就是每2.5纳秒更新一次。通过汇编指令rdtsc就可以读取它的值。所以,知道了CPU的频率,就可以精确计时,至于获取CPU的频率,我还没有查到,那位读过内核的给说一下。

我写了个简单的计算CPU频率的程序,由于用了gettimeofday,所以很不精确,仅供讨论。参考了linux的内核代码。

[code:1]
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#define rdtsc(low,high) \
     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))

int main (int argc, char** argv)
{
        unsigned int high1, low1;
        unsigned int high2, low2;
        struct timeval t1, t2;

        gettimeofday (&t1, NULL);

        rdtsc(low1, high1);

        /* 一秒的循环 */
        while (1) {
                gettimeofday (&t2, NULL);
                if (t1.tv_sec<t2.tv_sec && t1.tv_usec<=t2.tv_usec)
                        break;
        }


        rdtsc(low2, high2);

        printf ("%ld.%ld\n", t1.tv_sec, t1.tv_usec);
        printf ("%ld.%ld\n", t2.tv_sec, t2.tv_usec);
        if (low2<low1) {
                low2 = 0xffffffff - low1 + low2;
                high2 = high2 - high1 -1;
        }
        else {
                high2 = high2 - high1;
                low2 = low2 - low1;
        }
        printf ("%08x %08x\n", high2, low2);
        return 0;
}
[/code:1]

linux计算386系列CPU频率的函数在arch/i386/kernel/timers/common.c
发表于 2004-11-9 13:41:27 | 显示全部楼层
这个……请问在什么情况下要用它而不能用gettimeofday?
回复

使用道具 举报

发表于 2004-11-9 19:27:14 | 显示全部楼层
Linux使用Cycle Counters计数,Windows使用 Interval Counting实现gettimeofday(Win下有吗?不知道)。所以用这个函数已经很精确了。
回复

使用道具 举报

发表于 2004-11-10 14:08:25 | 显示全部楼层
[code:1]
//这是clock.h文件
//取自《Computer System》
#include <stdio.h>
static unsigned cyc_hi = 0;
static unsigned cyc_lo = 0;

void access_counter ( unsigned *hi, unsigned *lo)
{
  asm("rdtsc; movl %%edx,%0;movl %%eax,%1"
      : "=r" (*hi), "=r" (*lo)
      :
      : "%edx","%eax");
}

void start_counter()
{
  access_counter(&cyc_hi, &cyc_lo);
}

double get_counter()
{
  unsigned ncyc_hi, ncyc_lo;
  unsigned hi,lo, borrow;
  double result;
  access_counter (&ncyc_hi, &ncyc_lo);

  lo = ncyc_lo - cyc_lo;
  borrow = lo > ncyc_lo;
  hi = ncyc_hi - cyc_hi - borrow;
  result = (double) hi *(1<<30) *4+lo;
  if( result <0) {
    fprintf(stderr, "Error: counter returns neg value; %.of\n", result);
  }

  return result;
}
[/code:1]
[code:1]
//这是测试文件
//取自《Computer System》
#include "clock.h"

int main()
{
  start_counter();
  printf("ok\n");

  printf("%f\n",  get_counter());
}
[/code:1]
这是从《Computer System》上转的程序。仅适用于ia32体系。
回复

使用道具 举报

 楼主| 发表于 2004-11-10 14:29:19 | 显示全部楼层
楼上的程序除了能读tsc的内容,还有什么用吗?
回复

使用道具 举报

发表于 2004-11-10 16:07:20 | 显示全部楼层
没啥用   
回复

使用道具 举报

发表于 2005-7-11 22:01:37 | 显示全部楼层
有个问题……gettimeofday()返回的是从什么时候到调用时的时间间隔?
回复

使用道具 举报

发表于 2005-7-12 08:42:34 | 显示全部楼层
还不如直接读/proc/uptime
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2025-7-24 00:25 , Processed in 0.032423 second(s), 16 queries .

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表