Spec-Zone.ru › NumPy 1.21

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

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

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

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

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

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

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

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

Сборка Python для отладки для поиска утечек памяти

Сборки Python для отладки легко доступны, например, на debian системах и могут использоваться на всех платформах. Запуск теста или терминала обычно так же прост, как:

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

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

Сборка Python для отладки поможет:

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

    sys.gettotalrefcount()
    sys.getallocatedblocks()
    

Использование вместе с 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 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–2022 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.21/dev/development_advanced_debugging.html

Spec-Zone.ru

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