py-spy

py-spy

轻量级Python程序性能分析工具

py-spy是一个开源的Python程序采样分析器,无需修改代码即可可视化程序运行时间分布。使用Rust开发,具有低开销特性,可安全地分析生产环境代码。支持主流操作系统和多个CPython版本,提供性能记录、实时监控和堆栈转储功能。py-spy能生成多种格式的分析报告,包括火焰图,有助于开发者深入了解和优化Python程序性能。

py-spyPython性能分析采样分析器跨平台Github开源项目

py-spy:Python程序的采样分析器

py-spy是一个用于Python程序的采样分析器。它可以让你可视化Python程序的耗时情况,无需重启程序或以任何方式修改代码。py-spy的开销极低:它使用Rust编写以提高速度,并且不在被分析的Python程序的同一进程中运行。这意味着py-spy可以安全地用于生产环境的Python代码。

py-spy可在Linux、OSX、Windows和FreeBSD上运行,并支持分析所有近期版本的CPython解释器(2.3-2.7和3.3-3.11版本)。

安装

可以通过PyPI安装预编译的二进制wheel文件:

pip install py-spy

你也可以从GitHub发布页面下载预编译的二进制文件。

如果你是Rust用户,也可以通过以下命令安装py-spy:cargo install py-spy

在macOS上,py-spy已被收录到Homebrew,可以使用brew install py-spy安装。

在Arch Linux上,py-spy在AUR中,可以使用yay -S py-spy安装。

在Alpine Linux上,py-spy在测试仓库中,可以使用apk add py-spy --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted安装。

使用方法

py-spy在命令行中运行,需要提供要采样的程序的PID或Python程序的命令行。py-spy有三个子命令:recordtopdump

record

py-spy支持使用record命令将分析结果记录到文件中。例如,你可以通过以下方式生成Python进程的火焰图

py-spy record -o profile.svg --pid 12345 # 或者 py-spy record -o profile.svg -- python myprogram.py

这将生成一个交互式的SVG文件,看起来像这样:

[火焰图示例]

你可以使用--format参数更改文件格式,以生成speedscope配置文件或原始数据。 使用py-spy record --help可以查看其他选项的信息,包括更改采样率、仅包含持有GIL的线程、分析原生C扩展、显示线程ID、分析子进程等。

top

top显示Python程序中最耗时函数的实时视图,类似于Unix的top命令。运行py-spy时使用:

py-spy top --pid 12345 # 或者 py-spy top -- python myprogram.py

将会显示Python程序的实时更新的高级视图:

[控制台查看器演示]

dump

py-spy还可以使用dump命令显示每个Python线程的当前调用栈:

py-spy dump --pid 12345

这将向控制台输出每个线程的调用栈以及一些基本的进程信息:

[dump输出示例]

当你只需要一个调用栈来确定Python程序在哪里卡住时,这非常有用。通过设置--locals标志,该命令还可以打印出与每个栈帧相关的局部变量。

常见问题

为什么我们需要另一个Python分析器?

本项目旨在让你能够分析和调试任何正在运行的Python程序,即使该程序正在处理生产流量。

虽然有许多其他Python分析项目,但几乎所有这些项目都需要以某种方式修改被分析的程序。通常,分析代码在目标Python进程内部运行,这会降低程序的运行速度并改变程序的运行方式。这意味着通常不能安全地使用这些分析器来调试生产服务中的问题,因为它们通常会对性能产生明显的影响。

py-spy是如何工作的?

py-spy通过直接读取Python程序的内存来工作,在Linux上使用process_vm_readv系统调用,在OSX上使用vm_read调用,在Windows上使用ReadProcessMemory调用。

通过查看全局PyInterpreterState变量来确定Python程序的调用栈,以获取解释器中运行的所有Python线程,然后遍历每个线程中的每个PyFrameObject以获取调用栈。由于Python ABI在不同版本之间会发生变化,我们使用Rust的bindgen为我们关心的每个Python解释器类生成不同的Rust结构,并使用这些生成的结构来确定Python程序中的内存布局。

由于地址空间布局随机化,获取Python解释器的内存地址可能有点棘手。如果目标Python解释器带有符号,通过解引用interp_head_PyRuntime变量(取决于Python版本)就可以很容易地确定解释器的内存地址。然而,许多Python版本都是以剥离二进制文件的形式发布的,或者在Windows上没有相应的PDB符号文件。在这些情况下,我们会扫描BSS段,寻找看起来可能指向有效PyInterpreterState的地址,并检查该地址的布局是否符合我们的预期。

