用C++获得准确的执行时间(微秒)

use*_*616 30 c++ performance

我希望在用C++实现的程序的微秒内获得准确的执行时间.我试图用clock_t获得执行时间,但这不准确.

Oli*_*rLi 68

如果您使用的是c ++ 11或更高版本,则可以使用std::chrono::high_resolution_clock.

一个简单的用例:

auto start = std::chrono::high_resolution_clock::now();
...
auto elapsed = std::chrono::high_resolution_clock::now() - start;

long long microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
Run Code Online (Sandbox Code Playgroud)

该解决方案具有便携的优点.

  • @qdii以微秒为单位测试程序的性能,设置和销毁部分_should_将被忽略. (9认同)
  • @qdii确切地说,不同的操作系统有不同的设置时间.这就是为什么.如果包含该位,则不是测量应用程序性能,而是测量操作系统性能.为什么要这么做?除非您是操作系统开发人员,否则您无法对设置时间做任何事情.即使在一个操作系统上,硬盘也可能需要旋转才能读取可执行文件.你真的想测量到微秒的精度吗? (4认同)
  • 注意:自GCC 4.8.1起,以g ++纳秒为准. (3认同)
  • @qdii 是的,这是一个应用程序。但是你真的会通过测量时间来做到这一点吗?您肯定需要一个分析器来识别_什么_部分导致高设置时间。任何程序的启动都应该“感觉瞬间”。你真的不需要衡量这个恕我直言。 (3认同)
  • @stefan 嗯,例如,我可能想要这样做,因为我是一名游戏开发人员,我想知道我的游戏在 Windows 8 上专门启动需要多长时间。作为开发人员,我对可执行文件的大小有影响:我可以在二进制可执行文件的部分中嵌入资源、剥离符号、优化空间等。我认为需要澄清这个问题,以便准确测量什么. (2认同)

Gab*_*les 17

以下是如何在 C++ 中获得简单的类似 C 的毫秒、微秒和纳秒时间戳:

新的 C++11std::chrono库是我见过或试图弄清楚如何使用的最复杂的一堆乱七八糟的C++ 之一,但至少它是跨平台的!

所以,如果你想简化它并使它更像 C 语言,包括删除它所做的所有类型安全的类的东西,这里有 3 个简单且非常易于使用的函数来获取时间戳毫秒、微秒和纳秒……我只花了大约 12 小时来写*:

注意:在下面的代码中,您可能会考虑使用std::chrono::steady_clock代替std::chrono::high_resolution_clock。他们在这里的定义(https://en.cppreference.com/w/cpp/chrono)如下:

  • stable_clock (C++11) - 永远不会被调整的单调时钟
  • high_resolution_clock (C++11) - 可用最短滴答周期的时钟
#include <chrono>

// NB: ALL OF THESE 3 FUNCTIONS BELOW USE SIGNED VALUES INTERNALLY AND WILL EVENTUALLY OVERFLOW (AFTER 200+ YEARS OR
// SO), AFTER WHICH POINT THEY WILL HAVE *SIGNED OVERFLOW*, WHICH IS UNDEFINED BEHAVIOR (IE: A BUG) FOR C/C++.
// But...that's ok...this "bug" is designed into the C++11 specification, so whatever. Your machine won't run for 200
// years anyway...

// Get time stamp in milliseconds.
uint64_t millis()
{
    uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::
                  now().time_since_epoch()).count();
    return ms; 
}

// Get time stamp in microseconds.
uint64_t micros()
{
    uint64_t us = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::
                  now().time_since_epoch()).count();
    return us; 
}

// Get time stamp in nanoseconds.
uint64_t nanos()
{
    uint64_t ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::
                  now().time_since_epoch()).count();
    return ns; 
}
Run Code Online (Sandbox Code Playgroud)

* (抱歉,我更像是一名嵌入式开发人员,而不是标准的计算机程序员,所以所有这些高级抽象静态成员内类内命名空间内命名空间内命名空间内的东西让我感到困惑。唐别担心,我会好起来的。)

问:为什么std::chrono

A:因为 C++ 程序员喜欢对事物发疯,所以他们让它为你处理单元。以下是一些 C++ 怪异之处和std::chrono. 参考此页面:https : //en.cppreference.com/w/cpp/chrono/duration

在此处输入图片说明

因此,您可以声明一个 1 秒的变量并将其更改为微秒,而无需像这样进行强制转换:

// Create a time object of type `std::chrono::seconds` & initialize it to 1 sec
std::chrono::seconds time_sec(1); 
// integer scale conversion with no precision loss: no cast
std::cout << std::chrono::microseconds(time_sec).count() << " microseconds\n";
Run Code Online (Sandbox Code Playgroud)

你甚至可以像这样指定时间,在我看来,这太奇怪了,而且太过分了。C++14 从字面上重载了字符msusns等作为函数调用运算符来初始化std::chrono各种类型的对象,如下所示:

在此处输入图片说明

auto time_sec = 1s; // <== notice the 's' inside the code there to specify 's'econds!
// OR:
std::chrono::seconds time_sec = 1s;
// integer scale conversion with no precision loss: no cast
std::cout << std::chrono::microseconds(time_sec).count() << " microseconds\n";
Run Code Online (Sandbox Code Playgroud)

以下是更多示例:

std::chrono::milliseconds time_ms = 1ms;
// OR:
auto time_ms = 1ms;

std::chrono::microseconds time_us = 1us;
// OR:
auto time_us = 1us;

