perf record竟会导致磁盘满载?

背景

在某服务的测试环境中,/root目录挂载的是一块20G的磁盘。每个节点可能会运行多个实例,我们会在环境上进行性能测试、性能分析等操作。在某次测试的过程中,我们发现系统盘的20G已被占满。

由于一般的环境都是这样处理的,所以这里我们不考虑重新划盘这样的解决方案。

问题发现与分析

是什么占据了磁盘?

我们查看每个文件夹的大小:

shell 复制代码
du -h --max-depth=1

发现在20G的空间中,除了一些必要的文件外,有大约8G.debug文件夹占据,此外还有2Gperf采集到的数据。perf采集到的数据直接删除即可,我们重点关注.debug文件夹。.debug文件夹是用来保存可执行文件对应的debug信息的。

进入.debug文件夹下,我们发现了和可执行文件的路径几乎一致的路径。例如可执行文件testcpp路径为/root/workplace/test/testcpp,对应在.debug下的路径就是/root/.debug/root/workplace/test/testcpp/1ec9a7a87620face349c8f562de67d00e7a1cfa2,这里的1ec9a7a87620face349c8f562de67d00e7a1cfa2是这个可执行文件的buildid。这里buldid是这个可执行文件在编译的时候生成的。我们可以用file来进行查看:

由于测试环境上会运行多个实例,所以在.debug文件夹下会出现多个实例的elf文件,这就导致整体的存储占用比较高。

是什么产生了这些文件?

从过去使用perf的经验中,笔者了解到perf script可能会使用到.debug文件夹下的内容,同时perf也有perf buildid-list这样明显和.debug文件相关联的部分,因此笔者首先将目光放到了perf上。

显然这是一个已经执行过perf的环境,所以我们不妨找一个没有.debug文件夹的环境,执行perf试试:

可以看到在这里生成了.debug目录。

我们通过strace抓取perf record执行的情况:

shell 复制代码
strace -o strace perf record -ag -F 999 -- sleep 2

在输出的strace结果中直接搜索.debug

可以看到perf直接去创建了.debug目录并且会去检查其子目录的情况,并进行子目录的创建,也即perf record会生成.debug文件夹及对应的文件

perf config注释中,我们也找到了相关说明:

The recording tools also stores a hard link or copy in a per-user directory, $HOME/.debug/, of binaries, shared libraries, /proc/kallsyms and /proc/kcore files to be used at analysis time.

问题解决

在前面我们提到,我们不考虑增加存储这样的解法,因此我们考虑如下的两个思路:

  • 不生成.debug
  • .debug生成到其他目录下

不生成.debug

如何不生成.debug目录

我们首先去查阅了perf record的文档,在文档中我们发现可以用-B/-N选项关闭:

-B, --no-buildid Do not save the build ids of binaries in the perf.data files. This skips post processing after recording, which sometimes makes the final step in the recording process to take a long time, as it needs to process all events looking for mmap records. The downside is that it can misresolve symbols if the workload binaries used when recording get locally rebuilt or upgraded, because the only key available in this case is the pathname. You can also set the "record.build-id" config variable to 'skip to have this behaviour permanently.

-N, --no-buildid-cache Do not update the buildid cache. This saves some overhead in situations where the information in the perf.data file (which includes buildids) is sufficient. You can also set the "record.build-id" config variable to no-cache to have the same effect.

我们实际验证一下:

不生成的影响

根据注释来说,我们会发现-B-N的作用并不是完全一致的,前者是不保存相关的二进制信息,而后者是不做更新。这会有什么后果呢?

perf的使用流程中,我们往往会使用perf script去解析perf record生成的数据,在解析的过程中,会涉及到地址与函数的转换,这里就需要我们的debug信息的参与。在实际的转换过程中,perf script会通过以下的渠道去找对应的二进制文件:

  • 可执行文件目录,例如前文提到的/root/workplace/test/testcpp;如果是容器环境,会首先进行setns操作;
  • $HOME/.debug目录下的文件(默认情况下);
  • /usr/lib/debug目录下的文件;

perf会进行如下的操作:

Each executable and shared library in modern distributions comes with a content based identifier that, if available, will be inserted in a perf.data file header to, at analysis time find what is needed to do symbol resolution, code annotation, etc.

因此,正如注释中说到的,如果可执行文件目录的文件发生了变更,就会导致错误的匹配。这也就是.debug保存的原因,让perf能够在即使可执行文件消失的情况下也可以正确的解析。所以如果环境上的程序不会发生太多变化的话,不保存相关信息也是可以的。

将.debug生成到其他目录下

在前面提到的注释中,我们发现也可以通过进行配置的方式来调整perf record执行的情况,我们查看perf config的选项,发现如下的选项:

buildid\] # Default, disable using /dev/null dir = \~/.debug

因此我们可以将该目录生成到其他路径中,不使用该系统盘路径即可。下面是使用perf config切换路径的例子:

小结

本文基于在实际情况中遇到的磁盘满载问题,进行了一系列的探索,结论如下:

  • 为了更好的做解析,perf record默认会将诸多debug文件放到~/.debug文件夹下;
  • 可以通过-B/-N选项禁止该行为
  • 可以通过perf config配置存放文件路径
相关推荐
国思RDIF框架1 小时前
RDIFramework.NET CS 敏捷开发框架 V6.3 版本重磅发布!.NET8+Framework双引擎,性能升级全维度进化
后端·.net
心在飞扬1 小时前
ReRank重排序提升RAG系统效果
前端·后端
喝茶与编码1 小时前
Python异步并发控制:asyncio.gather 与 Semaphore 协同设计解析
后端·python
不早睡不改名1 小时前
网络编程基础:从BIO到NIO再到AIO(一)
后端
开源之眼1 小时前
《github star 加星 Taimili.com 艾米莉 》为什么Java里面,Service 层不直接返回 Result 对象?
java·后端·github
心在飞扬1 小时前
RAPTOR 递归文档树优化策略
前端·后端
zone77391 小时前
003:RAG 入门-LangChain 读取图片数据
后端·python·面试
心在飞扬1 小时前
LangChain Parent Document Retriever (父文档检索器)
后端
zone77392 小时前
002:RAG 入门-LangChain 读取文本
后端·算法·面试
用户8356290780512 小时前
在 PowerPoint 中用 Python 添加和定制形状的完整教程
后端·python