zoukankan      html  css  js  c++  java
  • linux 时间处理 + 简单写log

    
    1s ==1000ms == 1,000,000us == 1,000,000,000 nanosecond
    
    
    uname -a
    Linux scott-Z170X 4.15.0-34-generic #37-Ubuntu SMP Mon Aug 27 15:21:48 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
    intel i5-6500
    
    我的CLOCKS_PER_SEC   是100W
    
    ---------------------------
    
    //格式化输出
    int64_t   %ld ,    uint64_t  %lu
    longlong  %lld ,  ulonglong  %llu
    
    
    double  %g
    float   %f
    int %d
    uint %u
    
    //指定输出到哪个地方,可以指定log文件 ,或者控制台 stdout
    fprintf(stdout, "%g is %g
    ", inputValue, outputValue);
    
    

    Linux时钟精度:毫秒?微妙?纳秒?

    
    首先:linux有一个很重要的概念——节拍,它的单位是(次/秒)。2.6内核这个值是1000,系统中用一个HZ的宏表征这个值。同时有全局的jiffies变量,表征从开机以来经过的节拍次数(这里面还有故事,后面说,先记住这个)。当然还有wall_jiffies的墙上jiffies来表示从 07-01-1970 到现在的节拍数。每个节拍里面执行一次时钟中断。就是说,它的精度是毫秒。
    
    接着:内核中还有一个变量xtime表征系统的实际时间(墙上时间),定义如下。其中xtime.tv_sec以秒为单位,存放从Unix祖宗定的纪元时间(19700701)到现在的秒数。xtime.tv_nsec以纳秒为单位,记录从上一秒开始经过的纳秒数。就是说,它的精度是纳秒。
    
    struct timespec xtime;
    
    struct timespec{
        time_t tv_sec;   //秒
        long tv_nsec;    //纳秒
    };
    
    最后:linux提供一个gettimeofday的系统调用,它会返回一个timeval的结构体,定义如下。解释同上,tv_sec代表墙上时间的秒,tv_usec表示从上一秒到现在经过的微秒数。就是说,它的精度是微妙。
    
    struct timeval{
        long tv_sec;     //秒
        long tv_usec;    //微妙
    };
    
    精彩的来了:
    1. 内核中的xtime会在每个时钟中断的时候被更新一次,也就是每个节拍更新一次。你妹!!每毫秒更新一次怎么能冒出来纳秒的精度??而且,内核还有可能丢失节拍。怎么能是纳秒??
    2. 各种书上说,gettimeofday系统调用是读取的xtime的值。日,为啥读出来之后精度丢了?变成微妙了?
    
    寻寻觅觅终于理清了故事:
    针对问题1:在linux启动的时候,一个节拍的时间长度还会以纳秒为单位初始化到tick_nsec中,初始化值为999848ns,坑爹啊!不到一毫秒!节拍大约为1000.15Hz。靠!实际的节拍竟然不是准确的1000!所以在每个时钟中断通过wall_jiffies去更新xtime的时候得到的就是一个以纳秒为最小单位的的值。所以!xtime的粒度应该是不到1毫秒,也就是精度是不到1毫秒。
    
    针对问题2:gettimeday系统调用的读xtime代码部分如下:
    do{
        unsigned long lost;
        seq = read_seqbegin(&xtime_lock);
    
        usec = timer->get_offset();    //在计时器中取从上一次时钟中断到现在的微秒数
        lost = jiffies - wall_jiffies;
        if(lost)
            usec += lost*(1000000/HZ); //HZ是节拍宏,值1000
        sec = xtime.tv_sec;
        usec += (xtime.tv_nsec/1000);  //由纳秒转为微妙
    
    }while(read_seqretry(&xtime_lock, seq))
    
    while部分使用了seg锁,只看中间的就好了。加了注释之后就很清晰了。由于节拍可能会丢失,所以lost是丢失的节拍数(不会很多)。至于计时器就比较麻烦了,timer可能有下面四种情况。
    
    a. 如果cur_timer指向timer_hpet对象,该方法使用HPET定时器——Inter与Microsoft开发的高精度定时器频率至少10MHz,也就是说此时可提供真正的微妙级精度。
    b. 如果cur_timer指向timer_pmtmr对象,该方法使用ACPI PMT计时器(电源管理定时器)平率大约3.58MHz,也就是说也可以提供真正的微妙级精度。
    c. 如果cur_timer指向timer_tsc对象,该方法使用时间戳计数器,内置在所有8086处理器,每个CPU时钟,计数器增加一次,频率就是CPU频率,所以timer精度最高。完全可以胜任微妙级的精度。
    d. 如果cur_timer指向timer_pit对象,该方法使用PIT计数器,也即是最开始提到的节拍计数,频率大概是1000Hz,此时显然不能提供精度达到微妙的时间。所以只有这种情况是假毫秒精度!
    
    综上:如果使用gettimeofday系统调用,只要不要使用节拍计数器就可以保证达到微妙精度的时间(刨除进程上下文时间误差)。至于网上说的可以拿到纳秒精度的时间,看起来都是错的。除非通过修改内核,使用时间戳计数器实现。Over!
    
    
    最后最后说一个事情:jiffies的定义的是4字节,你可能猜想它初始值是0。实际上,事实并非如此!linux中jiffies被初始化为0xfffb6c20,它是一个32位有符号数,正好等于-300 000。因此,计数器会在系统启动5分钟内溢出。这是为了使对jiffies溢出处理有缺陷的内核代码在开发阶段被发现,避免此类问题出现在稳定版本中。
    
    
    
    参考《深入理解linux内核》
    
    
    
    #include <stdio.h>   //file 
    
    #include <iostream> 
    #include <ctime>         //c++   精确度s   time(),ctime()
    #include <string>
    
    #include <sys/time.h>  //linux  精确度s, us    gettimeofday()
    
    
    using namespace std;
    
    int main()
     {
            time_t beginTime,endTime;
            struct timeval tvBegin,tvEnd;
            struct timezone tz;
    
     
            time (&beginTime);
            printf ("The current local time is: %s", ctime (&beginTime));
            gettimeofday (&tvBegin , &tz);
    
            //do  something
        
            time (&endTime);
            printf ("The current local time is: %s 
    ", ctime (&endTime));
            gettimeofday (&tvEnd , &tz);
    
            //tv_sec 是 Unix timestamp
            //tvEnd.tv_sec-tvBegin.tv_sec 得到多少s,   ==>1 s*1000  (5-3=2, 2*1000=>2000ms) 
            //tvEnd.tv_usec-tvBegin.tv_usec 得到多少us,==>1 us/1000 (55100-373988= -31812, 2/1000=>318ms)
            //2000ms+(-318ms) 就是最终消耗的时间 1682ms
    
    
            uint64_t uSpendms = (tvEnd.tv_sec-tvBegin.tv_sec)*1000+(tvEnd.tv_usec-tvBegin.tv_usec)/1000;
    
    
    #ifdef TEST 
            printf ("uSpendms = %lu .tvEnd.tv_sec = %ld, tvBegin.tv_sec=%ld ;  tvEnd.tv_usec = %ld, tvBegin.tv_usec=%ld .
    ",
             uSpendms,
             tvEnd.tv_sec, tvBegin.tv_sec, 
             tvEnd.tv_usec, tvBegin.tv_usec); 
    #else
            std::cout<< "tvEnd.tv_sec ="<<tvEnd.tv_sec << ". tvBegin.tv_sec ="<<tvBegin.tv_sec <<std::endl;
            std::cout<< "tvEnd.tv_usec ="<<tvEnd.tv_usec << ". tvBegin.tv_usec ="<<tvBegin.tv_usec <<std::endl;
            std::cout<< "SpendTime="<<uSpendms<<"ms"<<std::endl;
    
    #endif     
    
    
    
    #ifdef  WRITE_LOG
    
      int i;
      double result;
    
      // open the output file
      FILE* fout = fopen(“test.log”, "w");
      if (!fout) {
        return 1;
      }
    
      // create a source file with a table of square roots
      fprintf(fout, "double sqrtTable[] = {
    ");
      for (i = 0; i < 10; ++i) {
        result = sqrt(static_cast<double>(i));
        fprintf(fout, "%g,
    ", result);
      }
    
      // close the table with a zero
      fprintf(fout, "0};
    ");
      fclose(fout);
    
    #endif
    
    
    
      return 0;
    
    }
    
  • 相关阅读:
    【BZOJ 4581】【Usaco2016 Open】Field Reduction
    【BZOJ 4582】【Usaco2016 Open】Diamond Collector
    【BZOJ 4580】【Usaco2016 Open】248
    【BZOJ 3754】Tree之最小方差树
    【51Nod 1501】【算法马拉松 19D】石头剪刀布威力加强版
    【51Nod 1622】【算法马拉松 19C】集合对
    【51Nod 1616】【算法马拉松 19B】最小集合
    【51Nod 1674】【算法马拉松 19A】区间的价值 V2
    【BZOJ 2541】【Vijos 1366】【CTSC 2000】冰原探险
    【BZOJ 1065】【Vijos 1826】【NOI 2008】奥运物流
  • 原文地址:https://www.cnblogs.com/scotth/p/9586125.html
Copyright © 2011-2022 走看看