C++算法计时器的实现示例

目录
  • 1.毫秒级精度
    • 1.1 CLOCKS_PER_SEC
    • 1.2 GetTickCount()函数 (Windows API)
    • 1.3 timeGetTime()函数(Windows API)
    • 1.4 timeval结构体(Linux)
  • 2.微秒级精度
    • QueryPerformanceCounter()函数和QueryPerformanceFrequency()函数(Windows API)
  • 3.纳秒级精度
  • 4.利用chrono的各精度集成版(本质微秒)
    • 4.1 chrono库介绍
    • 4.2 代码示例
  • 5.秒级精度
    • time() 函数

有时为了检测和比较算法效率和复杂度,需要一个计时器,而这个计时器往往需要精确到毫秒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:%f\n", (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:%f\n", (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:%f\n", (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:%f\n",(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++算法计时器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ clock()解析如何使用时钟计时的应用

    C/C++中的计时函数是clock(),而与其相关的数据类型是clock_t.在MSDN中,查得对clock函数定义如下: clock_t clock( void ); 这个函数返回从"开启这个程序进程"到"程序中调用clock()函数"时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock).其中clock_t是用来保存时间的数据类型,在time.h文件中,我们可以找到对它的定义:#ifndef _CLOCK_T_DE

  • C++实现统计代码运行时间计时器的简单实例

     C++实现统计代码运行时间计时器的简单实例 一.前言 这里记下从网上找到的一些自己比较常用的C++计时代码 二.Linux下精确至毫秒 #include <sys/time.h> #include <iostream> #include <time.h> double get_wall_time() { struct timeval time ; if (gettimeofday(&time,NULL)){ return 0; } return (double

  • C++如何实现简单的计时器详解

    实现分析 首先我们先分析一下计时器的一些功能,简单一点的计时器包括开始.暂停.停止和显示基本功能,这些功能以C++面向对象的编程思想(OOP)进行抽象,就是计时器类(Timer)的4个成员函数,当然我们要把这些函数作为公有的,因为它们是留给外部的接口(interface). 然后我们再分析一下计时器的三种状态:停止,正在运行,暂停(注意:暂停不是停止),那么怎么记录计时器的三种状态呢? 这里我们用布尔类型的变量记录计时器的三种状态,分别为bool is_pause,bool is_stop,在这

  • 总结UNIX/LINUX下C++程序计时的方法

    前言 良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较.但要精确测量程序的运行时间并不容易,因为进程切换.中断.共享的多用户.网络流量.高速缓存访问及转移预测等因素都会对程序计时产生影响. 下面看看小编为大家整理几个计时方法 方法一: 如果是想统计某个程序的运行时间,那么可以使用 time ./a.out 方法二: 如果是想对某个函数或者语句进行计时,那么有别的方法.比如说,gettimeofday函数.直接贴示例代码: #include <sys/time.h> v

  • c++利用windows函数实现计时示例

    复制代码 代码如下: //Windows系统下可以用 time(),clock(),timeGetTime(),GetTickCount(),QueryPerformanceCounter()来对一段程序代码进行计时 #include <stdio.h>#include <windows.h>#include <time.h>                   //time_t time()  clock_t clock()    #include <Mmsys

  • C++算法计时器的实现示例

    目录 1.毫秒级精度 1.1 CLOCKS_PER_SEC 1.2 GetTickCount()函数 (Windows API) 1.3 timeGetTime()函数(Windows API) 1.4 timeval结构体(Linux) 2.微秒级精度 QueryPerformanceCounter()函数和QueryPerformanceFrequency()函数(Windows API) 3.纳秒级精度 4.利用chrono的各精度集成版(本质微秒) 4.1 chrono库介绍 4.2 代

  • Java算法之堆排序代码示例

    堆是一种特殊的完全二叉树,其特点是所有父节点都比子节点要小,或者所有父节点都比字节点要大.前一种称为最小堆,后一种称为最大堆. 比如下面这两个: 那么这个特性有什么作用?既然题目是堆排序,那么肯定能用来排序.想要用堆排序首先要创建一个堆,如果对4 3 6 2 7 1 5这七个数字做从小到大排序,需要用这七个数创建一个最大堆,来看代码: public class HeapSort { private int[] numbers; private int length; public HeapSor

  • Java语言字典序排序算法解析及代码示例

    字典序法就是按照字典排序的思想逐一产生所有排列. 在数学中,字典或词典顺序(也称为词汇顺序,字典顺序,字母顺序或词典顺序)是基于字母顺序排列的单词按字母顺序排列的方法. 这种泛化主要在于定义有序完全有序集合(通常称为字母表)的元素的序列(通常称为计算机科学中的单词)的总顺序. 对于数字1.2.3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的.例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后.按照这样的规定,5个数字的所有的

  • Spring计时器StopWatch使用示例

    StopWatch是位于org.springframework.util包下的一个工具类,通过它可方便的对程序部分代码进行计时(ms级别),适用于同步单线程代码块. 正常情况下,我们如果需要看某段代码的执行耗时,会通过如下的方式进行查看: public static void main(String[] args) throws InterruptedException { StopWatchTest.test0(); // StopWatchTest.test1(); } public sta

  • Python数学建模学习模拟退火算法多变量函数优化示例解析

    目录 1.模拟退火算法 2.多变量函数优化问题 3.模拟退火算法 Python 程序 4.程序运行结果 1.模拟退火算法 退火是金属从熔融状态缓慢冷却.最终达到能量最低的平衡态的过程.模拟退火算法基于优化问题求解过程与金属退火过程的相似性,以优化目标为能量函数,以解空间为状态空间,以随机扰动模拟粒子的热运动来求解优化问题([1] KIRKPATRICK,1988). 模拟退火算法结构简单,由温度更新函数.状态产生函数.状态接受函数和内循环.外循环终止准则构成. 温度更新函数是指退火温度缓慢降低的

  • Unity计时器功能实现示例

    目录 Demo展示 介绍 计时器功能 Unity计时器 Demo展示 介绍 游戏中有非常多的计时功能,比如:各种cd,以及需要延时调用的方法: 一般实现有一下几种方式: 1.手动计时 float persistTime = 10f float startTime = Time.time; if(Time.time - startTime > persistTime) { Debug.Log("计时结束"); } float curTime = 0; curTime += Time

  • 用JS写了一个30分钟倒计时器的实现示例

    前端页面倒计时功能在很多场景中会用到,如很多秒杀活动等,本文主要介绍了用JS写了一个30分钟倒计时器的实现示例,感兴趣的可以了解一下 <!DOCTYPE HTML> <html>     <head>         <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>         <title>Countdown Tim

  • C语言算法积累分离数位示例

    题目:输出一个三位整数的个.十.百位数. 关键字:得到数位 思路: Q:如何利用简单的基本运算来得到一个数字的各个数位上的数字? A:利用除法和求余运算:以153为例 首先,百位最容易得到:153/100=1.任何三位数除以100都是得到其百位的数字 其次,个位也好弄:153%10=3.任何三位数对10取余都是其个位数. 最后,十位数有四个方法. 最好想的: 1.用(原三位数—百位数* 100—个位数 * 1)/10 153-1X100-1X3=50; 50/10=5 2.将原三位数对100取余

  • java数据结构与算法数组模拟队列示例详解

    目录 一.什么是队列 二.用数组来模拟队列 一.什么是队列 队列是一个有序列表,可以用数组或者链表来实现. 遵循先入先出的原则,即:先存入队列的数据,要先取出.后存入的的数据,后取出. 看一张队列的模拟图,1,2,3表示同一个队列Queue.在队列中有2个指针,front表示队首,rear表示队尾. 图1中表示队列里还没有数据,所以front跟rear初始化都是-1. 当图2中有数据进行存入的时候,front没变,而rear则随着数据的增多而改变.存入了4个数据,于是rear=3. 再看图3,f

  • C语言实现交换排序算法(冒泡,快速排序)的示例代码

    目录 前言 一.冒泡排序 1.基本思想 2.优化 3.扩展 二.快速排序 1.基本思想 2.优化 3.代码 前言 查找和排序是数据结构与算法中不可或缺的一环,是前辈们在算法道路上留下的重要且方便的一些技巧,学习这些经典的查找和排序也能让我们更好和更快的解决问题.在这个专栏中我们会学习六大查找和十大排序的算法与思想,而本篇将详细讲解其中的交换排序——冒泡排序和快速排序: 注意:本文中所有排序按照升序排序,降序只需要把逻辑反过来即可! 一.冒泡排序 1.基本思想 对于很多同学来说冒泡排序是再熟悉不过

随机推荐