c/c++开发分享C++算法计时器的实现示例

有时为了检测和比较算法效率和复杂度,需要一个计时器,而这个计时器往往需要精确到毫秒ms、微秒μs甚至纳秒ns,不太常用的库或api就不放上来了。1.毫秒级精度1.1 clocks_per_sec

有时为了检测和比较算法效率和复杂度,需要一个计时器,而这个计时器往往需要精确到毫秒ms、微秒μs甚至纳秒ns,不太常用的库或api就不放上来了。

1.毫秒级精度

1.1 clocks_per_sec

在头文件time.h或ctime中,clock()函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的cpu时钟计时单元(clock tick)数,在msdn中称之为挂钟时间(wal-clock),常量clocks_per_sec,它用来表示一秒钟会有多少个时钟计时单元,精确到毫秒,其使用方法如下:

精华代码:

#include <iostream>  #include<vector>  #include <algorithm>  #include <ctime>  using namespace std;  int main()  {            clock_t begin, end;      begin = clock();      for (int i = 1; i <= 100; ++i)      {               }      end = clock();      cout << "100次循环所用时间:" << double(end - begin) / clocks_per_sec * 1000 << "ms" << endl;               return 0;  }

示例为检测二叉堆不同输入一个一个插入所用时间(不能直接跑):

#include <iostream>  #include<vector>  #include <algorithm>  #include <ctime>  using namespace std;    int main()  {      int num, mode;      cout << "输入大小和模式,其中模式1为正序,2为倒序,3位随机" << endl;      cout << "示例:1000 2" << endl;      cin >> num >> mode;//输入大小和模式,其中模式1为正序,2为倒序,3位随机      binaryheap<int> heap1,heap2;      clock_t begin, end;      switch (mode)      {      case 1://正序          begin = clock();          for (int i = 1; i <= num; ++i)          {              heap1.insert(i);          }          end = clock();          cout << "一个一个正序插入所用时间:" << double(end - begin) / clocks_per_sec * 1000 << "ms" << endl;          break;      case 2://倒序          begin = clock();          for (int i = num; i >= 1; --i)          {              heap1.insert(i);          }          end = clock();          cout << "一个一个倒序插入所用时间:" << double(end - begin) / clocks_per_sec * 1000 << "ms" << endl;          break;      case 3://正倒序交叉模拟随机          begin = clock();          for (int i = 1; i<num/2; ++i)          {              heap1.insert(i);              heap1.insert(num - i);          }          end = clock();          cout << "一个一个随机插入所用时间:" << double(end - begin) / clocks_per_sec * 1000 << "ms" << endl;          break;      default:          break;      }             return 0;  }

1.2 gettickcount()函数 (windows api)

gettickcount返回(retrieve)从操作系统启动所经过(elapsed)的毫秒数,它的返回值是dword。

#include <stdio.h>  #include <windows.h>  #include<iostream>  #pragma comment(lib, "winmm.lib") //告诉编译器要导入winmm库,有时候可删    int main()  {      dword t1, t2;      t1 = gettickcount();      for(int i=1;i<=10000;++i)      {                }//do something      t2 = gettickcount();      //printf("use time:%fn", (t2 - t1) * 1.0);      cout<<"use time:"<<(double)(t2-t1)<<"ms"<<endl;      return 0;  }

1.3 timegettime()函数(windows api)

以毫秒计的系统时间,该时间为从系统开启算起所经过的时间。在使用timegettime之前应先包含头文件#include <mmsystem.h>或#include <windows.h>并在project->settings->link->object/library modules中添加winmm.lib。也可以在文件头部添加 #pragma comment( lib,"winmm.lib" )。

备注:命令行:#pragma comment( lib,"xxx.lib" )时预编译处理指令,让vc将winmm.lib添加到工程中去进行编译。

//#include<stdio.h>  #include<windows.h>  #include<iostream>  #pragma comment( lib,"winmm.lib" )    int main()  {      dword t1, t2;      t1 = timegettime();      foo();//do something      t2 = timegettime();      //printf("use time:%fn", (t2 - t1)*1.0 / 1000);      cout<<"use time:"<<(double)(t2-t1)<<"ms"<<endl;      return 0;  }

