获得最准确的时间戳 [英] Getting the most accurated timestamp possible

查看:112
本文介绍了获得最准确的时间戳的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景:

我正在开发一个新模块,以特殊格式生成协议文件,并将其集成到更大的软件中。主要软件有几个部分,一些在C#.Net中,一些在c ++中有MFC(包括多线程),我使用的API也有一个.c文件。

我的测试应用是一个在VS2017 Professional中支持MFC和ATL的C ++控制台。

虽然主要软件使用多线程,但我不愿意在我的测试应用程序中使用它们。



我想获得最快(从性能的角度来看)和最准确/最小的分辨率时间戳来计算我可以使用的增量/所需的执行时间。

需要的可能性程序另一部分的增量还没有消失,所以我想在一个变量中得到它以防万一。这就是我尝试通过代码而不是使用外部性能工具进行测量的原因。


我尝试了什么:



我尝试了几种方法:



1)

Scenario:
I am developing a new module to generate protocol files in a special format that will be integrated in a bigger software. The main software has several parts, some in C# .Net and some in c++ with MFC (including multi-threading) and the API I am using has a .c file too.
My test Application is a C++ Console with MFC and ATL support in VS2017 Professional.
Although the main software uses multithread I am not willing to get involved with them in my test app.

I would like to get the fastest (from performance point of view) and most accurate / smallest resolution timestamp to calculate deltas / needed time of execution I can use.
The possibility of needing the deltas in another part of the program is not gone yet, so I would like to get it in a variable just in case. This is why I try to do the measurements via code instead of using external performance tools.

What I have tried:

I have tried several approaches:

1)

time_t GetActualTime()
{
  _tzset();

  time_t myTime;
  time(&myTime);

  return myTime;
}

我认为是最快的选项(在执行时间内),但它返回秒。对于我的程序的其他部分是绰绰有余,但不是我现在要检查的内容。



2)

使用FILETIME我应该能够达到100x纳秒,但问题是我用来获取所需时间戳的解决方法。使用此代码:

I suppose is the fastest option (in execution time), but it returns seconds. For other parts of my program is more than enough, but not for what I want to check right now.

2)
With FILETIME I should be able to get down to 100x Nanoseconds, but the problem is the "workaround" I am using to get the needed timestamp. With this code:

ULARGE_INTEGER GetTimeFile100xNanoSec (int iNr)
{
  FILETIME timeCreation;        // Value in 100x NanoSecons
  ULARGE_INTEGER uli100xNanoSec;
  
  CString strFileName = _T("");
  strFileName.Format(_T("D:\\Temp\\myDummyFile_%03d.txt"), iNr); // to avoid tunnelig effect if using same name
  CStringW strFileNameW(strFileName);
  LPCWSTR lpFileName = strFileNameW;

  HANDLE hFile = CreateFileW(lpFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);

  GetFileTime(hFile, &timeCreation, NULL, NULL);
  CloseHandle(hFile);
  DeleteFileW(lpFileName);

  uli100xNanoSec.LowPart = timeCreation.dwLowDateTime;
  uli100xNanoSec.HighPart = timeCreation.dwHighDateTime;
 
  return uli100xNanoSec;
}

在循环中使用它:

using it in a loop like:

ULARGE_INTEGER lluOld;
ULARGE_INTEGER lluNew;

lluOld = GetTimeFile100xNanoSec(999);
for (int i=0; i<100; i++)
{
  lluNew = GetTimeFile100xNanoSec(i);
  wprintf(_T("\nIn Loop [%d], New - old = %llu"), i, lluNew.QuadPart - lluOld.QuadPart);
  lluOld.QuadPart = lluNew.QuadPart;
}



我得到的值从10001(1毫秒)到60006(6毫秒),100次尝试的平均值几乎是2 ,5毫秒。创建/删除临时文件会影响性能,使其速度变慢,有效范围以毫秒为单位。是什么让小分辨率徒劳无功。





