是否有一种方法可以避免Google性能工具将文件列表为“?:?”,即找不到包含它报告的函数的文件?如何计算出包含正在调用的函数的哪个库?
$ env LD_PRELOAD="/usr/lib/libprofiler.so.0" \
CPUPROFILE=output.prof python script.py
$ google-pprof --text --files /usr/bin/python output.prof
Using local file /usr/bin/python.
Using local file output.prof.
Removing _L_unlock_13 from all stack traces.
Total: 433 samples
362 83.6% 83.6% 362 83.6% dtrsm_ ??:?
58 13.4% 97.0% 58 13.4% dgemm_ ??:?
1 0.2% 97.2% 1 0.2% PyDict_GetItem /.../Objects/dictobject.c
1 0.2% 97.5% 1 0.2% PyParser_AddToken /.../Parser/parser.c
...我的目标是能够在一个包含许多编译C扩展模块的python包中分析C代码。在上面的玩具示例中,我要做什么来跟踪"dtrsm_“是在哪里定义的?如果有多个加载的库包含具有相同名称的函数,是否有任何方法可以判断正在调用哪个版本?
发布于 2015-09-07 17:24:50
如果相同的预处理源文件(例如包含扩展的#)包含相同符号的重复定义,C/C++将不会编译。(请注意,在C++的情况下,根据编译器特定的方案,符号会被损坏,以合并参数签名,以便于重载函数,否则无法区分。)
链接器只关注未解决的符号(因此不应该有任何事情阻止多个库同时调用它们各自的内部定义函数,并使用符合的名称)。如果一个文件调用了一个已声明但未定义的函数,并且多个可用库实现了这个符号,那么链接器就可以自由地选择哪个版本在搜索路径中被替换(比如搜索路径中的优先级)。(顺便说一句,这也是分析器(如gperftools或hpctoolkit )能够注入自己并改变另一个应用程序的正常行为的相同机制。)
由于不同的库被映射到不同的内存页,所以应该能够识别(从内存地址)包含函数的执行版本的库。实际上,GNU调试器可以识别代码所包含的库,即使它无法命名函数。
$ gdb python
(gdb) run -c "from numpy import *; linalg.inv(random.random((1000,1000)))"
CTRL-C
(gdb) backtrace
#0 0x00007ffff5ba9df8 in dtrsm_ () from /usr/lib/libblas.so.3
...
#3 0x00007ffff420df83 in ?? () from /.../numpy/linalg/_umath_linalg.soLinux (或者更确切地说是GNU库)提供了“回溯”调用(用于从调用堆栈获取指针列表),以及用于自动将每个指针转换为描述性字符串的"backtrace_symbols“调用,如:
"/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fc429929ec5]"Gperftools (从github镜像上的查询判断)可以调用通用的“回退跟踪”,但不是"backtrace_symbols“,而是”分叉到pprof来执行实际的符号化“。这是一个相当史诗式的perl脚本,看起来很可能在哪里“?”来自于。
关键的是,google-pprof试图报告定义函数的源文件(和行号),而不是包含机器代码的二进制文件(通常在堆栈跟踪中引用)。它调用"nm“实用程序。在我的系统中(通过运行"nm -l -D"),与libc和python二进制不同的是,libblas已经删除了这样的调试符号(可能是为了优化),从而解释了结果。
要回答最初的问题:调用堆栈示例应该明确和明确地指定要调用的版本。可以使用几个月前在google中添加的选项来转储这些数据,或者(对于时间密集型的函数)可以通过使用gdb进行手动重采样来粗略确定。(甚至可以想象,可以调整g-pprof,以显式地标识输出摘要中的二进制路径。)或者,您可以在候选二进制文件/库上运行"nm“(和grep) (其中一个短列表可以通过对分析器的原始输出运行”字符串“来获得,以及其他方法)。如果源是可以访问的( grep)或者库是流行的(在网络上),那么当然(并且按照Mike ),只查询函数名可能是最简单的。理论上"??:?“可以通过仔细重新编译违规对象来解决。
发布于 2015-08-31 21:26:46
只需搜索令人反感的函数名。上面显示的内容在LAPACK中定义。dtrsm用于求解矩阵方程。dgemm用于乘矩阵。
你需要知道的是: 1)为什么要调用它们,2)矩阵有多大。
为了找出它们被调用的原因,我只需要检查单个堆栈样本,https://stackoverflow.com/a/4299378/23771。
矩阵大小重要的原因是,如果它们很小,这些LAPACK例程实际上可以花费相当大一部分时间来分类它们的输入,例如调用函数LSAME。
https://stackoverflow.com/questions/31352682
复制相似问题