通过 clang++ 的 -finstrument-functions 进行 C++ 函数检测:如何忽略内部标准库调用?
C++ function instrumentation via clang++'s -finstrument-functions : how to ignore internal std library calls?
假设我有这样一个函数:
template<typename It, typename Cmp>
void mysort( It begin, It end, Cmp cmp )
{
std::sort( begin, end, cmp );
}
当我使用 -finstrument-functions-after-inlining
和 clang++ --version
编译它时:
clang version 11.0.0 (...)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: ...
工具代码使执行时间爆炸,因为每次调用
都会调用我的进入和退出函数
void std::__introsort_loop<...>(...)
void std::__move_median_to_first<...>(...)
我正在对一个非常大的数组进行排序,所以我的程序没有完成:没有检测需要大约 10 秒,使用检测我在 10 分钟后取消了它。
我已经尝试将 __attribute__((no_instrument_function))
添加到 mysort
(以及调用 mysort
的函数),但这似乎对这些标准库没有影响通话有关。
有谁知道是否可以忽略像 std::sort
这样的标准库函数内部的函数检测?理想情况下,我只会 mysort
进行检测,因此一次进入和一次退出!
我很遗憾地看到 clang++
还不支持 finstrument-functions-exclude-function-list
或 finstrument-functions-exclude-file-list
之类的东西,但是 g++
还不支持 -finstrument-functions-after-inlining
我会的理想情况下有,所以我卡住了!
编辑:玩多了之后,似乎对执行时间的影响实际上比描述的要小,所以这不是世界末日。然而,问题仍然存在,因为大多数在 clang
中进行函数检测的人只关心应用程序代码,而不关心那些从(例如)标准库链接的函数。
EDIT2:现在我已经在合理的时间范围内 运行 解决了这个问题,为了进一步强调这个问题:我使用这两个标准库函数从检测代码生成的跟踪结果是 15GB。当我对跟踪进行硬编码以忽略这两个函数地址时,生成的跟踪为 3.7MB!
我 运行 遇到了同样的问题。似乎曾经提出过支持这些标志,但从未合并到主分支中。
https://reviews.llvm.org/D37622
这不是一个直接的答案,因为该工具不支持你想做的事情,但我认为我有一个不错的 work-around。我最后做的是创建一个“跳过列表”之类的。在检测函数(__cyg_profile_func_enter
和 __cyg_profile_func_exit
)中,我猜对执行时间贡献最大的部分是打印。如果您能想出一种 short-circuiting 配置文件功能的方法,那应该会有所帮助,即使它不是最理想的。至少它会限制输出文件的大小。
类似
#include <stdint.h>
uintptr_t skipAddrs[] = {
// assuming 64-bit addresses
0x123456789abcdef, 0x2468ace2468ace24
};
size_t arrSize = 0;
int main(void)
{
...
arrSize = sizeof(skipAddrs)/sizeof(skipAddrs[0]);
//
...
}
void __cyg_profile_func_enter (void *this_fn, void *call_site) {
for (size_t idx = 0; idx < arrSize; idx++) {
if ((uintptr_t) this_fn == skipAddrs[idx]) {
return;
}
}
}
我使用 objdump -t binaryFile
之类的东西来检查符号 table 并找到每个函数的地址。
如果您特别想忽略库调用,可能有用的方法是在链接到库之前检查目标文件的符号 table,然后忽略所有在最终文件中出现的新文件二进制。
所有这些都应该可以通过 grep
、awk
或 python
.
之类的东西实现
您必须向不应检测的函数添加属性 __attribute__((no_instrument_function))
。不幸的是,要使其与 C/C++ 标准库函数一起使用并不容易,因为此功能需要编辑所有 C++ 库函数。
您可以采取一些技巧,例如 #define
来自 include/__config 的现有宏来添加此属性。例如,
-D_LIBCPP_INLINE_VISIBILITY=__attribute__((no_instrument_function,internal_linkage))
确保使用 no_instrument_function
附加现有宏定义以避免意外错误。
假设我有这样一个函数:
template<typename It, typename Cmp>
void mysort( It begin, It end, Cmp cmp )
{
std::sort( begin, end, cmp );
}
当我使用 -finstrument-functions-after-inlining
和 clang++ --version
编译它时:
clang version 11.0.0 (...)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: ...
工具代码使执行时间爆炸,因为每次调用
都会调用我的进入和退出函数void std::__introsort_loop<...>(...)
void std::__move_median_to_first<...>(...)
我正在对一个非常大的数组进行排序,所以我的程序没有完成:没有检测需要大约 10 秒,使用检测我在 10 分钟后取消了它。
我已经尝试将 __attribute__((no_instrument_function))
添加到 mysort
(以及调用 mysort
的函数),但这似乎对这些标准库没有影响通话有关。
有谁知道是否可以忽略像 std::sort
这样的标准库函数内部的函数检测?理想情况下,我只会 mysort
进行检测,因此一次进入和一次退出!
我很遗憾地看到 clang++
还不支持 finstrument-functions-exclude-function-list
或 finstrument-functions-exclude-file-list
之类的东西,但是 g++
还不支持 -finstrument-functions-after-inlining
我会的理想情况下有,所以我卡住了!
编辑:玩多了之后,似乎对执行时间的影响实际上比描述的要小,所以这不是世界末日。然而,问题仍然存在,因为大多数在 clang
中进行函数检测的人只关心应用程序代码,而不关心那些从(例如)标准库链接的函数。
EDIT2:现在我已经在合理的时间范围内 运行 解决了这个问题,为了进一步强调这个问题:我使用这两个标准库函数从检测代码生成的跟踪结果是 15GB。当我对跟踪进行硬编码以忽略这两个函数地址时,生成的跟踪为 3.7MB!
我 运行 遇到了同样的问题。似乎曾经提出过支持这些标志,但从未合并到主分支中。
https://reviews.llvm.org/D37622
这不是一个直接的答案,因为该工具不支持你想做的事情,但我认为我有一个不错的 work-around。我最后做的是创建一个“跳过列表”之类的。在检测函数(__cyg_profile_func_enter
和 __cyg_profile_func_exit
)中,我猜对执行时间贡献最大的部分是打印。如果您能想出一种 short-circuiting 配置文件功能的方法,那应该会有所帮助,即使它不是最理想的。至少它会限制输出文件的大小。
类似
#include <stdint.h>
uintptr_t skipAddrs[] = {
// assuming 64-bit addresses
0x123456789abcdef, 0x2468ace2468ace24
};
size_t arrSize = 0;
int main(void)
{
...
arrSize = sizeof(skipAddrs)/sizeof(skipAddrs[0]);
//
...
}
void __cyg_profile_func_enter (void *this_fn, void *call_site) {
for (size_t idx = 0; idx < arrSize; idx++) {
if ((uintptr_t) this_fn == skipAddrs[idx]) {
return;
}
}
}
我使用 objdump -t binaryFile
之类的东西来检查符号 table 并找到每个函数的地址。
如果您特别想忽略库调用,可能有用的方法是在链接到库之前检查目标文件的符号 table,然后忽略所有在最终文件中出现的新文件二进制。
所有这些都应该可以通过 grep
、awk
或 python
.
您必须向不应检测的函数添加属性 __attribute__((no_instrument_function))
。不幸的是,要使其与 C/C++ 标准库函数一起使用并不容易,因为此功能需要编辑所有 C++ 库函数。
您可以采取一些技巧,例如 #define
来自 include/__config 的现有宏来添加此属性。例如,
-D_LIBCPP_INLINE_VISIBILITY=__attribute__((no_instrument_function,internal_linkage))
确保使用 no_instrument_function
附加现有宏定义以避免意外错误。