c++ Flamegraph可以显示所有的函数调用吗?

guicsvcw  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(77)

我知道有一个叫做火焰图的分析工具,它能够快速识别二进制文件的性能瓶颈。
实际上,我不需要知道性能统计数据。相反,我只对堆栈跟踪感兴趣。Flame图能够可视化所有历史堆栈跟踪。Flamegraph可以包含比传统GDB崩溃堆栈跟踪更多的信息,因为它记住了所有历史函数调用。
所以我的问题是:flamegraph能满足我所寻找的吗?我听说flamegraph做采样,所以我担心它会失去函数调用。
我在https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html#C++这个网页上找到了很多flamegraph的例子。flamegraph正是我想要的,因为我可以放大和缩小来检查函数调用。这里唯一的担心是:我听说perf之类的prof工具只会通过采样率来收集stacktrace,所以flamegraph可能不会忠实地展示所有的函数调用。
简而言之,我所寻找的是:flamegraph减去性能统计数据,但加上100%的函数调用历史。

vxqlmq5t

vxqlmq5t1#

我刚刚想出了一个方法来实现我的目标。这是一个黑客利用现有的flamegraph功能。
第1步:通过类似于以下的补丁来检测代码库:

+#include <iostream>
+#include <vector>
+#include <sstream>
+
+extern thread_local std::vector<std::string> thread_local_stack;
+
+struct tracer_t {
+    tracer_t(std::string method) {
+        thread_local_stack.emplace_back(std::move(method));
+        std::ostringstream oss;
+        for (int i = 0; i < thread_local_stack.size(); ++i) {
+            if (i) {
+                oss << ";";
+            }
+            oss << thread_local_stack[i];
+        }
+        printf("%s 1", oss.str().c_str());
+    }
+
+    ~tracer_t() {
+        thread_local_stack.pop_back();
+    }
+};
+
+inline std::string methodName(const std::string& prettyFunction)
+{
+    size_t colons = prettyFunction.find("::");
+    size_t begin = prettyFunction.substr(0, colons).rfind(" ") + 1;
+    size_t end = prettyFunction.rfind("(") - begin;
+
+    return prettyFunction.substr(begin,end) + "()";
+}
+
+#define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__)
+
+#define LOG_CALL tracer_t _token(__METHOD_NAME__)

字符串
在某处声明线程本地堆栈:

+thread_local std::vector<std::string> thread_local_stack;


在你想跟踪的函数的开头添加LOG_CALL宏。可能有几百个,我不知道有什么自动工具,所以我手动添加了它。
上面的代码在clang编译器中工作。
第二步:编译代码,运行一个你感兴趣的测试用例。我们会得到跟踪。内容应该是这样的:

func1 1
func1;func2 1
func1;func2;func3 1
func1;func2;func4 1
func1;func2;func3 1
func2 1
...


上面的格式可以通过flamegraph工具从https://github.com/brendangregg/FlameGraph/blob/master/flamegraph.pl中识别出来。我通过尝试这个例子学习了这个格式:https://github.com/brendangregg/FlameGraph/blob/master/files.pl
第3步:运行flamegraph与“--flamechart”选项,因为我们希望X轴排序的时间和禁用“自动合并”在flamegraph。
“flamechart”和“flamegraph”的区别在于:flamegraph是为了研究perf瓶颈而设计的,所以很多样本被合并(求和)。为了这篇文章的目的,我们需要按时间对X轴进行排序,永远不要合并。
使用以下命令:

cat ~/d/output.txt |  ./flamegraph.pl --hash --countname=bytes --flamechart  > /tmp/out.svg


然后我得到了我想要的flamechart in out. svg。

相关问题