Spec-Zone.ru › NumPy 1.20

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

Цели выравнивания памяти в Numpy

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

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

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

«Истинное» выравнивание относится к архитектурно-зависимому выравниванию эквивалентного C-типа в C. Например, в системах x64 numpy.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, которые контролируют и описывают выравнивание

В Numpy используются 4 соответствующих случая использования слова align.

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

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

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

  1. Создание выровненных структур: для того, чтобы знать, как сместить поле при align=True, Numpy ищет field.dtype.alignment. Это включает поля, которые являются вложенными структурированными массивами.
  2. Функции ufuncs: Если флаг ALIGNED массива равен False, функции ufuncs будут буферизовать/преобразовывать массив перед оценкой. Это необходимо, так как внутренние циклы функций ufunc обращаются к сырым элементам непосредственно, что может привести к ошибке на некоторых архитектурах, если элементы не выровнены по истинному значению.
  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–2020 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.19/reference/alignment.html

Spec-Zone.ru

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