py-spy能分析原生扩展吗?

可以!py-spy支持分析用C/C++或Cython等语言编写的原生Python扩展,可在x86_64 Linux和Windows上使用。你可以通过在命令行中传递--native来启用此模式。为获得最佳结果,你应该使用符号编译Python扩展。对于Cython程序,值得注意的是py-spy需要生成的C或C++文件才能返回原始.pyx文件的行号。阅读博客文章以获取更多信息。

如何分析子进程?

通过向record或top视图传递--subprocesses标志,py-spy还将包括目标程序的任何子Python进程的输出。这对于分析使用多进程或gunicorn工作池的应用程序很有用。py-spy将监控新进程的创建,自动附加到这些进程,并在输出中包含来自这些进程的样本。record视图将在调用栈中包含每个程序的PID和命令行,子进程将显示为其父进程的子进程。

什么时候需要以sudo运行?

py-spy通过从不同的Python进程读取内存来工作,出于安全原因,这可能不被允许,具体取决于你的操作系统和系统设置。在许多情况下,以root用户身份运行(使用sudo或类似方法)可以绕过这些安全限制。OSX始终需要以root身份运行,但在Linux上,这取决于你如何启动py-spy以及系统安全设置。

在Linux上,默认配置是在附加到非子进程时需要root权限。对于py-spy来说,这意味着你可以通过让py-spy创建进程来在没有root访问权限的情况下进行分析(py-spy record -- python myprogram.py),但通过指定PID附加到现有进程通常需要root权限(sudo py-spy record --pid 123456)。 你可以通过设置ptrace_scope sysctl变量来移除Linux上的这个限制。

如何检测线程是否空闲?

py-spy尝试仅包含正在主动运行代码的线程的堆栈跟踪,并排除正在睡眠或其他空闲状态的线程。在可能的情况下,py-spy尝试从操作系统获取这些线程活动信息:在Linux上通过读取/proc/PID/stat,在OSX上使用mach的thread_basic_info调用,在Windows上通过查看当前的SysCall是否已知为空闲

然而,这种方法存在一些限制,可能会导致空闲线程仍被标记为活动。首先,我们必须在暂停程序之前获取这些线程活动信息,因为从暂停的程序中获取这些信息会导致它总是返回空闲状态。这意味着存在潜在的竞争条件,即我们获取线程活动信息后,线程在我们获取堆栈跟踪时可能处于不同的状态。查询操作系统获取线程活动信息的功能在FreeBSD和Linux上的i686/ARM处理器上尚未实现。在Windows上,被IO阻塞的调用目前还不会被标记为空闲,例如从stdin读取输入时。最后,在某些Linux调用中,我们使用的ptrace附加可能会导致空闲线程暂时唤醒,从而在从procfs读取时产生误报。出于这些原因,我们还有一个启发式的备选方案,将Python中某些已知的调用标记为空闲。

你可以通过设置--idle标志来禁用此功能,这将包括py-spy认为是空闲的帧。

GIL检测是如何工作的?

我们通过查看_PyThreadState_Current符号指向的threadid值(对于Python 3.6及更早版本)以及通过在Python 3.7及更高版本中从_PyRuntime结构中确定等效值来获取GIL活动。这些符号可能不包含在你的Python发行版中,这将导致解析哪个线程持有GIL失败。当前的GIL使用情况也会在top视图中显示为%GIL。 传递 --gil 标志将只包含持有全局解释器锁(Global Interpreter Lock)的线程的跟踪。在某些情况下,这可能更准确地反映您的 Python 程序如何使用时间,但您应该注意,这将会遗漏在释放 GIL 但仍然活跃的扩展中的活动。

为什么我在 OSX 上对 /usr/bin/python 进行性能分析时遇到问题?

OSX 有一个名为系统完整性保护(System Integrity Protection)的功能,它阻止即使是 root 用户也无法读取位于 /usr/bin 中的任何二进制文件的内存。不幸的是,这包括 OSX 自带的 Python 解释器。

有几种不同的方法可以解决这个问题:

  • 您可以安装不同的 Python 发行版。内置的 Python 将在未来的 OSX 版本中被移除,而且您可能无论如何都想迁移到 Python 3。
  • 您可以使用 virtualenv 在 SIP 不适用的环境中运行系统 Python。
  • 您可以禁用系统完整性保护。

