深究 Go CPU profiler

在 profiling 方面,Go 是独一无二的。在 runtime 里面它包含强大的,有自主意识的 profilers。其他编程语言像 Ruby,Python,或者 Node.js,包含了 profilers 或者一些 APIs 接口用来写 profiler。但与 Go 提供的开箱即用的服务相比,它们的范围还是有限的。如果你想学习更多关于 Go 提供的可观测性工具,我强烈建议 Felix Geisendörfer 的 忙碌的开发人员指南 - Go 性能分析,追踪和可观测性

作为一个好奇的工程师,我喜欢钻研底层的实现原理,并且我一直希望能学习 Go CPU profiler 是如何实现的。这个博客就是这个学习的过程。毫无例外的,我总是能在我阅读 Go runtime 的时候找到并学习新的知识点。

基础知识

有两种类型的 profiler :

  1. 追踪型:任何时候触发提前设定的事件就会做测量,例如:函数调用,函数退出,等等

  2. 采样型:常规时间间隔做一次测量

Go CPU profiler 是一个采样型的 profiler。也有一个追踪型的 profiler,Go 执行追踪器,用来追踪特定事件像请求锁,GC 相关的事件,等等。

采样型 profiler 通常包含两个主要部分:

  1. 采样器:一个在时间间隔触发的回调,一个堆栈信息一般会被收集成 profiling data。不同的 profiler 用不同的策略去触发回调。

  2. 数据收集:这个是 profiler 收集数据的地方:它可能是内存占用或者是调用统计,基本上跟堆栈追踪相关的数据

其他 profiler 如何工作的小调研

Linux perf 使用 PMU(Performance Monitor Unit)计数器进行采样。你指示 PMU 在某些事件发生 N 次后产生一个中断。一个例子,可能是每 1000 个 CPU 时钟周期进行一次采样。Denis Bakhvalov 写了一篇详细的文章,解释了像 perf 和 VTune 这样的工具如何使用 PMU 计数器来实现。一旦数据收集回调被定期触发,剩下的就是收集堆栈痕迹并适当地汇总。为了完整起见,Linux perf 使用 perf_event_open(PERF_SAMPLE_STACK_USER,...) 来获取堆栈追踪信息。捕获的堆栈痕迹通过 mmap'd 环形缓冲区写到用户空间。

pyspy 和 rbspy 是 Python 和 Ruby 著名的采样分析器。它们都作为外部进程运行,定期读取目标应用程序的内存,以捕获运行线程的堆栈追踪。在Linux中,它们使用 process_vm_readv,如果我没记错的话,这个 API 在读取内存时,会让目标程序暂停几毫秒。然后他们在读取的内存中跟踪指针,来找到当前运行的线程结构和堆栈追

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值