在多线程程序中,如何有效地分析等待锁、休眠或以其他方式调度的线程?
为了我的分析目的,我需要深入了解一些锁争用。所以我想在例如堆栈跟踪分析器工具中看到这一点,可以从中生成火焰图。我首先尝试使用 gperftools
CPU 分析器来做到这一点。但顾名思义,它只会分析实际上在 CPU 上执行某些操作的线程,您不会看到等待锁的线程的堆栈跟踪。
然后我切换到 perf,我希望它足够强大,能够以某种方式收集计划外线程的配置文件信息。但到目前为止还没有运气。
这是我的测试程序:
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
const int NR_THREADS = 8;
const int DURATION = 5;
bool done = false;
struct thread_data_t {
pthread_t thread;
pthread_mutex_t* mutex;
int tid;
};
void *threadfunction(void *arg)
{
pthread_mutex_t* mutex = arg;
pthread_mutex_lock(mutex);
printf("I am the thread function!\n");
pthread_mutex_unlock(mutex);
}
int main(void)
{
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, 0);
pthread_mutex_lock(&mutex);
pthread_t thread;
(void) pthread_create(&thread, NULL, threadfunction, &mutex);
for (int i = 0; i < 60000000; i++)
printf("I am the main function!\n");
pthread_mutex_unlock(&mutex);
(void) pthread_join(thread, NULL);
return 0;
}
现在我运行以下性能记录
perf record -F50 --call-graph dwarf test_program
我将其编译成火焰图
perf script > perf.script
stackcollapse-perf.pl perf.script | flamegraph.pl > flamegraph.svg
生成的火焰图如下。而且你可以看到它基本上只显示了属于 main 函数的堆栈。 threadfunction
在不同的线程中运行,因为它正在等待锁定并因此被调度,你看不到任何与之相关的堆栈跟踪。
我尝试将某些事件添加到perf-record
-e sched:sched_stat_sleep,sched:sched_switch
但这也没有帮助。
我如何使用 perf
有效地创建和编译基于锁争用的堆栈跟踪配置文件和基于 CPU 的堆栈跟踪配置文件?我喜欢使用 perf,但我也非常愿意接受其他工具建议。
例如,据我所知,使用基于gdb
的穷人分析器,您实际上可以获得休眠线程的堆栈跟踪。这是合理的,因为 gdb
必须能够以某种方式从任何线程获取堆栈信息。但是我更喜欢一个更协调和专用的工具来完成这样的任务 gdb
.