可视化每个线程正在运行的函数的工具

Tool to visualize what function each thread is running

本文关键字:运行 函数 工具 线程 可视化      更新时间:2023-10-16

我正在尝试调试多线程C++应用程序的性能问题。基本上,我的多线程程序(10个线程)比单线程程序慢得多。

我一直在尝试valgrind(callgrind)、gprof和gdb等工具。但到目前为止,我还无法弄清楚线程被阻塞的确切位置以及原因。gprof和callgrind给了我在每个函数上花费的全部时间。但是这个时间包括线程在某个事情上被阻塞的时间吗?有什么开源工具可以用来调试这个问题吗。

即使我没有现成的答案,我也会从这里的注释切换,因为还有更多的空间可以编写和格式化。。

你能澄清一下"lahks"这个词吗?我在维基上只发现了一些松散的相关内容,但这只是猜测,我不知道你的意思。

你说的large number of objects per thread。当你随机取样/停车时,你看了堆叠比赛吗?我知道alloc/dealloc是堆叠种族中最常见的叶子,但*非叶子*s呢?你能看到实际是什么在调用alloc/dealloc吗?这就是采样方法的要点——查看调用的原始来源,并从统计上估计调用频率过高的可能来源。

由于大量优化或架构不匹配(即,如果您的应用程序使用任务队列,那么大多数时候您只会看到"获取任务"、"检查任务"answers"执行任务"步骤,而不是真正的起源),您可能无法观察到堆栈竞争的"较高部分",但几乎在每种架构中,你都可以进行适当的调整(就任务查询而言——只需尝试对任务注册进行采样!)

还有另一种方式——alloc/dealloc膨胀是非常普遍的:它通常与架构和算法有关,或者,嗯,与bug有关。然而,这类事情应该很容易观察到,不仅在"优化版本"构建中(在那里看到堆栈竞争有问题),而且应该很快出现在"完整调试信息"构建中——如果优化较少,整个系统运行速度会较慢,但你应该能够看到并收集所有可能来源的中间方法。

还有一件事:你说过"多线程"的工作速度比"单线程"慢得多。这就产生了一个关于的问题,您如何能够在它们之间切换?您有两个单独的实现吗?还是只调整线程池大小,使其介于1个workertread和N个workerthread之间?与"alloc/dealloc"问题交叉——也许你的每个线程每次都需要执行太多的设置/拆卸?

试着检查线程(作为一个组,也要查看线程的寿命)必须重复准备的内容,而与单线程选项形成对比。

例如,单线程在某种程度上节省了alloc/dealloc,并且可能重用一些结构),而N线程可能需要N倍的相同结构。如果线程只是重复启动/停止并且没有重用,那么它们的N*数据可能也没有重用,因此N线程可能只是在实际工作之前消耗准备时间。。

此外,如果您设法捕捉到了无关的分配方案,为什么不进一步跟踪呢:停止后,退出分配器,试着看看是什么被覆盖了。我的意思是,你可以仔细检查写在记忆中的内容,这可以让你对实际发生的事情有更深入的了解。然而,这可能是一项非常艰巨的任务,尤其是因为它必须重复多次。。我会把它作为最后的手段。

另一件事是——纯粹猜测——您的平台可能在alloc/dealloc内部有一些全局锁,以"安全地跟踪"内存管理。这样,如果所有线程都按照自己的意愿管理自己的内存,那么线程将在每次内存分配/释放操作时相互等待。更改内存分配方案,或使用不同的内存管理器,或使用堆栈或TLS,或将线程池拆分为单独的进程可能会有所帮助,因为这将免除全局锁的需要。但是,这只是一个非常遥远的猜测,没有一个解决方案是容易应用的。

我对这种笼统含糊的谈话感到抱歉。你只提供了一些细节,很难说什么了。我故意回避"将工作形象化的工具"这个话题。如果你不能仅仅通过sample/stop方法看到发生了什么,那么所有可能的"线程可视化"工具很可能都没有帮助:它们可能会向你显示与你现在看到的完全相同的内容,因为它们都分析相同的堆栈竞争,只是比手动停止快一点。。

一种可能性是您在单核CPU上运行多线程代码:)

关于多线程的一个常见误解是,只需将线程投入到问题中,就可以获得加速改进:除非你有一个真正的多核CPU和一个可并行的问题(即,一个可以分解为独立可解子问题的问题),否则这是错误的

也许您正在处理一个不可并行的问题(例如哈希计算)或使用I/O访问(同样是不可并行)