TLDR:您可以很好地了解毫秒分辨率的热点,但由于各种原因,纳秒分辨率不起作用。
您可能可以找到或编写一些函数,为您提供计算机所能提供的最佳分辨率,但是,这仍然不能为您提供任何有意义的结果:
auto start = getBestPrecisionTime();
foo();
auto end = getBestPrecisionTime();
std::cout << "foo took " << to_nanoseconds(end - start) << "ns";
第一个问题是foo() 被另一个程序中断,而您实际上不是在测量foo(),而是foo() + some_random_service。解决这个问题的一种方法是进行 1000 次测量,希望其中至少有一次没有被打断,并采取这些测量中的最小值。根据foo() 实际花费的时间,您的机会从永远到永远。
同样,foo() 可能会访问位于 1/2/3/4 级缓存、RAM 或硬盘驱动器中某处的内存,因此您再次测量错误。您需要获取真实世界的数据,说明foo() 需要的内存在哪个内存中以及具有哪些访问时间的可能性有多大。
另一个主要问题是优化。衡量调试版本的性能没有多大意义,因此您需要在启用最大优化的情况下进行衡量。具有高优化级别的编译器将重新排序和内联代码。 getBestPrecisionTime 函数有两个选项: 允许编译器将代码移过或不移过它。如果它允许重新排序,编译器会这样做:
foo();
auto start = getBestPrecisionTime();
auto end = getBestPrecisionTime();
std::cout << "foo took " << to_nanoseconds(end - start) << "ns";
然后进一步优化到
std::cout << "foo took 0ns";
显然,这会产生错误的结果,并且我遇到的所有计时功能都会添加障碍以禁止这样做。
但替代方案也好不到哪里去。如果没有测量,编译器可能会对此进行优化
foo();
bar();
进入
code_that_does_foo_bar;
由于更好地利用了寄存器/SIMD 指令/缓存/...,因此效率更高。但是,一旦您测量了性能,您就禁用了此优化并且测量了错误的版本。经过大量工作,您可能能够提取出code_that_does_foo_bar 中的哪些汇编指令源自foo(),但由于您甚至无法准确判断一条汇编指令需要多长时间,而且该时间还取决于您拥有的周围的汇编指令没有机会获得优化代码的准确数字。
你能做的最好的就是使用std::chrono::high_resolution_clock,因为它并没有变得更精确。