【发布时间】:2015-05-12 21:44:15
【问题描述】:
(注:以下提及execinfo/
backtrace,但这只是一个例子。问题中的行为出现在各种库中。)
考虑一个实用程序库,它跟踪与其链接的某些应用程序的资源分配。当函数分配和释放资源时,它们调用一个跟踪函数,该函数记录操作的细节,以及一些可用于重构调用路径的信息。有时,会通过调用路径查询库以获取操作细分。
在本题的设置中,要求跟踪是低开销的,但查询不一定。因此,为了跟踪,我存储了标识调用路径的最少信息,例如,通过调用execinfo/
backtrace。翻译符号、拆解等等,都被推迟到查询中,而不是这个问题的一部分。
令我惊讶的是,与 malloc 调用相比,简单地调用 backtrace 会使执行速度减慢 ~4000%(!)。由于backtrace 将请求的(最大)堆栈深度作为参数,并且可以通过具有不同堆栈深度的调用路径调用它,因此我试图了解这些参数如何影响其性能。据我所知,以任何方式简单地调用此函数都会产生巨大的损失。
对于测量,我编写了以下简单代码(另请参阅full version):
const size_t max_backtrace_size = 100;
void *backtrace_buf[max_backtrace_size];
static void track()
{
if(backtrace_size > 0)
::backtrace(backtrace_buf, backtrace_size);
}
static void op(size_t i)
{
if(i == 0)
{
track();
return;
}
op(i - 1);
}
这两个函数中的第一个,track,模拟实际跟踪(注意backtrace_size == 0 完全禁用对backtrace 的调用);第二个,op 是一个通过调用track 终止的递归。使用这两个函数,我改变了参数并测量了结果(另见the IPython Notebook)。
下图显示了跟踪时间,作为不同堆栈大小的函数,对于每个调用backtrace 和backtrace_size == 1 或不调用它(它的时间太短以至于它位于X 轴上,并且可以图中几乎看不到)。 backtrace 即使使用小参数调用也会产生巨大的开销。
下图进一步显示了开销,现在作为回溯大小和堆栈深度的函数。同样,只要调用这个函数就会有一个巨大的跳跃。
是否有任何技术方法可以减少查找回溯的开销? (可能是不同的库,或不同的构建设置。)
在没有 1. 的情况下,是否有完全不同的可行替代方案来解决顶部问题?
【问题讨论】:
标签: c++ linux g++ profiling glibc