3)

使用SYSTEMTIME我只能去降到毫秒。我还没有检查性能速度,但我会稍后再做,如果我能以稳定的方式获得1ms的步骤,我想我会使用它,因为#2不够稳定可靠





以可靠和可重复使用的方式获得低于毫秒标记的任何建议?可重用我的意思是获取可以在其他地方评估的变量中的值。


I am getting values from 10001 (1 ms) up to 60006 (6 ms), average of the 100 tries is almost 2,5 ms. Creating / deleting the temp files affects the performance making it so slow, that the valid range gets in milliseconds. What makes the small resolution to be in vain.


3)
With SYSTEMTIME I can only go down to Miliseconds. I have not checked performance speed yet, but I will do it later, if I can get the 1ms step in a stable way, I suppose I will use this since #2 is not stable enough to be reliable


Any suggestions to get below the mark of milliseconds in a reliable and reusable way? With reusable I mean getting the value in a variable that can be evaluated in other place.

推荐答案

我在QueryPerformanceCounter API函数周围使用了一个小包装器类。以下是它的简化版本:
I use a little wrapper class around the QueryPerformanceCounter API function. Here is a stripped down version of it:
class CElapsed
{
public :
   CElapsed()   // constructor
   {
        // get the frequency of the performance counter and its period in seconds

        LARGE_INTEGER li = { 0 };
        m_Period = QueryPerformanceFrequency( &li ) ? 1.0 / (double)li.QuadPart : 0;
   }

   // get the current performance counter value, convert it
   // to seconds, and return the difference from begin in seconds

   double TimeSince( double begin=0 )
   {
       LARGE_INTEGER endtime;
       QueryPerformanceCounter( &endtime );
       return ( endtime.QuadPart * m_Period ) - begin;
   }

   // returns true if the counter is available

   bool IsAvailable()     { return m_Period != 0; }

   // return the counter frequency

   double GetFrequency()  { return 1.0 / m_Period; }

protected :
   double  m_Period;
};

这是一个如何使用它的例子:

Here is an example of how to use it :

CElapsed et;
double start = et.TimeSince( 0 );

// code to time goes here

double elapsed = et.TimeSince( start );
_tprintf( _T( "elapsed time was %.3f seconds\n" ), elapsed );

我建议您阅读QueryPerformanceCounter以查看其属性。计数器频率取决于机器,但几乎总是在兆赫兹范围内,所以它的分辨率在几微秒内,但确实有一些开销。我从来不需要分辨率低于毫秒的时间,所以这对我的目的来说是足够的。



这种计时器类有很多变种。我喜欢这个实现,因为它不保留起始值。这允许一个计时器对象同时用于许多事情。事实上,如果你想这样做,一个计时器对象可以用于整个应用程序。构造也是最小的,因此可以快速,轻松地创建实例,而且开销最小。

I recommend reading up on QueryPerformanceCounter to see what its properties are. The counter frequency is machine-dependent but is nearly always in the megahertz range so its resolution is in the microseconds but it does have some overhead. I have never needed timing with a resolution of under a millisecond so this is adequate for my purposes.

There are many variations of this kind of timer class. I like this implementation because it does NOT retain the starting value. This allows one timer object to be used for many things simultaneously. In fact, one timer object can be used for an entire application if you want to do that. Construction is also minimal so instances can be created quickly and easily with a minimum of overhead.


请参见此处: GetTickCount函数| Microsoft Docs [ ^ ]和这里:关于计时器 - Windows应用程序| Microsoft Docs [ ^ ]



分辨率不固定:它因系统而异,因此在运行相同软件的两台不同PC上获得的分辨率可能不同。
See here: GetTickCount function | Microsoft Docs[^] and here: About Timers - Windows applications | Microsoft Docs[^]

Resolution is not fixed: it varies by system, so what you get on two different PCs running the same software may be different.


这篇关于获得最准确的时间戳的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