解释 gperftools 在多线程工作负载上的结果

Posted

技术标签:

【中文标题】解释 gperftools 在多线程工作负载上的结果【英文标题】:Interpreting results for gperftools on multi-threaded workloads 【发布时间】:2017-09-15 15:17:20 【问题描述】:

我正在尝试使用 gperftools 分析多线程工作负载,但难以解释产生的输出。我编写了一个简单的程序,它启动两个具有相同工作负载的线程并使用 gperftools cpu 分析器进行分析。在输出中,我可以看到每个线程的两个函数,但是每个线程的开销从一次运行到下一次变化很大。我希望这两个函数显示相同的结果,因为它们是相同的工作负载,但实际上,一个可能是 90%,另一个是 10%,或者有时是 80%/20%、95%/5% 等。我不了解为什么函数显示不同的开销,或者为什么结果从一次运行到下一次变化如此之大。基准运行大约 5 秒,有 1600 个样本,所以应该是稳定的。

是否有任何文档说明分析如何适用于多线程工作负载,以及如何解释输出?例如,分析器是否对每个样本的每个线程进行回溯,如果没有,它在做什么?

#include <vector>
#include <cstdlib>
#include <thread>
using namespace std;

void thread_func() 
    int size = 500000;
    vector<int> V(size);
    for(int i = 0; i < 100000; i++) 
        V.erase(V.begin() + (rand() % size));
        V.insert(V.begin() + (rand() % size), rand() % 10);
    


void thread_func2() 
    int size = 500000;
    vector<int> V(size);
    for(int i = 0; i < 100000; i++) 
        V.erase(V.begin() + (rand() % size));
        V.insert(V.begin() + (rand() % size), rand() % 10);
    


int main() 
    srand(1234);
    thread t1(thread_func);
    thread t2(thread_func2);
    t1.join();
    t2.join();
    return 0;

示例输出:

0   0.0% 100.0%     1429  89.3% thread_func
0   0.0% 100.0%      172  10.7% thread_func2

89.3% 和 10.7% 来自哪里? (这些是函数及其被调用者中总样本的百分比)

Image contains a portion of the graph, numbers are slightly different from above because it's a different run

【问题讨论】:

输出中的列是什么意思?我认为这对于了解不同的列特别有用。此外,如果您将结果可视化更多一点,它可能已经有所启发。 有趣的列是第 4 列和第 5 列:此函数及其被调用者中的样本数,此函数及其被调用者中总样本的百分比。前 2 列与列出的函数内的样本有关,第 3 列是迄今为止在输出中打印的所有函数的累积百分比 我想我想知道的是,对于每个样本,分析器是否对每个正在运行的线程进行回溯?如果没有,它在做什么? 听起来更像是在猜测......反正我不是 gperfs 专业人士,所以不能告诉你,只是评论,因为这是你的第一篇文章。 【参考方案1】:

这是 SIGPROF 信号传递的已知问题。有关详细信息,请参阅https://github.com/golang/go/issues/14434。

Gperftools 实际上对偏斜有“修复”(如该问题所述)。您只需要设置 CPUPROFILE_PER_THREAD_TIMERS=t 并确保 librt 和 libpthread 已链接。您还需要“注册”您的线程或 LD_PRELOAD https://github.com/alk/gperf-all-threads

【讨论】:

@Aliaksei Kandratsenka,感谢您的精彩回答。我有一个后续问题,我不确定它是否值得单独发布:打开 gperftools 的多线程支持后,如何分别输出每个线程的分析结果?通过您的设置,在我看来,所有结果都收集在 CPUPROFILE 指定的单个输出文件中。 无法跟踪线程特定的配置文件。对仅分析特定线程子集的基本支持。请参阅 ProfileOptions 结构。分析特定线程有时非常有用。

以上是关于解释 gperftools 在多线程工作负载上的结果的主要内容,如果未能解决你的问题,请参考以下文章

在多线程应用程序表单上使用while循环锁定c#阻塞单核机器上的所有线程

Java 线程与操作系统线程

在多线程中显示模态窗口,出现异常现象

9月11号面试总结(guangfa)

如何正确处理信号,让 gperftools CPU profiler 仍然有效?

使用带有排序的 gperftools 时分析计时器已过期