该函数的时间精度是五毫秒或更大一些,这取决于机器的性能。可用timebeginperiod和timeendperiod函数提高timegettime函数的精度。如果使用了,连续调用timegettime函数,一系列返回值的差异由timebeginperiod和timeendperiod决定。也可以用timegettime实现延时功能delay

void delay(dword delaytime)  {    dword delaytimebegin;    dword delaytimeend;    delaytimebegin=timegettime();    do    {        	delaytimeend=timegettime();    }while((delaytimeend-delaytimebegin)<delaytime)  }

1.4 timeval结构体(linux)

timeval结构体

#include <sys/time.h>   #include <iostream>   #include <time.h>   double get_wall_time()   {     struct timeval time ;     if (gettimeofday(&time,null)){       return 0;     }     return (double)time.tv_sec + (double)time.tv_usec * .000001;   }      int main()   {     unsigned int t = 0;     double start_time = get_wall_time()     while(t++<10e+6);     double end_time = get_wall_time()     std::cout<<"循环耗时为:"<<end_time-start_time<<"ms";     return 0;   } 

2.微秒级精度

queryperformancecounter()函数和queryperformancefrequency()函数(windows api)

queryperformancefrequency()函数返回高精确度性能计数器的值,它可以以微妙为单位计时,但是queryperformancecounter()确切的精确计时的最小单位是与系统有关的,所以,必须要查询系统以得到queryperformancecounter()返回的嘀哒声的频率。queryperformancefrequency()提供了这个频率值,返回每秒嘀哒声的个数。

//#include<stdio.h>  #include<iostream>  #include<windows.h>  #pragma comment( lib,"winmm.lib" )    int main()  {      large_integer t1, t2, tc;      queryperformancefrequency(&tc);      queryperformancecounter(&t1);      foo();//do something      queryperformancecounter(&t2);      //printf("use time:%fn", (t2.quadpart - t1.quadpart)*1.0 / tc.quadpart);      cout << "use time:" << (double)((t2.quadpart - t1.quadpart) * 1000000.0 / tc.quadpart) << "μs" << endl;      return 0;  }

封装好的易于调用的代码:

//mytimer.h//   #ifndef __mytimer_h__    #define __mytimer_h__    #include <windows.h>       class mytimer   {   private:     int _freq;     large_integer _begin;     large_integer _end;      public:     long costtime;      // 花费的时间(精确到微秒)       public:     mytimer()     {       large_integer tmp;       queryperformancefrequency(&tmp);//queryperformancefrequency()作用:返回硬件支持的高精度计数器的频率。           _freq = tmp.quadpart;       costtime = 0;     }        void start()      // 开始计时      {       queryperformancecounter(&_begin);//获得初始值      }        void end()        // 结束计时      {       queryperformancecounter(&_end);//获得终止值        costtime = (long)((_end.quadpart - _begin.quadpart) * 1000000 / _freq);     }        void reset()      // 计时清0      {       costtime = 0;     }   };   #endif       //main.cpp   #include "mytimer.h"   #include <iostream>         int main()   {     mytimer timer;     unsigned int t = 0;      timer.start();     while (t++ < 10e+5);     timer.end();      std::cout << "耗时为:" << timer.costtime << "us";     return 0 ;   } 

3.纳秒级精度

要先获取cpu频率。

在intel pentium以上级别的cpu中,有一个称为“时间戳(time stamp)”的部件,它以64位无符号整型数的格式,记录了自cpu上电以来所经过的时钟周期数。由于目前的cpu主频都非常高,因此这个部件可以达到纳秒级的计时精度。这个精确性是上述几种方法所无法比拟的.在pentium以上的cpu中,提供了一条机器指令rdtsc(read time stamp counter)来读取这个时间戳的数字,并将其保存在edx:eax寄存器对中。由于edx:eax寄存器对恰好是win32平台下c++语言保存函数返回值的寄存器,所以我们可以把这条指令看成是一个普通的函数调用,因为rdtsc不被c++的内嵌汇编器直接支持,所以我们要用_emit伪指令直接嵌入该指令的机器码形式0x0f、0x31。

