调试C扩展#

Pandas使用精选C扩展来实现高性能IO操作。如果您需要调试这些扩展的段错误或一般问题,以下步骤可能会很有帮助。

首先,确保使用适当的标志编译扩展以生成调试符号并删除优化。这可以通过以下方式实现:

python setup.py build_ext --inplace -j4 --with-debugging-symbols

使用调试器#

假设您使用的是类Unix操作系统,则可以使用lldb或gdb进行调试。两者之间的选择在很大程度上取决于您的编译工具链--如果使用clang,通常会使用lldb;如果使用GCC,通常会使用gdb。对于MacOS用户,请注意 gcc 在现代系统中是 clang 因此,如果使用Xcode,您通常会选择lldb。无论您选择哪种调试器,请参考您的操作系统说明以了解如何安装。

在安装调试器之后,您可以创建一个脚本来访问您希望调试的扩展模块。出于演示目的,我们假设您有一个名为 debug_testing.py 内容如下:

import pandas as pd

pd.DataFrame([[1, 2]]).to_json()

放置 debug_testing.py 在项目根目录中编写脚本,并在调试器下启动一个Python进程。如果使用lldb:

lldb python

如果使用gdb:

gdb python

在执行我们的脚本之前,让我们在JSON序列化程序的入口函数中设置一个断点 objToJSON 。Lldb语法如下所示:

breakpoint set --name objToJSON

GDB也是如此:

break objToJSON

备注

您可能会收到一条警告,提示您无法在lldb中解析此断点。GDB可能会给出类似的警告,并提示您在将来的库加载时设置断点,您应该对此表示同意。这应该只在第一次调用时发生,因为您希望调试的模块尚未加载到内存中。

现在继续执行您的脚本:

run <the_script>.py

代码执行将在定义的断点处或发生任何段错误时暂停。LLDB的 GDB to LLDB command map 提供可以使用任一调试器执行的调试器命令的列表。

在lldb下执行整个测试套件的另一种选择是运行以下命令:

lldb -- python -m pytest

或用于GDB

gdb --args python -m pytest

进程启动后,只需键入 run 并且测试套件将开始,在可能发生的任何分段错误处停止。

使用valgrind检查内存泄漏#

您可以使用 Valgrind 检查并记录扩展中的内存泄漏。例如,要检查套件测试中的内存泄漏,您可以运行:

PYTHONMALLOC=malloc valgrind --leak-check=yes --track-origins=yes --log-file=valgrind-log.txt python -m pytest <path_to_a_test>

请注意,在valgrind下执行代码所需的时间将比平时长得多。虽然您可以对使用任何优化级别编译的扩展运行valgrind,但建议从编译的扩展中关闭优化,以减少误报。这个 --with-debugging-symbols 在程序包安装过程中传递的标志将自动为您完成此操作。

备注

为了获得最佳结果,您应该使用配置了Valgrind支持的Python安装运行(--with-valgrind)