如何找到锁定Linux futex的C ++行? 但是请注意,死锁或与同步相关的错误是典型的heisenbugs。

使用C ++编写的大型应用程序存在性能问题。该程序仅使用150%的CPU,而服务器是24核超线程EPYC,其他类似应用程序可以可靠地达到预期的4800%CPU负载。 iotop实际上没有显示任何I / O,这是预期的。

由于该程序显然既不受I / O约束,也不受CPU约束,因此我检查了strace,发现绝大多数跟踪调用都是在单个futex上等待。就是说:程序中的50个线程中有48个似乎锁定了相同的线程,这很好地解释了为什么CPU负载仅勉强超过100%。

示例:

[pid 11581] futex(0x55acec47a900,FUTEX_WAIT_PRIVATE,2,NULL <unfinished ...>
[pid 11580] futex(0x55acec47a900,NULL <unfinished ...>
[pid 11579] futex(0x55acec47a900,NULL <unfinished ...>
[pid 11578] futex(0x55acec47a900,NULL <unfinished ...>
[pid 11577] futex(0x55acec47a900,NULL <unfinished ...>
[pid 11576] futex(0x55acec47a900,NULL <unfinished ...>

现在对我来说,问题是:如何找到有问题的代码?该程序不是死锁,只是速度很慢,因此查找死锁的常用技术不起作用。

iCMS 回答:如何找到锁定Linux futex的C ++行? 但是请注意,死锁或与同步相关的错误是典型的heisenbugs。

我发现自己最好的方法是在GDB中运行该程序。由于大多数线程被阻止,因此info threads将显示大多数处于相同状态的线程。对我来说,这恰好在__lll_lock_wait中被阻止。切换到这些线程中的任何一个都给了我一个堆栈跟踪,显示了我如何以__lll_lock_wait结尾。在堆栈的三个级别上,我找到了令人反感的代码。

,

我如何找到锁定Linux futex的C ++行?

如果您接受更改 C ++源代码,则可以使用 recent 将其与g++ -O -g(因此,与DWARF调试信息一起)进行编译。 > GCC编译器,并使用Ian Taylor的libbacktrace。该库在运行时使用ELF executableshared libraries中的DWARF调试信息提供了很好的回溯信息。

然后,您可以将locking C++ classes子类化(例如std::mutexstd::lock_guard)或添加额外的C ++代码(也许使用preprocessor X-macros)来使用它回溯库。

还考虑使用GNU gprof进行概要分析。

另一种可能的方法(仅对于超过十万行C ++的大型代码库才有价值)可能是使用动态链接器技巧(例如LD_PRELOAD,请参见ld.so(8))来重新定义C ++标准库,或者编写GCC plugin来修改与futex(7)locking C++ classes相关的代码。

对于较小的代码库,还可以考虑编写专门的metaprogram(本着Qt moc的精神)来转换C ++代码(例如,自动向libbacktrace函数添加C ++调用)然后更新您的build automation(例如您的Makefile)以使用它。

举一个具体的例子,研究一下GCC的源代码

但是请注意,死锁或与同步相关的错误是典型的heisenbugs

因此,请花几周的调试时间。

本文链接:https://www.f2er.com/1937376.html

大家都在问