std::chrono::nanoseconds time_ns = 1ns;
// OR:
auto time_ns = 1ns;
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我更愿意简化语言并执行此操作,就像我已经做的那样,并且在此之前几十年来在 C 和 C++ 中都已完成:

// Notice the `_sec` at the end of the variable name to remind me this 
// variable has units of *seconds*!
uint64_t time_sec = 1; 
Run Code Online (Sandbox Code Playgroud)

这里有一些参考:

  1. 时钟类型(https://en.cppreference.com/w/cpp/chrono):
    1. system_clock
    2. steady_clock
    3. high_resolution_clock
    4. utc_clock
    5. tai_clock
    6. gps_clock
    7. file_clock
    8. 等等。
  2. 在 C++ 中获得准确的执行时间(微秒)(@OlivierLi 的回答)
  3. http://en.cppreference.com/w/cpp/chrono/time_point/time_since_epoch
  4. http://en.cppreference.com/w/cpp/chrono/duration - 显示小时、分钟、秒、毫秒等类型
  5. http://en.cppreference.com/w/cpp/chrono/system_clock/now

我需要继续观看的视频:

  1. CppCon 2016:Howard Hinnant “A ?chrono? 教程”

有关的:

  1. 我的 3 组时间戳函数(相互交叉链接):
    1. 对于C 时间戳,请在此处查看我的答案:Get a timestamp in C in microseconds?
    2. 对于C++ 高分辨率时间戳,请在此处查看我的答案:在 C++ 中获得准确的执行时间(微秒)
    3. 对于Python 高分辨率时间戳,请在此处查看我的答案:如何在 Python 中获取毫秒和微秒分辨率的时间戳?

附录

更多关于“用户定义的文字”(C++11 起)

operator"" mysuffix()操作者过载/用户定义字面/后缀功能(如C ++ 11的)是如何奇怪auto time_ms = 1ms;事情的作品的上方。写作1ms实际上是一个函数调用功能operator"" ms(),用1在传递作为输入参数,就好像你写一个函数调用是这样的:operator"" ms(1)。要了解有关此概念的更多信息,请参阅此处的参考页面:cppreference.com:用户定义的文字(C++11 起)

这是定义用户定义的文字/后缀函数的基本演示,并使用它:

// 1. Define a function
// used as conversion from degrees (input param) to radians (returned output)
constexpr long double operator"" _deg(long double deg)
{
    long double radians = deg * 3.14159265358979323846264L / 180;
    return radians;
}

// 2. Use it
double x_rad = 90.0_deg;
Run Code Online (Sandbox Code Playgroud)

为什么不使用更像的东西double x_rad = degToRad(90.0);(就像几十年来在 C 和 C++ 中所做的那样)?我不知道。我猜这与 C++ 程序员的想法有关。也许他们正试图让现代 C++ 更加 Pythonic。

这种魔法也是潜在非常有用的 C++fmt库的工作原理,这里是:https : //github.com/fmtlib/fmt。它由Victor Zverovich编写,他也是 C++20's std::format. 您可以在detail::udl_formatter<char> operator"" _format(const char* s, size_t n) 此处查看该函数的定义。它的用法是这样的:

"Hello {}"_format("World");
Run Code Online (Sandbox Code Playgroud)

输出:

你好,世界

这会将"World"字符串插入到所在的第一个字符串中{}。这是另一个例子:

"I have {} eggs and {} chickens."_format(num_eggs, num_chickens);
Run Code Online (Sandbox Code Playgroud)

示例输出:

我有 29 个鸡蛋和 42 只鸡。

这与Python 中的str.format字符串格式非常相似。在此处阅读 fmt lib 文档。

  • 多年后,即使在专业使用 C++ 几个月后,我仍然对 C++ 引入的秒、毫秒、微秒和纳秒(以及许多其他事物)等简单事物的不必要的复杂性感到绝对难以置信。 (2认同)
  • 您可以使用 Y 语言来使用 X 语言惯用语进行编程,但这可能会变得一团糟。用任意两种语言代替 X 和 Y,这就是事实。在本例中是 C 和 C++。这是如何正确使用 `&lt;chrono&gt;` 的一个很好的例子:/sf/answers/4161262731/ 使其成为一个好例子的最大特征是不会不断地将 chrono 类型系统转义为整数类型。 (2认同)

Sun*_*lly 7

如果您正在查看从Unix shell执行程序所消耗的时间,请使用Linux 时间,如下所示,

time ./a.out 

real    0m0.001s
user    0m0.000s
sys     0m0.000s
Run Code Online (Sandbox Code Playgroud)

其次,如果你想在程序代码(C)中执行多少语句,请尝试使用gettimeofday(),如下所示,

#include <sys/time.h>
struct timeval  tv1, tv2;
gettimeofday(&tv1, NULL);
/* Program code to execute here */
gettimeofday(&tv2, NULL);
printf("Time taken in execution = %f seconds\n",
     (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
     (double) (tv2.tv_sec - tv1.tv_sec));
Run Code Online (Sandbox Code Playgroud)

  • 使用 clock_gettime() 代替 - 手册页说 - gettimeofday() 返回的时间受系统时间不连续跳跃的影响(例如,如果系统管理员手动更改系统时间)。如果您需要单调递增的时钟,请参阅clock_gettime(2)。Opengroup 说 - 应用程序应该使用 clock_gettime() 函数而不是过时的 gettimeofday() 函数。&lt;&lt; (3认同)

归档时间:

查看次数:

43765 次

最近记录:

6 年,1 月 前