具有繁重的内核工作(锁定解锁)的多线程程序,请尝试使用性能分析工具在我的代码中查找热点。
我写了一个最小的可复制程序。编译它。将性能分析工具(如perf,gprof)与调用堆栈记录一起使用。然后,没有人可以在我的代码中报告热点,但是在内核或libstdc ++。so中报告功能。
#include <iostream>
#include <mutex>
#include <thread>
#include <memory>
#include <vector>
std::mutex mtx;
long long_val = 0;
void do_something(long &val)
{
std::unique_lock<std::mutex> lck(mtx);
for(int j=0; j<1000; ++j)
val++;
}
void thread_func()
{
for(int i=0; i<1000000L; ++i)
{
do_something(long_val);
}
}
int main(int argc, char* argv[])
{
std::vector<std::unique_ptr<std::thread>> threads;
for(int i=0; i<100; ++i)
{
threads.push_back(std::move(std::unique_ptr<std::thread>(new std::thread(thread_func))));
}
for(int i=0; i<100; ++i)
{
threads[i]->join();
}
threads.clear();
std::cout << long_val << std::endl;
return 0;
}
正如我们所知,do_something()
是我程序的热点。因为太多的unique_lock会花费大量内核工作,并且该函数的inc运算量为1000倍。
我想使用分析工具告诉我,do_something()会产生很多锁定,导致大量内核工作。但是从perf
,我只能发现它是锁使我的代码变慢,但是使这些锁在我的代码上运行的地方呢?还不清楚。
编译:
g++ -o a.out -O3 -std=c++11 -fno-omit-frame-pointer -pthread -pg main.cpp
运行程序./a.out
,htop报告内核占用了一半的CPU资源。
性能记录:
perf record -g ./a.out
性能报告:
Children Self Command Shared Object Symbol
- 98.64% 0.00% a.out libstdc++.so.6.0.21 [.] 0x00000000000b8c80
- 0xb8c80
+ 41.80% __lll_unlock_wake
+ 35.39% __lll_lock_wait
12.77% pthread_mutex_lock
7.69% pthread_mutex_unlock
0.70% _Z11thread_funcv
- 49.21% 0.88% a.out [kernel.kallsyms] [k] entry_SYSCALL_64_after_hwframe
+ 48.33% entry_SYSCALL_64_after_hwframe
0.88% 0xb8c80
- 47.64% 1.06% a.out [kernel.kallsyms] [k] do_syscall_64
+ 46.59% do_syscall_64
+ 1.06% 0xb8c80
- 47.18% 1.44% a.out [kernel.kallsyms] [k] sys_futex
+ 45.74% sys_futex
+ 1.44% 0xb8c80
- 45.55% 1.65% a.out [kernel.kallsyms] [k] do_futex
+ 43.90% do_futex
+ 1.65% 0xb8c80
- 41.80% 1.30% a.out libpthread-2.23.so [.] __lll_unlock_wake
+ 40.50% __lll_unlock_wake
+ 1.30% 0xb8c80
- 35.39% 4.53% a.out libpthread-2.23.so [.] __lll_lock_wait
+ 30.86% __lll_lock_wait
+ 4.53% 0xb8c80
- 20.51% 5.40% a.out [kernel.kallsyms] [k] futex_wake
+ 15.11% futex_wake
+ 5.40% 0xb8c80
- 19.41% 0.88% a.out [kernel.kallsyms] [k] futex_wait
+ 18.53% futex_wait
+ 0.88% 0xb8c80
- 16.92% 6.25% a.out [kernel.kallsyms] [k] _raw_spin_lock
+ 10.67% _raw_spin_lock
+ 6.25% 0xb8c80
- 12.77% 12.73% a.out libpthread-2.23.so [.] pthread_mutex_lock
12.73% 0xb8c80
pthread_mutex_lock
+ 11.80% 5.41% a.out [kernel.kallsyms] [k] futex_wait_setup
+ 11.05% 11.05% a.out [kernel.kallsyms] [k] syscall_return_via_sysret
+ 10.68% 10.67% a.out [kernel.kallsyms] [k] native_queued_spin_lock_slowpath
+ 7.69% 7.65% a.out libpthread-2.23.so [.] pthread_mutex_unlock
+ 7.36% 0.11% a.out [kernel.kallsyms] [k] wake_up_q
+ 7.17% 1.27% a.out [kernel.kallsyms] [k] try_to_wake_up
+ 4.42% 0.23% a.out [kernel.kallsyms] [k] futex_wait_queue_me
+ 4.17% 0.08% a.out [kernel.kallsyms] [k] schedule
+ 3.84% 0.75% a.out [kernel.kallsyms] [k] __schedule
+ 2.70% 0.01% a.out [kernel.kallsyms] [k] ttwu_do_activate
+ 2.49% 2.48% a.out [kernel.kallsyms] [k] get_futex_value_locked
+ 2.38% 0.11% a.out [kernel.kallsyms] [k] activate_task
+ 2.26% 0.15% a.out [kernel.kallsyms] [k] enqueue_task_fair
+ 1.88% 1.88% a.out [unknown] [k] 0xfffffe000000601b
+ 1.84% 0.15% a.out [kernel.kallsyms] [k] __task_rq_lock
+ 1.78% 1.78% a.out [unknown] [k] 0xfffffe000005e01b
+ 1.77% 1.77% a.out [unknown] [k] 0xfffffe000003201b
+ 1.67% 0.02% a.out [kernel.kallsyms] [k] deactivate_task
+ 1.66% 1.66% a.out [unknown] [k] 0xfffffe000008a01b
如何在我的程序中使用概要分析工具找出此类热点。我不想每次都使用“二进制印章注释”来解决它。谢谢!
答案 0 :(得分:1)
perf
默认情况下使用框架指针展开,这是快速的,但是并不可靠。即使您的应用程序不省略帧指针,库也可能会如此。
或者,您可以将--call-graph
与dwarf
或lbr
一起使用。
dwarf
记录采样期间的堆栈块,这些块稍后进行评估。它可以提供更多细节,但会留下大量痕迹,并且可能会带来更多干扰。
lbr
需要较新的Intel处理器提供硬件支持。
它将显示如下内容:
99.25% 2.61% a.out a.out [.] thread_func
|
|--97.67%--thread_func
| |
| |--45.33%--pthread_mutex_lock@plt
| |
| |--28.65%--pthread_mutex_unlock@plt
| |
| |--18.88%--__pthread_mutex_lock
| | __lll_lock_wait
| |
| --4.75%--__pthread_mutex_unlock_usercnt
| __lll_unlock_wake
|
--0.72%--__pthread_mutex_lock