概要分析:一行简单代码的自我时间与总时间

Profiling: Self time vs Total time for a simple line of code

在分析时,我们知道 'self time' 表示方法花费的时间忽略它调用的函数,而 'total time' 表示该方法及其子函数被调用的总时间。

我有一个简单的函数,我只对数组进行计算而不调用内部的任何其他函数。但是,在分析时,self 和 total 的时间对于函数本身以及函数的每一行都是完全不同的。这是来自 Zoom Profiler 的示例分析线,运行 有 32 个线程。

for循环中行的时机

Total        Self         Code
29.4 sec     16.9 sec     id=*(pid); 

令我困惑的是,根据第一段应该是说,如果一行代码没有调用任何方法,那么自用时间和总用时应该是相同的。 对正在发生的事情有什么想法吗?

我不会太担心那个。

分析器显示的统计数据,即使是好的分析器,也必须使用 "with a grain of salt"。 这些统计数据表明,在某些包含该行代码的堆栈示例中,它不是堆栈中的最后一行代码,这很难相信。 更容易相信探查器是错误的。 如今,随着处理器的管道 运行 遥遥领先,这可能会让人非常困惑。

无论如何,如果您进行概要分析的原因是为了寻找加速,则很难看出如何加速该特定代码行。 您正在寻找 可以 加速的东西,而不是 不能 的东西。

顺便说一句,我建议不要看秒或毫秒或任何绝对时间测量,而是看小数时间 - 时间除以总时间。 真正的加速往往占更大的比例,从 5% 到 99%。 此外,不要打扰自己的时间 - 包含时间包括它,如果程序有任何重要的大小,那么堆栈样本会变深,堆栈样本上的非终端行(即函数调用)是一个丰富的狩猎加速的基础。 最后,不需要测量精度,所以不需要大量的样本。

这就是很多人使用 this technique 的原因。


编辑:FWIW,这就是我的意思。这里有 5 个随机时间堆栈示例:

---------------------------
... some calls above
... exp(4.02) ...
... some calls below
---------------------------
... some calls above
... exp(0.35) ...
... some calls below
---------------------------
... some calls above
... push_back(...) ...
...
... new ...
...
---------------------------
...
... myArray[...]
...
---------------------------
... some calls above
... exp(0.35) ...
... some calls below
---------------------------

其中三个在堆栈上、您的代码中或您可以编辑的代码中调用了 exp,很可能来自代码中的不同位置。 这意味着您花费大约 60% 的时间调用 exp。 你不能加速那个函数,但你能不能少调用它?

现在请注意,第二个和第五个示例使用相同的数字参数调用 exp。 (这是任何分析器都无法告诉你的。) 那是什么意思? 这意味着大约 40% 的时间是在 exp 调用重复参数, 您可以通过记住先前的值或通过记忆 exp.

来避免这种情况

如果您进行采样,直到您看到某种您可以采取措施的模式,并且您看到它 两次或更多次,您就获得了健康的加速。 达到该点所需的样本越少,加速越大。 然后你可以重复整个过程,直到你不能再做为止。 这是获得难以超越的速度的可靠方法。