C ++计时,自上一秒以来的毫秒数

时间:2020-03-06 14:33:45  来源:igfitidea点击:

我正在开发一个C ++应用程序,该应用程序需要详细的时序信息,直到毫秒级。

我们打算使用<ctime>中的标准time()函数将时间收集到秒精度。我们还想收集自time()给出的最后一秒以来经过的毫秒数。

有谁知道获取此信息的便捷方法?

解决方案

如果这适用于Windows,请查看QueryPerformanceCounter方法。

由于ANSI C没有定义标准的毫秒级精确时间函数,因此没有可移植的解决方案。如果使用Windows,则可以使用GetTickCount(),timeGetTime()或者QueryPerformanceCounter()/ QueryPerformanceFrequency()。请记住,它们具有不同的精度和不同的运行时成本。

其他操作系统中还有其他类似的功能。我不确定它们在我头顶上什么。

(c)time.h标头中没有的任何内容都需要特定于操作系统的方法。我相信所有这些方法都是第二种解决方法。

我们正在使用什么操作系统?

如果基础平台支持的话,Boost.DateTime具有毫秒和纳秒的表示形式。当它使用平台特定的代码时,它将那些细节保留在代码之外。

如果这很重要,那么他们确实有另一种独立于平台的亚秒级分辨率的方法。此页面几段下来讨论了如何执行此操作。

(来自页面)

例如,假设我们要使用代表十分之一秒的计数进行构造。也就是说,每个刻度是0.1秒。

int number_of_tenths = 5;
//create a resolution independent count -- divide by 10 since there are 
//10 tenths in a second.  
int count = number_of_tenths*(time_duration::ticks_per_second()/10);
time_duration td(1,2,3,count); //01:02:03.5 //no matter the resolution settings

英特尔处理器的高分辨率,低开销时序

如果我们使用的是Intel硬件,则以下是读取CPU实时指令计数器的方法。它会告诉我们自处理器启动以来执行的CPU周期数。这可能是我们可以用来进行性能评估的最细粒度的计数器。

请注意,这是CPU周期数。在Linux上,我们可以从/ proc / cpuinfo获取CPU速度,然后除以秒数。将其转换为双精度非常方便。

当我在盒子上运行它时,我得到

11867927879484732
11867927879692217
it took this long to call printf: 207485

这是英特尔开发人员指南,其中提供了大量详细信息。

#include < stdio.h >  // stackoverflow bug: pre tag eats the filenames,
#include < stdint.h > // so i had to put spaces in the angle brackets

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}

Windows中的GetTickCount

  • nix中的gettimeofday
    Windows中的QueryPerformanceCounter可提供更好的解析度(尽管GetTickCount应该可以做到)

如果我们使用的是Unix,gettimeofday()将返回秒和微秒,直到系统时钟的分辨率为止。

int gettimeofday(struct timeval *tv, struct timezone *tz);

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

#include <ctime>

clock_t elapsed = static_cast<double>(clock() / CLOCKS_PER_SEC);

经过的时间是经过的处理器时间(以秒为单位)。

分辨率取决于操作系统,但通常在大多数系统上都优于毫秒级分辨率。

英特尔的线程构建模块库具有此功能,但是TBB当前仅在英特尔和克隆上可用(也就是说,在SPARC,PowerPC,ARM等上不可用)。

就像其他人所说的那样,没有便携式的方法可以做到这一点。

我要做的(在msvc ++和linux / g ++上)是我使用以下类,这些类在Windows上使用QueryPerformanceCounter,在Linux上使用gettimeofday。这是一个计时器类,可以让我们了解两次通话之间的经过时间。我们可能需要对其进行修改以适合需求。

#if defined(_MSC_VER)
#  define NOMINMAX // workaround un bug dans windows.h qui define des macros
                   // "min" et "max" qui entrent en conflit avec la STL.
#  include <windows.h>
#else
#  include <sys/time.h>
#endif

namespace Utils
{

   /**
    * Implémente un chronométre qui mesure le temps etre deux appels.
    */
   class CTimer
   {
   private:
#     if defined(_MSC_VER)
         LARGE_INTEGER m_depart;
#     else
         timeval m_depart;
#     endif

   public:
      /**
       * Démarre le timer.
       * 
       * Cette fonction sert à démarrer le timer. Si le timer est  déja
       * démarrer, elle le redémarre simplement.
       */
      inline void start()
      {
#        if defined(_MSC_VER)
            QueryPerformanceCounter(&m_depart);
#        else
            gettimeofday(&m_depart, 0);
#        endif

      };

      /**
       * Retourne le nombre de secondes depuis le départ du timer.
       * 
       * @return Nombre de secondes écoulés depuis le départ du timer
       */
      inline float GetSecondes() const
      {
#        if defined(_MSC_VER)
            LARGE_INTEGER now;
            LARGE_INTEGER freq;

            QueryPerformanceCounter(&now);
            QueryPerformanceFrequency(&freq);

            return (now.QuadPart - m_depart.QuadPart) / static_cast<float>(freq.QuadPart);
#        else
            timeval now;
            gettimeofday(&now, 0);

            return now.tv_sec - m_depart.tv_sec + (now.tv_usec - m_depart.tv_usec) / 1000000.0f;
#        endif
      };
   };
}