Spec-Zone.ru › NumPy 2.0

Инструменты расширенной отладки

Если вы дошли до этого раздела, вы хотите углубиться в использование или применять более продвинутые инструменты. Обычно это не требуется для первоначальных участников и для повседневной разработки. Эти инструменты используются реже, например, перед выпуском новой версии NumPy или при внесении крупных или особенно сложных изменений.

Поскольку не все эти инструменты используются регулярно и доступны только на некоторых системах, ожидайте различий, проблем или особенностей; мы будем рады помочь, если вы застрянете, и ценим любые улучшения или предложения по этим рабочим процессам.

Поиск ошибок C с дополнительными инструментами

Для большинства задач разработки не потребуется больше, чем стандартная система отладки, как показано в Отладка. Однако, например, утечки памяти могут быть особенно скрытыми или сложными для выявления.

Мы не ожидаем, что эти инструменты будут использоваться большинством участников. Однако вы можете помочь нам легче отслеживать такие проблемы:

  • Тесты должны покрывать все пути кода, включая пути ошибок.
  • Старайтесь писать короткие и простые тесты. Если у вас очень сложный тест, подумайте о создании дополнительного более простого теста. Это может быть полезно, потому что часто легко найти тест, который вызывает проблему, но не строку кода теста.
  • Никогда не используйте np.empty при чтении/использовании данных. valgrind заметит это и сообщит об ошибке. Если значения не важны, можно сгенерировать случайные значения вместо них.

Это поможет нам выявить любые упущения до выпуска вашего изменения и означает, что вам не нужно беспокоиться об ошибках подсчёта ссылок, которые могут быть пугающими.

Отладочная сборка Python

Отладочные сборки Python легко доступны, например, через менеджер пакетов системы на Linux-системах, но также доступны и на других платформах, возможно, в менее удобном формате. Если вы не можете легко установить отладочную сборку Python из менеджера пакетов системы, вы можете создать её самостоятельно с помощью pyenv. Например, для установки и глобальной активации отладочной сборки Python 3.10.8 можно выполнить:

pyenv install -g 3.10.8
pyenv global 3.10.8

Обратите внимание, что pyenv install компилирует Python из исходного кода, поэтому необходимо убедиться, что зависимости Python установлены до компиляции. См. документацию pyenv для инструкций по установке, специфичных для платформы. Вы можете использовать pip для установки необходимых зависимостей Python для вашей сессии отладки. Если нет debug-пакета для pypi,, вам необходимо скомпилировать зависимости из исходного кода и убедиться, что ваши зависимости также скомпилированы как debug-сборки.

Часто отладочные сборки Python называют исполняемый файл Python pythond вместо python. Чтобы проверить, установлена ли у вас отладочная сборка Python, вы можете запустить, например, pythond -m sysconfig для получения конфигурации сборки для исполняемого файла Python. Отладочная сборка будет скомпилирована с отладочными параметрами компилятора в CFLAGS (например, -g -Og).

Запуск тестов NumPy или интерактивной оболочки обычно выполняется так же просто, как:

python3.8d runtests.py
# or
python3.8d runtests.py --ipython

и уже упоминался в Отладке.

Отладочная сборка Python поможет:

  • Найти ошибки, которые могут в противном случае привести к непредсказуемому поведению. Одним примером является ситуация, когда объект по-прежнему используется после того, как он был удалён.
  • Отладочные сборки Python позволяют проверить правильность подсчёта ссылок. Для этого используются дополнительные команды:

    sys.gettotalrefcount()
    sys.getallocatedblocks()
    
  • Отладочные сборки Python упрощают отладку с помощью gdb и других отладчиков C.

Использование вместе с pytest

Запуск набора тестов только с отладочной сборкой Python не найдёт многие ошибки самостоятельно. Дополнительным преимуществом отладочной сборки Python является возможность обнаружения утечек памяти.

Инструментом для упрощения этого является pytest-leaks, который можно установить с помощью pip. К сожалению, сам pytest может иметь утечки памяти, но обычно (в настоящее время) можно добиться хороших результатов, удалив:

@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
    doctest_namespace['np'] = numpy

@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
    monkeypatch.setenv('PYTHONHASHSEED', '0')

