gpt4 book ai didi

c++ - 在 C++ 中为 std::chrono 时钟设置/暂停时钟时间

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:05:03 29 4
gpt4 key购买 nike

我写了一些东西来衡量我的代码运行需要多长时间,并将其打印出来。我现在拥有的方式支持嵌套这些测量值。

事情是在获取时间间隔,转换成数字,获取时间格式,然后全部转换成字符串,然后打印出来的过程中需要一段时间(2-3毫秒),我/O 尤其显得昂贵。我希望时钟在某种意义上“跳过”这个过程,因为我正在测量的东西将以微秒为单位。 (我认为无论如何,如果我有其他我想跳过的东西,这将是一个很好的功能)

std::chrono::high_resolution_clock clock;
std::chrono::time_point<std::chrono::steady_clock> first, second;

first = clock.now();

std::chrono::time_point<std::chrono::high_resolution_clock> paused_tp = clock.now();
std::cout << "Printing things \n";
clock.setTime(paused_tp); // Something like this is what I want

second = clock.now();

这个想法是为了确保 firstsecond 的差异最小,最好是相同的。

据我所知,high_resolution_clock 类(以及所有其他 chrono 时钟)将它们的 time_point 保密,您只能从 clock.now()

访问它

我知道那里可能有基准测试库可以执行此操作,但我想自己弄清楚如何执行此操作(如果只是为了了解如何执行)。任何关于其他图书馆如何做的信息或关于 chrono 如何工作的见解也将受到赞赏。我可能误解了 chrono 内部如何保持跟踪。

(对于这样的事情,std::chrono::high_resolution_clock 是否足够准确?)

(当我在这里时,如果有任何关于使 C++ 程序更高效的资源,那就太好了)

编辑:我实际上在尝试计时的代码部分之后进行打印,问题只出现在,比如说,当我想要计时整个程序以及单个函数时。然后函数时间的打印会导致整个程序时间的延迟。

编辑 2:我想我应该有更多的例子来说明我在做什么。我有一个可以处理所有事情的类,假设它叫做 tracker,它会处理所有时钟废话。

tracker loop = TRACK(
for(int i = 0; i != 100; ++i){
tracker b = TRACK(function_call());
b.display();
}
)
loop.display();

宏是可选的,它只是一个快速的东西,可以使它不那么困惑,并允许我显示被调用函数的名称。

宏显式展开为

tracker loop = "for(int i = 0; i != 100; ++i){ tracker b = TRACK(function_call()); b.display(); }"
loop.start()
for(int i = 0; i != 100; ++i){
tracker b = "function_call()"
b.start();
function_call();
b.end();
b.display();
}
loop.end();
loop.display();

在大多数情况下,打印不是问题,它只跟踪 start()end() 之间的内容,但这里的 b .display() 最终会干扰 tracker loop

我的一个目标是让跟踪器尽可能地非侵入性,所以我希望大部分/全部都在跟踪器类中处理。但是后来我遇到了 b.display() 是与 tracker loop 不同实例的方法的问题。我尝试了一些使用 static 关键字的方法,但遇到了一些问题(仍在尝试)。我可能已经把自己写进了死胡同,但还有很多事情要尝试。

最佳答案

只需分别对两个时间间隔进行计时并相加,即总共保存 4 个时间戳。对于嵌套间隔,您可能只是将时间戳保存到一个数组中,然后在最后对所有内容进行排序。 (或者在时间戳被覆盖之前的外循环内)。存储到数组中非常便宜。


或者更好:推迟打印。

如果定时间隔只有几毫秒,只需保存您要打印的内容并在定时间隔之外执行。

如果你有嵌套的定时间隔,至少将打印从最里面的间隔中取出,以尽量减少你必须做的停止/重新启动的次数。

如果您在各处手动检测您的代码,也许可以查看性能分析工具,例如 flamegraph,尤其是当您的时间间隔在函数边界上中断时。 linux perf: how to interpret and find hotspots .


不仅 I/O 本身需要时间,它还会使后面的代码运行得更慢数百或数千个周期。进行系统调用会涉及很多代码,因此当您返回时对于用户空间,您可能会得到指令缓存和数据缓存未命中。修改页表的系统调用也会导致 TLB 未命中。

(参见“系统调用的(实际)成本”部分 in the FlexSC paper(Soares,Stumm),在运行 Linux 的 i7 Nehalem 上计时。(第一代 i7,从 ~2008/9 开始)。该论文提出了一个批处理用于高吞吐量 Web 服务器和类似系统的系统调用机制,但除此之外,它们对普通 Linux 的基线结果很有趣且相关。)

在启用了 Meltdown 缓解的现代 Intel CPU 上,您通常会遇到 TLB 未命中。在最近的 x86 上启用 Spectre 缓解措施后,分支预测历史记录可能会被清除,具体取决于缓解策略。 (英特尔添加了一种方法,让内核在这一点之后请求更高权限的分支不会受到较低权限分支的预测历史的影响。在当前的 CPU 上,我认为这只是刷新分支预测缓存。)

您可以通过让 iostream 避免系统调用开销为你缓冲。它仍然是格式化和复制数据的重要工作,但比写入终端便宜得多。 重定向程序的 stdout到一个文件将使cout默认情况下是全缓冲的,而不是行缓冲的。 即像这样运行它:

 ./my_program > time_log.txt

最终输出将与您在终端上获得的输出相匹配,但是(只要您不做任何愚蠢的事情,例如使用 std::endl 强制刷新)它只会被缓冲。默认缓冲区大小可能类似于 4kiB。使用 strace ./my_program或类似的工具来跟踪系统调用,并确保你得到一个大的 write()最后,而不是很多小 write()

避免在(外部)定时区域内缓冲 I/O 会很好,但是避免在您的“真实”(非检测)代码没有它们的地方进行系统调用非常重要,如果您时间精确到纳秒。这甚至在 定时间隔之前也是如此,而不仅仅是在内部。

cout << foo如果它不进行系统调用,就减慢以后的代码而言并不“特殊”。

关于c++ - 在 C++ 中为 std::chrono 时钟设置/暂停时钟时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51995828/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com