c++ - 使用C时间函数测量时间: are they code-reordering resistant?

标签 c++ c performance time language-lawyer

当我添加一段代码来测量 CPU 执行时间时,例如:

int main()
{
   clock_t init_time = clock(); // (1)
   your_fun(); // (2)
   printf("Seconds: %f", (double)(clock() - init_time) / CLOCKS_PER_SEC); // (3)
}

如果我以完全优化的方式编译那段代码,是否可以将代码重新排序,使 init_time 初始化在 your_fun 之后执行,这样你就什么都不测量了?换句话说,clock 是否有任何内存屏障机制来保护测量 block 不被重新排序?

如果 clock 不是抗重排序的:如果我将 (1) 和 (3) 移动到在不同编译单元中实现的新函数,那么编译器在编译 main, 看不到里面的东西,能不能防止这样的重排序?

我一直有这个问题,因为我通常会看到等待执行的时间(秒)与打印的执行时间(毫秒甚至 0)之间相互矛盾的执行时间。

C++ 时钟或本地时间函数怎么样?他们有类似的问题吗?

最佳答案

对时间读取函数的调用是系统调用:测量将准确地发生在正确的位置,相对于其他系统调用,包括 I/O 操作。这不是您要的:您正在为一个纯操作计时,一个没有 SE(副作用)的计算。

您希望计算恰好发生在两个系统调用之间的正确位置;您需要订购它,而不是完全优化它。

像往常一样,要阻止优化,请使用volatile:所有volatile操作都是副作用,就像一个系统调用(比如调用readwrite)。

注意:您可能指望真正的单独编译来达到同样的效果;那是如果您确定不会应用全局程序优化。

根据定义,副作用永远无法重新排序。此外, volatile 读取具有不确定的值,即使是常量也是如此:

const volatile int indeterminate_zero = 0;

任何表达式中 indeterminate_zero 的每个实例都会产生编译器无法假定为 0 的 0。

您需要将计算与副作用放在一起,并使其依赖于未知值,以便计算准确地发生在您想要的位置。

在正确的位置插入 volatile 操作将以普通内存读取或写入的微不足道的成本做到这一点:对 volatile 全局整数类型的操作与常规(非 volatile)的成本完全一样) 在几乎所有编译器上禁用优化的类似操作。

重要的是,您将 volatile 读取视为特殊的 scanf 并将写入视为特殊的 printf,两者都不与任何 STDIO 流交互,并且它们的成本都极低,并且比调用普通系统调用(如 getpidgetppid、0 字节的 write...)更可移植。

(我没有发布带有可编译代码的完整答案,因为您没有提出带有我可以重新表述的可运行代码的完整问题。)

如果您不想打扰所有这些,只需使用单独的编译即可。所有常用的编译器都支持单独编译(编译器可以合法地强制您一次提交所有代码,但据我所知,没有一个这样做)。

关于c++ - 使用C时间函数测量时间: are they code-reordering resistant?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67370546/

相关文章:

c++ - 如何在 C++ 中重置结构体中的所有变量?

c - 在 Linux 内核中混合汇编和 C 函数 - x64 模式

c - for 循环中的哪个变量的新用户输入

sql - 从SQL Server全文索引中获取前n个最新条目

c++ - 清理窗口套接字内部缓冲区

c++ - 为什么 std::list 上的 push_back 会更改用 rbegin 初始化的反向迭代器?

C++:将 UDP sockaddr 传输到新位置

c - 获取 pthread 的索引,而不将其作为参数传递给函数。

performance - 通过 SQLDeveloper 与应用程序实现的 Oracle 性能

string - R中的快速部分字符串匹配