Пакет jdk.incubator.vector
Экспериментальная функция. Будет удалена в будущей версии.
Этот пакет предоставляет классы для выражения векторных вычислений, которые, при подходящем оборудовании и возможностях среды выполнения, ускоряются с помощью векторных инструкций аппаратного обеспечения.
Вектор представляет собой последовательность фиксированного числа элементов, каждый из которых имеет фиксированный тип элемента, такой как byte, long, или float. Каждый элемент содержит независимое значение типа элемента. Операции над векторами обычно выполняются поэлементно, распределяя некоторый скалярный оператор (такой как сложение) по элементам участвующих векторов, обычно генерируя результирующий вектор, элементы которого содержат различные скалярные результаты. При выполнении на поддерживающей платформе поэлементные операции могут выполняться параллельно аппаратным обеспечением. Этот стиль параллелизма называется параллелизмом Single Instruction Multiple Data (SIMD).
В стиле программирования SIMD большинство операций внутри элемента вектора являются безусловными, но эффект условного выполнения может быть достигнут с помощью маскированных операций, таких как blend(), под управлением связанной VectorMask. Перемещение данных, отличное от строго поэлементного потока, достигается с помощью межэлементных операций, часто под управлением связанного VectorShuffle. Данные элементов и/или целые векторы могут быть переформатированы с помощью различных видов поэлементных преобразований и байтового переформатирования переинтерпретаций, часто под управлением рефлексивного объекта VectorSpecies, который выбирает альтернативный формат вектора, отличающийся от входного вектора.
Vector<E> объявляет набор векторных операций (методов), общих для всех типов элементов. Эти общие операции включают общий доступ к значениям элементов, выбор и перемещение данных, переформатирование, а также некоторые арифметические и логические операции (такие как сложение или сравнение), общие для всех примитивных типов.
Общедоступные подтипы Vector соответствуют определённым типам элементов. Они объявляют дополнительные операции, специфичные для этого типа элемента, включая доступ к значениям элементов без упаковки, битовые операции над значениями целых типов элементов или трансцендентные операции над значениями типов с плавающей запятой.
Некоторые поэлементные операции, такие как оператор add, определены как полная названная операция, где соответствующий метод в Vector предоставляется в маскированных и не-маскированных перегрузках, а (в подклассах) также предоставляются ковариативные переопределения (возвращающие подкласс) и дополнительные перегрузки с широковещательной передачей скалярного значения (как маскированные, так и не-маскированные). Другие поэлементные операции, такие как оператор min, определены как частично реализованные (не полные) названные операции, где соответствующий метод в Vector и/или подклассе предоставляют некоторые, но не все возможные перегрузки и переопределения (обычно не-маскированный вариант с широковещательной передачей скалярных значений). Наконец, все поэлементные операции (названные как описано выше или другие методы) имеют соответствующий operator token, объявленный как статическая константа в VectorOperators. Каждый оператор определяет символическое выражение Java для операции, например a + b для операторного токена ADD. Общие методы, принимающие токен поэлементной операции, такие как поэлементная унарная операция, предоставляются в Vector и имеют те же варианты, что и полная названная операция.
Этот пакет содержит общедоступный подтип Vector, соответствующий каждому поддерживаемому типу элементов: ByteVector, ShortVector, IntVector, LongVector, FloatVector и DoubleVector.
Вот пример умножения элементов двух массивов float a и b с использованием векторных вычислений и сохранением результата в массиве c.
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
void vectorMultiply(float[] a, float[] b, float[] c) {
// It is assumed array arguments are of the same size
for (int i = 0; i < a.length; i += SPECIES.length()) {
VectorMask<Float> m = SPECIES.indexInRange(i, a.length);
FloatVector va = FloatVector.fromArray(SPECIES, a, i, m);
FloatVector vb = FloatVector.fromArray(SPECIES, b, i, m);
FloatVector vc = va.mul(vb)
vc.intoArray(c, i, m);
}
}
В приведенном выше примере мы используем маски, сгенерированные indexInRange(), чтобы предотвратить чтение/запись за пределами длины массива. Первые a.length / SPECIES.length() итерации будут иметь маску со всеми элементами установленным значением. Только последняя итерация (если a.length не кратно SPECIES.length()) будет иметь маску с первыми a.length % SPECIES.length() элементами установленным значением. Поскольку маска используется во всех итерациях, данная реализация может не обеспечить оптимальной производительности (для больших длин массивов). То же самое вычисление можно реализовать без масок следующим образом:
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
void vectorMultiply(float[] a, float[] b, float[] c) {
int i = 0;
// It is assumed array arguments are of the same size
for (; i < SPECIES.loopBound(a.length); i += SPECIES.length()) {
FloatVector va = FloatVector.fromArray(SPECIES, a, i);
FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
FloatVector vc = va.mul(vb)
vc.intoArray(c, i);
}
for (; i < a.length; i++) {
c[i] = a[i] * b[i];
}
}
Скалярные вычисления после векторных вычислений необходимы для обработки хвоста элементов массива TLENGTH, где TLENGTH < SPECIES.length() для вида вектора. Приведенные выше примеры используют предпочтительный вид (FloatVector.SPECIES_PREFERRED), обеспечивая динамическое соответствие оптимальной форме для платформы, на которой выполняется код. Вспомогательный метод loopBound() используется в приведенном выше коде для определения конца цикла вектора. Примитивное выражение маскирования, например, (a.length & ~(SPECIES.length() - 1)), также может быть здесь использовано, так как SPECIES.length() известно как 8, что является степенью двойки. Но это не всегда верное предположение. Например, если FloatVector.SPECIES_PREFERRED оказывается иметь зависящую от платформы форму S_Max_BIT, а эта форма имеет некоторое странное гипотетическое значение, например 384 (что является допустимым размером вектора по некоторым архитектурам), тогда вручную настроенное выражение маскирования может дать неожиданные результаты.
Примечания по производительности
Этот пакет зависит от способности среды выполнения динамически компилировать векторные операции в оптимальные векторные инструкции аппаратного обеспечения. Для каждой операции существует реализация по умолчанию на скалярной основе, которая используется, если операция не может быть скомпилирована в векторные инструкции.Пользователям следует обратить внимание на следующие моменты для генерации оптимального кода векторной машины:
- Формат используемых векторов должен поддерживаться базовой платформой. Например, код, написанный с использованием
IntVectorвидаVectorShapeS_512_BIT, не будет скомпилирован в векторные инструкции на платформе, которая поддерживает только 256-битные векторы. Вместо этого будет использоваться реализация по умолчанию на скалярной основе. Поэтому рекомендуется использовать предпочтительный вид, как показано выше, для написания векторных вычислений с обобщённым размером. - Большинство классов, определённых в этом пакете, следует рассматривать как классы базирующиеся на значении. Это относится к
Vectorи его подтипам,VectorMask,VectorShuffleиVectorSpecies. При использовании этих типов операции, чувствительные к идентичности, такие как==, могут давать непредсказуемые результаты или снизить производительность. Необычно, ноv.equals(w)может быть быстрее, чемv==w, так какequals— не операция, чувствительная к идентичности. Кроме того, эти объекты могут храниться в локальных переменных и параметрах, а также как константыstatic final, но их хранение в других полях Java или элементах массивов, хотя и семантически допустимо, может повлиять на производительность.
Для каждого класса в этом пакете, если не указано иное, все аргументы метода ссылочного типа не должны быть равны null, и любой аргумент null вызовет NullPointerException. Этот факт не документируется индивидуально для методов данного API.
| Класс | Описание |
|---|---|
| ByteVector | Специализированный Vector, представляющий упорядоченную неизменяемую последовательность значений byte. |
| DoubleVector | Специализированный Vector, представляющий упорядоченную неизменяемую последовательность значений double. |
| FloatVector | Специализированный Vector, представляющий упорядоченную неизменяемую последовательность значений float. |
| IntVector | Специализированный Vector, представляющий упорядоченную неизменяемую последовательность значений int. |
| LongVector | Специализированный Vector, представляющий упорядоченную неизменяемую последовательность значений long. |
| ShortVector | Специализированный Vector, представляющий упорядоченную неизменяемую последовательность значений short. |
| Vector<E> | Последовательность фиксированного числа лейнов, всех одного фиксированного типа элемента, например, byte, long, или float. |
| VectorMask<E> | A VectorMask представляет собой упорядоченную неизменяемую последовательность значений boolean. |
| VectorOperators | Этот класс состоит только из статических констант, описывающих векторные операции на уровне лейнов, плюс вложенные интерфейсы, которые их классифицируют. |
| VectorOperators.Associative | Тип всех реассоциирующих операторов на уровне лейнов, используемых в выражениях, таких как e = v0.reduceLanes(ADD). |
| VectorOperators.Binary | Тип всех операторов на уровне лейнов бинарных (двух аргументных), используемых в выражениях, таких как w = v0.lanewise(ADD, v1). |
| VectorOperators.Comparison | Тип всех бинарных поэлементных булевых сравнений значений лейнов, используемых в выражениях, таких как m = v0.compare(LT, v1). |
|
VectorOperators.Conversion<E, |
Тип всех поэлементных преобразований значений лейнов, используемых в выражениях, таких как w1 = v0.convert(I2D, 1). |
| VectorOperators.Operator | Корневой тип для всех операторных токенов, предоставляющий запросы для общих свойств, таких как арность, типы аргументов и возвращаемого значения, символьное имя и имя оператора. |
| VectorOperators.Ternary | Тип всех поэлементных тернарных (трёх-аргументных) операторов, используемых в выражениях, таких как w = v0.lanewise(FMA, v1, v2). |
| VectorOperators.Test | Тип всех унарных поэлементных булевых проверок значений лейнов, используемых в выражениях, таких как m = v0.test(IS_FINITE). |
| VectorOperators.Unary | Тип всех поэлементных унарных (одно-аргументных) операторов, используемых в выражениях, таких как w = v0.lanewise(NEG). |
| VectorShape | A VectorShape выбирает определённую реализацию Vectors. |
| VectorShuffle<E> | A VectorShuffle представляет собой упорядоченную неизменяемую последовательность значений int называемых индексами источника, где каждый индекс источника численно выбирает исходный лейн из совместимого Vector. |
| VectorSpecies<E> |
© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/jdk.incubator.vector/jdk/incubator/vector/package-summary.html