Spec-Zone.ru › NumPy 1.17

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

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

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

  1. Создание структурированных типов данных с выровненными полями, как в C-структуре.
  2. Ускорение операций копирования, используя присваивание uint вместо memcpy
  3. Обеспечение безопасного выровненного доступа для функций ufunc/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. Функции ufunc: Если флаг ALIGNED массива равен False, функции ufunc буферизуют/приводят массив к типу перед оценкой. Это необходимо, поскольку внутренние циклы функций ufunc обращаются к элементам напрямую, что может привести к ошибкам на некоторых архитектурах, если элементы не являются истинно-выровненными.
  3. Функции getitem/setitem/copyswap: Аналогично функциям ufunc, эти функции, как правило, имеют два пути кода. Если 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–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.17.0/reference/alignment.html

Spec-Zone.ru

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