用于可视化每个线程正在运行的函数的工具 我试图用多线程C++应用程序调试性能问题。基本上,我的多线程程序(10个线程)比单线程程序慢得多

用于可视化每个线程正在运行的函数的工具 我试图用多线程C++应用程序调试性能问题。基本上,我的多线程程序(10个线程)比单线程程序慢得多,c++,multithreading,C++,Multithreading,我一直在尝试valgrind(callgrind)、gprof和gdb等工具。但到目前为止,我还无法弄清楚线程被阻塞的确切位置以及原因。gprof和callgrind为我提供了在每个函数上花费的全部时间。但这一次是否包括线程被阻塞的时间?是否有任何开源工具可用于调试此问题。即使我没有现成的答案,我也会从这里的注释中切换,因为还有更多的空间来编写和格式化 你能澄清一下“lahks”这个词吗?我只找到了,但这纯粹是猜测,我不知道你的意思 每个线程有大量的对象。当您随机采样/停止时,您是否观看了sta

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

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

你能澄清一下“lahks”这个词吗?我只找到了,但这纯粹是猜测,我不知道你的意思

每个线程有大量的对象。当您随机采样/停止时,您是否观看了stacktraces?我知道alloc/dealoc是stacktrace中最常见的叶子,但是*nonleaf*s呢?你能看到什么叫alloc/dealoc吗?这就是抽样方法的要点——查看调用的原始数据,并从统计上估计哪些可能的源代码导致调用过于频繁

由于大量优化或体系结构不匹配,您可能无法观察堆栈跟踪的“更高部分”(即,如果您的应用程序使用任务队列,那么大多数情况下,您将只看到“获取任务”、“检查任务”、“执行任务”步骤,而不是真正的来源),但是,几乎在每一个架构中,您都可以适当地进行调整(在任务查询方面,只需尝试对任务注册进行采样!)

还有另一种方式——alloc/Dealoc膨胀是相当普遍的:它通常与架构和算法有关,或者是与bug有关。然而,这种情况不仅在“优化发布”版本(在查看堆栈跟踪时存在问题)中很容易观察到,而且在“完整调试信息”版本中也会很快出现——优化越少,整个系统的运行速度就越慢,但是您应该能够看到并收集所有可能的中间方法

另一件事:你说过“多线程”比“单线程”慢得多。这就产生了一个关于如何在它们之间切换的问题?你们有两个独立的实现吗?或者您只是在1个workerthread和N个workerthread之间调整线程池大小?与“alloc/dealloc”问题交叉——也许您的每个线程每次都需要执行太多的设置/拆卸

尝试检查线程(作为一个组,也查看线程的生命周期)实际需要重复准备的内容,与单线程选项相比

例如,单线程可能会以某种方式节省alloc/dealoc,并可能重用某些结构),而N线程可能需要N倍于相同结构的时间。如果线程只是重复地启动/停止并且没有被重用,那么它们的N*数据也可能没有被重用,因此N个线程可能只是在实际工作之前的准备工作上浪费时间

此外,如果您成功地捕获了无关的分配方案,那么为什么不进一步跟踪一下呢:停止之后,走出分配器,尝试查看正在被覆盖的内容。我的意思是,你可以一步一步地检查写入记忆的内容,这可以让你进一步了解实际发生的事情。然而,这可能是一项非常艰巨的任务,特别是因为它必须重复多次。。我会把它作为最后的手段

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


我为这种笼统而含糊的谈话感到抱歉。你只提供了一些细节,很难再多说什么了。我故意回避“工作可视化工具”的话题。如果您无法通过sample/stop方法看到正在发生的事情,那么所有可能的“线程可视化”工具很可能都没有帮助:它们可能会显示与您现在看到的完全相同的内容,因为它们都分析相同的堆栈跟踪,只比手动停止快一点。

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

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


可能您正在处理不可并行化问题(例如哈希计算)或使用I/O访问(这也是不可并行化的)

可能的重复。我建议您尝试英特尔的vtune。而且你似乎还没有充分利用callgrind+hellgrind所能提供的功能。你是否只需要找到瓶颈和停止的来源?请试一试。这是一种最简单、最快速的治疗方法,效果非常好。尝试一下,即使它看起来“太琐碎而无法真正工作”。只需记住,它会让你发现等待的是什么。它不会告诉你多长时间,发生了什么,为什么。您必须阅读/思考代码中的这些内容。不过,找到等待的内容通常是一个很好的开始。提示:您可以使用unix time命令来估计上下文切换