如何在 Docker 中运行 py-spy?

在 Docker 容器内运行 py-spy 通常也会出现权限被拒绝的错误,即使以 root 身份运行也是如此。

这个错误是由于 Docker 限制了我们使用的 process_vm_readv 系统调用。可以通过在启动 Docker 容器时设置 --cap-add SYS_PTRACE 来覆盖此限制。

或者,您可以编辑 docker-compose.yaml 文件

your_service:
   cap_add:
     - SYS_PTRACE

请注意,您需要重启 Docker 容器才能使此设置生效。

您还可以从主机操作系统使用 py-spy 来对 Docker 容器内运行的进程进行性能分析。

如何在 Kubernetes 中运行 py-spy?

py-spy 需要 SYS_PTRACE 权限才能读取进程内存。Kubernetes 默认会丢弃该权限,导致出现以下错误:

Permission Denied: Try running again with elevated permissions by going 'sudo env "PATH=$PATH" !!'

推荐的解决方法是编辑规范并添加该权限。对于部署来说,这可以通过在 Deployment.spec.template.spec.containers 中添加以下内容来实现:

securityContext:
  capabilities:
    add:
    - SYS_PTRACE

更多详情请参见:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container 请注意,这将移除现有的 Pod 并重新创建它们。

如何在 Alpine Linux 上安装 py-spy?

Alpine Python 选择不使用 manylinux 轮子。您可以通过以下方式覆盖此行为,以使用 pip 在 Alpine 上安装 py-spy:

echo 'manylinux1_compatible = True' > /usr/local/lib/python3.7/site-packages/_manylinux.py

或者,您可以从 GitHub 发布页面下载 musl 二进制文件。

如何避免暂停 Python 程序?

通过设置 --nonblocking 选项,py-spy 不会暂停您正在分析的目标 Python 程序。虽然使用 py-spy 对进程进行采样的性能影响通常非常小,但设置此选项将完全避免中断正在运行的 Python 程序。

设置此选项后,py-spy 将在 Python 进程运行时读取解释器状态。由于我们用于读取内存的调用不是原子的,而且我们必须发出多个调用才能获得堆栈跟踪,这意味着在采样时偶尔会出现错误。这可能表现为采样时出错率增加,或在输出中包含部分堆栈帧。

py-spy 是否支持 32 位 Windows?是否集成 PyPy?是否适用于 Python2 的 USC2 版本?

目前还不支持。

如果您希望在 py-spy 中看到某些功能,请为相应的问题点赞或创建一个描述缺失功能的新问题。

如何在通过管道输出到分页器时强制使用彩色输出?

py-spy 遵循 CLICOLOR 规范,因此在环境中设置 CLICOLOR_FORCE=1 将使 py-spy 即使在通过管道输出到分页器时也能打印彩色输出。

致谢

py-spy 深受 Julia Evans 在 rbspy 上的出色工作的启发。特别是,生成火焰图和 speedscope 文件的代码直接来自 rbspy,而且该项目使用了从 rbspy 衍生出的 read-process-memory 和 proc-maps crates。

许可证

py-spy 根据 MIT 许可证发布,完整文本请参见 LICENSE 文件。

编辑推荐精选

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

热门AI工具AI办公办公工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

模型训练热门AI工具内容创作智能问答AI开发讯飞星火大模型多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

热门AI工具生产力协作转型TraeAI IDE
咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

AI助手热门AI工具AI创作AI辅助写作讯飞绘文内容运营个性化文章多平台分发
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

Hunyuan3D-2

Hunyuan3D-2

高分辨率纹理 3D 资产生成

Hunyuan3D-2 是腾讯开发的用于 3D 资产生成的强大工具,支持从文本描述、单张图片或多视角图片生成 3D 模型,具备快速形状生成能力,可生成带纹理的高质量 3D 模型,适用于多个领域,为 3D 创作提供了高效解决方案。

3FS

3FS

一个具备存储、管理和客户端操作等多种功能的分布式文件系统相关项目。

3FS 是一个功能强大的分布式文件系统项目,涵盖了存储引擎、元数据管理、客户端工具等多个模块。它支持多种文件操作,如创建文件和目录、设置布局等,同时具备高效的事件循环、节点选择和协程池管理等特性。适用于需要大规模数据存储和管理的场景,能够提高系统的性能和可靠性,是分布式存储领域的优质解决方案。

下拉加载更多