Пакет 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.
Вот пример умножения элементов двух массивов с плавающей точкой 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> | 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 | VectorShape выбирает определенную реализацию Vector. |
| VectorShuffle<E> | VectorShuffle представляет упорядоченную неизменяемую последовательность int значений, называемых индексами источника, где каждый индекс источника численно выбирает исходную лань из совместимого Vector. |
| VectorSpecies<E> |
© 1993, 2021, 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/17/docs/api/jdk.incubator.vector/jdk/incubator/vector/package-summary.html