из numpy/conftest.py (Это может измениться с новыми версиями pytest-leaks или обновлениями pytest).

Это позволяет удобно запустить набор тестов или часть его:

python3.8d runtests.py -t numpy/_core/tests/test_multiarray.py -- -R2:3 -s

где -R2:3 это команда pytest-leaks (см. её документацию), -s приводит к выводу на экран и может быть необходима (в некоторых версиях выводимый вывод детектировался как утечка).

Обратите внимание, что некоторые тесты известны (или даже разработаны) для утечек ссылок, мы стараемся их отметить, но ожидаем некоторых ложных срабатываний.

valgrind

Valgrind — мощный инструмент для поиска определённых проблем с доступом к памяти и должен использоваться для сложного C-кода. Базовое использование valgrind обычно не требует более чем:

PYTHONMALLOC=malloc valgrind python runtests.py

где PYTHONMALLOC=malloc необходимо, чтобы избежать ложных срабатываний со стороны самого Python. В зависимости от системы и версии valgrind, вы можете столкнуться с более ложными срабатываниями. valgrind поддерживает «подавления», чтобы игнорировать некоторые из них, и у Python есть файл подавления (даже опция компиляции), которые могут помочь, если это необходимо.

Valgrind помогает:

  • Найти использование неинициализированных переменных/памяти.
  • Обнаружить нарушения доступа к памяти (чтение или запись за пределами выделенной памяти).
  • Найти множество утечек памяти. Обратите внимание, что для большинства утечек подход с отладочной сборкой Python (и pytest-leaks) гораздо более чувствителен. Причина в том, что valgrind может обнаружить только то, что память определённо потеряна. Если:

    dtype = np.dtype(np.int64)
    arr.astype(dtype=dtype)
    

    имеет неправильный подсчёт ссылок для dtype, это ошибка, но valgrind не может её увидеть, потому что np.dtype(np.int64) всегда возвращает тот же объект. Однако не все типы данных являются синглтонами, поэтому это может привести к утечке памяти для различных входных данных. В редких случаях NumPy использует malloc а не менеджеры памяти Python, которые не видны для отладочной сборки Python. malloc обычно следует избегать, но есть исключения (например, структура PyArray_Dims — это публичный API и не может использовать менеджеры памяти Python).

Несмотря на то, что использование valgrind для обнаружения утечек памяти медленное и менее чувствительное, оно может быть удобным: вы можете запускать большинство программ с valgrind без модификаций.

Следует учитывать:

  • Valgrind не поддерживает longdouble, это означает, что тесты будут провалены или помечены как ошибки, которые являются вполне допустимыми.
  • Ожидайте некоторые ошибки до и после выполнения вашего кода NumPy.
  • Кэши могут означать, что ошибки (в частности, утечки памяти) могут не быть обнаружены или обнаруживаются позже, в несвязанное время.

Большим преимуществом valgrind является то, что у него нет требований помимо самого valgrind (хотя вы, вероятно, захотите использовать отладочные сборки для лучших отслеживаний).

Использование вместе с pytest

Вы можете запустить набор тестов с помощью valgrind, что может быть достаточно, если вы заинтересованы только в нескольких тестах:

PYTHOMMALLOC=malloc valgrind python runtests.py \
 -t numpy/_core/tests/test_multiarray.py -- --continue-on-collection-errors

Обратите внимание на --continue-on-collection-errors, которая в настоящее время необходима из-за отсутствия поддержки longdouble , что приводит к ошибкам (обычно это не нужно, если вы не запускаете весь набор тестов).

Если вы хотите обнаружить утечки памяти, вам также понадобятся --show-leak-kinds=definite и, возможно, дополнительные параметры valgrind. Как и для pytest-leaks , некоторые тесты известны тем, что вызывают ошибки в valgrind и могут или не могут быть помечены как таковые.

Мы разработали pytest-valgrind, который:

  • Отчитывается об ошибках для каждого теста индивидуально
  • Сужает утечки памяти до отдельных тестов (по умолчанию valgrind проверяет только утечки памяти после остановки программы, что очень неудобно).

См. его README для получения дополнительной информации (он включает пример команды для NumPy).

© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/dev/development_advanced_debugging.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API