2017-09-15 176 views
1

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

是否有任何文档解释了多线程工作负载分析的工作原理以及如何解释输出?例如,剖析器是否对每个样本的每个线程进行回溯,如果不是,那么它在做什么?

#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 

凡和10.7%来自的89.3%? (这些是总样本的在功能和它的被调用者的百分比)

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

+0

这些列在你的输出中意味着什么?我认为这是特别有用的知道列不同。另外,如果您想更多地看到结果,它可能已经有所了解。 – hakre

+0

有趣的列是第4和第5:此函数及其被调用者中的样本数,此函数及其被调用者中总样本的百分比。前两列与列出的函数中的样本相关,第三列是迄今为止在输出中输出的所有函数的累计百分比。 –

+0

我想我想知道的是,对于每个样本,是分析器对每个样本进行回溯运行线程?如果不是,它在做什么? –

回答

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

+0

这是一个很好的答案,谢谢你的帮助。 –

+0

@Aliaksei Kandratsenka,谢谢你的回答。我有一个后续问题,我不确定它是否值得单独发布:在打开gperftools的多线程支持的情况下,如何分别输出每个线程的性能分析结果?通过您的设置,我认为所有结果都收集在CPUPROFILE指定的单个输出文件中。 –

+0

无法跟踪线程特定的配置文件。只有特定的线程子集才能提供简单的支持。请参阅ProfileOptions结构。分析特定线程偶尔会非常有用。 –