inline unsigned __int64 getcyclecount()  {      __asm      {          _emit 0x0f;          _emit 0x31;      }  }    void test()  {      unsigned long t1,t2;      t1 = (unsigned long)getcyclecount();      foo();//dosomething      t2 = (unsigned long)getcyclecount();      printf("use time:%fn",(t2 - t1)*1.0/frequency);   //frequency指cpu的频率  }

下面为获取cpu精度的代码

#include<windows.h>  longlong getfrequency(dword sleeptime) //获取cpu主频    {        dword low1 = 0, high1 = 0, low2 = 0, high2 = 0;        large_integer fq, st, ed;        /*在定时前应该先调用queryperformancefrequency()函数获得机器内部计时器的时钟频率。接着在    需要严格计时的事件发生前和发生之后分别调用queryperformancecounter(),利用两次获得的技术    之差和时钟的频率,就可以计算出时间经历的精确时间。*/        ::queryperformancefrequency(&fq); //精确计时(返回硬件支持的高精度计数器的频率)        ::queryperformancecounter(&st); //获得起始时间        __asm { //获得当前cpu的时间数    rdtsc    mov low1, eax    mov high1, edx        }        ::sleep(sleeptime); //将线程挂起片刻        ::queryperformancecounter(&ed); //获得结束时间        __asm {  rdtsc //读取cpu的时间戳计数器    mov low2, eax    mov high2, edx        }        //将cpu得时间周期数转化成64位整数        longlong begin = (longlong)high1 << 32 | low1;        longlong end = (longlong)high2 << 32 | low2;        //将两次获得的cpu时间周期数除以间隔时间,即得到cpu的频率        //由于windows的sleep函数有大约15毫秒的误差,故以windows的精确计时为准        return (end - begin) * fq.quadpart / (ed.quadpart - st.quadpart);  }

4.利用chrono的各精度集成版(本质微秒)

4.1 chrono库介绍

函数原型:

template <class clock, class duration = typename clock::duration>    class time_point;

std::chrono::time_point 表示一个具体时间

第一个模板参数clock用来指定所要使用的时钟,在标准库中有三种时钟,分别为:

  • system_clock:当前系统范围(即对各进程都一致)的一个实时的日历时钟(wallclock)
  • steady_clock:当前系统实现的一个维定时钟,该时钟的每个时间嘀嗒单位是均匀的(即长度相等)。
  • high_resolution_clock:当前系统实现的一个高分辨率时钟。

第二个模板函数参数用来表示时间的计量单位(特化的std::chrono::duration<> )

时间点都有一个时间戳,即时间原点。chrono库中采用的是unix的时间戳1970年1月1日 00:00。所以time_point也就是距离时间戳(epoch)的时间长度(duration)。

4.2 代码示例

#include <iostream>  #include <chrono>     using namespace std;  using namespace std::chrono;     class timerclock  {  public:   timerclock()   {    update();   }      ~timerclock()   {   }      void update()   {    _start = high_resolution_clock::now();   }   //获取秒   double gettimersecond()   {    return gettimermicrosec() * 0.000001;   }   //获取毫秒   double gettimermillisec()   {    return gettimermicrosec()*0.001;   }   //获取微妙   long long gettimermicrosec()   {    //当前时钟减去开始时钟的count    return duration_cast<microseconds>(high_resolution_clock::now() - _start).count();   }  private:   time_point<high_resolution_clock>_start;  };     //测试的主函数  int main()  {   timerclock tc;   int sum = 0;   tc.update();   for (int i = 0; i > 100000; i++)   {    sum++;   }   cout << "cost time:" << tc.gettimermillisec() <<"ms"<< endl;   cout << "cost time:" << tc.gettimermicrosec() << "us" << endl;      return 0;  }

5.秒级精度

单纯以备不时之需,没人用吧。

time() 函数

在头文件time.h中,time()获取当前的系统时间,只能精确到秒,返回的结果是一个time_t类型,其使用方法如下:

#include <time.h>     #include <stdio.h>       int main()   {         time_t first, second;         first=time(null);         delay(2000);         second=time(null);         printf("the difference is: %f seconds",difftime(second,first));  //调用difftime求出时间差       return 0;     }

到此这篇关于c++算法计时器的实现示例的文章就介绍到这了,更多相关c++算法计时器内容请搜索<猴子技术宅>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<猴子技术宅>!

需要了解更多c/c++开发分享C++算法计时器的实现示例,都可以关注C/C++技术分享栏目—猴子技术宅(www.ssfiction.com)

本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ssfiction.com/c-cyuyankaifa/1240357.html

(0)
上一篇 4天前
下一篇 3天前

精彩推荐

发表回复

您的电子邮箱地址不会被公开。