为啥我在分析器中看到 __scalbnf?
Posted
技术标签:
【中文标题】为啥我在分析器中看到 __scalbnf?【英文标题】:Why do I see __scalbnf in my profiler?为什么我在分析器中看到 __scalbnf? 【发布时间】:2018-07-02 15:38:17 【问题描述】:我正在使用perf
分析一些C++ 代码,我看到__scalbnf
和__wrap_scalbnf
占用了很大一部分运行时间。我查看了这些函数是什么,我最好的猜测是我通过调用std::exp
来调用它们。但是,我希望能够确认这一点。有没有地方我可以看到实现 std::exp 的 C++ 代码来确认这一点?或者我(C++ 业余爱好者)开始深入研究并了解正在发生的事情的最佳方式是什么?
谢谢。
【问题讨论】:
好吧,如果您使用的是 libstdc++ 或 libc++,您可以检查他们的代码。您还可以使用调试器单步执行代码。 添加一个断点,然后在调试器中运行直到它中断,查看调用堆栈以找到最后一个已知函数 clang libcxx 源代码在这里:github.com/llvm-mirror/libcxx 但是看起来 std::exp 使用 c 函数 exp expf expl 所以阅读 c++ 代码无济于事...... 【参考方案1】:在__scalbn
上设置断点。运行你的程序。查看回溯(在 GDB 中,bt
)。调用树将显示exp()
是__scalbn
的父函数。
如果一个函数有多个调用者,第一个命中可能不是来自您正在分析的“热”函数。
要真正弄清楚哪个更高层函数(包括它的子函数)占用了大量时间,请参阅linux perf: how to interpret and find hotspots。自上而下的分析可以找到昂贵的函数,这些函数在调用其他函数时完成所有工作,即使这些其他函数也有“无辜”的调用者。 (例如,memcpy
被大量使用并且通常是不可避免的,但您想要找到的是使用它的调用者过多并且可以更好地优化。或者根本不调用。)
顺便说一句,是的 glibc 的数学库 exp()
实现确实在内部使用 __scalbn
。我不确定实现有多糟糕,但我没有看到 x86-64 的 asm 版本,只有这个纯 C 版本。 https://code.woboq.org/userspace/glibc/sysdeps/ieee754/dbl-64/wordsize-64/s_scalbn.c.html。 (对于__scalbnl(long double)
,有https://code.woboq.org/userspace/glibc/sysdeps/x86_64/fpu/s_scalbnl.S.html,对80 位浮点数使用x87 fscale
指令。但是对于其他大小,只有i386 asm 文件。和IA-64(安腾),但不是x86-64)。
不过,glibc 确实有一些矢量化 EXP 代码,例如 SSE4 SVML 版本 https://code.woboq.org/userspace/glibc/sysdeps/x86_64/fpu/multiarch/svml_d_exp2_core_sse4.S.html#_ZGVbN2v_exp_sse4。
如果您想要更高性能的 exp()
而没有完美的准确性,请参阅 Fastest Implementation of Exponential Function Using AVX(这是 float
,而不是 double
。我忘记了是否有双重版本的 SO 答案)。
还相关:Efficient implementation of log2(__m256d) in AVX2。
【讨论】:
【参考方案2】:要确认std::exp
是__scalbnf
和__wrap_scalbnf
的原因,您可以将std::exp
调用替换为:
那么,如果您在分析器输出中仍然看到 __scalbnf
和 __wrap_scalbnf
,则表示它不是来自 std::exp。
【讨论】:
以上是关于为啥我在分析器中看到 __scalbnf?的主要内容,如果未能解决你的问题,请参考以下文章