我想在用 C++ 实现的程序的微秒内获得准确的执行时间。我试图用clock_t 获得执行时间,但它不准确。
(请注意,微基准测试 _很难_。准确的计时器只是为短时间区域获得有意义的结果所必需的一小部分。有关一些更一般的警告,请参阅 Idiomatic way of performance evaluation? )
原文由 user3323616 发布,翻译遵循 CC BY-SA 4.0 许可协议
我想在用 C++ 实现的程序的微秒内获得准确的执行时间。我试图用clock_t 获得执行时间,但它不准确。
(请注意,微基准测试 _很难_。准确的计时器只是为短时间区域获得有意义的结果所必需的一小部分。有关一些更一般的警告,请参阅 Idiomatic way of performance evaluation? )
原文由 user3323616 发布,翻译遵循 CC BY-SA 4.0 许可协议
新的 C++11 std::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;
}
\* (对不起,我更像是一个嵌入式开发人员,而不是标准的计算机程序员,所以所有这些高级的、抽象的 static-member-within-class-within-namespace-within-namespace-within-namespace 的东西让我感到困惑。唐放心,我会好起来的。)
std::chrono
?A:因为 C++ 程序员喜欢为事情发疯,所以他们让它为你处理单元。以下是一些 C++ 怪异和使用 std::chrono
的案例。参考这个 cppreference 社区 wiki 页面: 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";
你甚至可以像这样指定时间,在我看来,这非常奇怪而且太过分了。 C++14 has literally overloaded the characters ms
, us
, ns
, etc. as function call operators to initialize std::chrono
objects of像这样的各种类型:
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";
Here are some more examples:
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;
就个人而言,我 宁愿 简化语言并这样做,就像我已经做过的那样,并且在这之前的几十年里,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;
system_clock
steady_clock
high_resolution_clock
utc_clock
tai_clock
gps_clock
file_clock
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;
为什么不直接使用类似 double x_rad = degToRad(90.0);
的东西(就像几十年来在 C 和 C++ 中所做的那样)?我不知道。这与我猜想的 C++ 程序员的方式有关。也许他们正试图让现代 C++ 更加 Pythonic。
这种魔力也是潜在非常有用的 C++ fmt
库的工作原理,这里: https ://github.com/fmtlib/fmt。它由 Victor Zverovich 编写,他也是 C++20 的 std::format
的作者。您可以在 此处查看 函数 detail::udl_formatter<char> operator"" _format(const char* s, size_t n)
的定义。它的用法是这样的:
"Hello {}"_format("World");
输出:
你好世界
这 "World"
{}
的第一个字符串中。这是另一个例子:
"I have {} eggs and {} chickens."_format(num_eggs, num_chickens);
样本输出:
我有 29 个鸡蛋和 42 只鸡。
这与 Python 中的 str.format 字符串格式化非常相似。在 此处 阅读 fmt lib 文档。
原文由 Gabriel Staples 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答1.6k 阅读✓ 已解决
2 回答1.2k 阅读✓ 已解决
1 回答1.1k 阅读✓ 已解决
2 回答615 阅读✓ 已解决
1 回答2.1k 阅读
1 回答793 阅读✓ 已解决
3 回答1.2k 阅读
如果您使用的是 c++11 或更高版本,则可以使用
std::chrono::high_resolution_clock
。一个简单的用例:
该解决方案具有便携性的优点。
请注意, 微基准测试很难。很容易测量错误的东西(比如你的基准优化掉了),或者在你的定时区域中包含页面错误,或者没有考虑 CPU 频率空闲与 turbo。
请参阅 绩效评估的惯用方式? 对于一些一般提示,例如,通过首先测试另一个来检查是否会改变哪个看起来更快。