Spec-Zone.ru › NumPy 2.0

Выравнивание памяти

Цели выравнивания NumPy

Существует три случая использования, связанных с выравниванием памяти в NumPy (начиная с версии 1.14):

  1. Создание структурированных типов данных с полями, выровненными как в C-структуре.
  2. Ускорение операций копирования с использованием присваивания uint вместо memcpy.
  3. Гарантирование безопасного выровненного доступа для функций ufuncs/setitem/преобразования.

NumPy использует две разные формы выравнивания для достижения этих целей: «истинное выравнивание» и «выравнивание Uint».

«Истинное» выравнивание относится к архитектурно-зависимому выравниванию эквивалентного C-типа в C. Например, в системах x64 float64 эквивалентно double в C. В большинстве систем это либо 4, либо 8 байт (и это можно контролировать в GCC с помощью опции malign-double). Переменная выровнена в памяти, если ее смещение памяти является кратным ее выравниванию. В некоторых системах (например, sparc) выравнивание памяти обязательно; в других это ускоряет выполнение.

«Выравнивание Uint» зависит от размера типа данных. Оно определяется как «истинное выравнивание» uint, используемого кодом копирования NumPy для копирования типа данных, или неопределенным/невыровненным, если нет эквивалентного uint. В настоящее время NumPy использует uint8, uint16, uint32, uint64, и uint64 для копирования данных размером 1, 2, 4, 8, 16 байт соответственно, а все другие типы данных не могут быть выровнены по Uint.

Например, на типичной системе Linux x64 GCC тип данных NumPy complex64 реализуется как struct { float real, imag; }. Это имеет «истинное» выравнивание 4 и «выравнивание Uint» 8 (равное истинному выравниванию uint64).

Некоторые случаи, где выравнивание Uint и истинное выравнивание отличаются (по умолчанию GCC Linux):

архитектура

тип

истинное выравнивание

выравнивание Uint

x86_64

complex64

4

8

x86_64

float128

16

8

x86

float96

4

-

Переменные в NumPy, которые управляют и описывают выравнивание

Существует 4 важных использования слова align в NumPy:

  • Атрибут dtype.alignment (descr->alignment в C). Он предназначен для отражения «истинного выравнивания» типа. Имеет значения по умолчанию, зависящие от архитектуры, для всех типов данных, за исключением структурированных типов, созданных с использованием align=True, как описано ниже.
  • Флаг ALIGNED массива ndarray, вычисляемый в IsAligned и проверяемый PyArray_ISALIGNED. Он вычисляется из dtype.alignment. Он устанавливается в True, если каждый элемент в массиве находится в месте памяти, согласованном с dtype.alignment, что имеет место, если data ptr и все шаги массива являются кратными этому выравниванию.
  • Ключевое слово align конструктора dtype, которое влияет только на Структурированные массивы. Если смещения полей структуры не заданы вручную, NumPy определяет их автоматически. В этом случае NumPy дополняет структуру, чтобы каждое поле было выровнено по «истинному» значению в памяти, и устанавливает dtype.alignment в наибольшее из «истинных» выравниваний полей. Это аналогично тому, что обычно делают C-структуры. В противном случае, если смещения или размер элемента заданы вручную, align=True просто проверяет, что все поля выровнены по «истинному» значению и что общий размер элемента является кратным наибольшему выравниванию полей. В любом случае dtype.isalignedstruct также устанавливается в True.
  • IsUintAligned используется для определения, является ли ndarray «выровненным по Uint», аналогично тому, как IsAligned проверяет истинное выравнивание.

Последствия выравнивания

Вот как используются переменные выше:

  1. Создание выровненных структур: чтобы знать, как сместить поле при align=True, NumPy ищет field.dtype.alignment. Это включает поля, которые являются вложенными структурированными массивами.
  2. Функции ufuncs: если флаг ALIGNED массива равен False, ufuncs будут буферизовать/преобразовывать массив перед вычислением. Это необходимо, так как внутренние циклы ufuncs обращаются к элементам напрямую, что может привести к ошибкам на некоторых архитектурах, если элементы не выровнены по истинному значению.
  3. Функции getitem/setitem/copyswap: аналогично функциям ufuncs, у них обычно есть два пути кода. Если ALIGNED равен False, они будут использовать путь кода, который буферизует аргументы, чтобы они были выровнены по истинному значению.
  4. Код копирования с шагом: здесь используется «выравнивание Uint». Если размер элемента массива равен 1, 2, 4, 8 или 16 байтам и массив выровнен по Uint, тогда NumPy вместо этого выполнит *(uintN*)dst) = *(uintN*)src) для соответствующего N. В противном случае NumPy копирует, выполняя memcpy(dst, src, N).
  5. Код nditer: поскольку он часто вызывает код копирования с шагом, он должен проверить «выравнивание Uint».
  6. Код преобразования: он проверяет «истинное» выравнивание, так как он выполняет *dst = CASTFUNC(*src) при выравнивании. В противном случае он выполняет memmove(srcval, src); dstval = CASTFUNC(srcval); memmove(dst, dstval), где dstval/srcval выровнены.

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

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

Spec-Zone.ru

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