Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate the Incubating Panama Vector API #12311

Merged
merged 59 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
a02161a
Include the Panama Vector API stubs in the generated 19/20 api jars
ChrisHegarty May 18, 2023
aad69f9
first dotProduct implementation
ChrisHegarty May 18, 2023
ab6300b
fix dimensions check
ChrisHegarty May 18, 2023
d49100c
merge Robert's dotProduct implementation
ChrisHegarty May 18, 2023
a714486
remove public
ChrisHegarty May 18, 2023
39bbc4d
remove doPriv and restructure module lookup
ChrisHegarty May 18, 2023
3edee15
remove unnecessary jvmArgs
ChrisHegarty May 18, 2023
030babd
Move DefaultVectorUtilProvider to it's own top-level class - since it…
ChrisHegarty May 19, 2023
927f1c7
refactor the provider and impl into a separate package
ChrisHegarty May 19, 2023
99f7e41
move to non-exported internal package
ChrisHegarty May 19, 2023
7b58a64
disable assertions in jdk.incubator.vector.LaneType
ChrisHegarty May 19, 2023
abb5979
revert assertion disablement. Check locale is workable
ChrisHegarty May 19, 2023
45b660f
Make sure to use UTC timezone when creating ZIP, so file reproduces o…
uschindler May 19, 2023
89bc0b5
Merge branch 'main' into panama_vector
uschindler May 19, 2023
0779fcb
simplify locale sensitive check - as per Uwe's suggestion
ChrisHegarty May 19, 2023
d3fe388
move back into util package, and make package-private. Some minor ren…
ChrisHegarty May 19, 2023
27ea8f2
Better filter classes and configure modules to include by java version
uschindler May 20, 2023
568a0c0
Remove unused code
uschindler May 20, 2023
bd9f479
Remove comment
uschindler May 20, 2023
74e6eb3
Only enable the vector module in Java 20
uschindler May 20, 2023
d6ff862
Further simplify extractor (and fix a bug where supers and interfaces…
uschindler May 20, 2023
45c00ae
Use a TreeMap of class names instead of sorting files. This also make…
uschindler May 20, 2023
f0c36f7
Print error on misconfiguration
uschindler May 20, 2023
3ed660f
Add warnings when vector module is note enabled or Lucene is running …
uschindler May 20, 2023
f1d4aad
tidy
uschindler May 20, 2023
afc3d55
speed up vector computation: more efficient reduction, 4x unrolling
rmuir May 21, 2023
b051a52
spotless
rmuir May 21, 2023
3a6cb81
vectorize the dotproduct(byte[], byte[]), initial impl
rmuir May 22, 2023
026091b
speed up dotproduct(byte[],byte[]) on 128bit vectors
rmuir May 22, 2023
956d402
speed up avx512 dotproduct(byte[],byte[])
rmuir May 22, 2023
83c26d8
add vectorized binary euclidean and cosine functions
rmuir May 22, 2023
2ca381b
remove bad javadocs sentence
rmuir May 22, 2023
38fe5c5
add vectorized float euclidean and cosine impls
rmuir May 23, 2023
8708251
INT_SPECIES_PREFERRED_BIT_SIZE
ChrisHegarty May 23, 2023
11e6634
remove comments
ChrisHegarty May 23, 2023
97ebe5b
Cleanup and rename constants and move to top of class file
uschindler May 23, 2023
919f0e4
Add a test comparing both providers (if available)
uschindler May 23, 2023
c8e5b6a
DELTA should be double to match signatures
uschindler May 23, 2023
609fc9b
Fix wrongly-named test parameter
uschindler May 23, 2023
74a9782
disable when vector bit size < 128
ChrisHegarty May 23, 2023
32a2a58
Use a varhandle to read the preferred vector size (spares extra catch…
uschindler May 23, 2023
e174526
Change loglevel to INFO like MMapDir
uschindler May 23, 2023
3007a61
Move success logging to after finding constructor (calling ctor canno…
uschindler May 23, 2023
1681757
Move logging to constructor of provider (like in MMap)
uschindler May 23, 2023
f9711e9
Move all logic to the provider class. It thows UOE on constructor if …
uschindler May 23, 2023
87348cf
try to prevent using vector api if c2 is disabled. untested, please d…
rmuir May 23, 2023
2b57e7d
satisfy linter
rmuir May 23, 2023
5d0206c
Add accesscontroller when reading sysprop; refactor code
uschindler May 23, 2023
fc0a79a
on CI builds don't disable C2 and pass no extra args to VM
uschindler May 23, 2023
6ecf445
Remove check (we bail out in ctor already)
uschindler May 23, 2023
6a18ba3
JDK-8301190 is fixed in 20.0.2, only disable prior to that update
ChrisHegarty May 24, 2023
5a54f9e
spotless
ChrisHegarty May 24, 2023
e3ea49f
Restructure the "Turkish vector bug"
uschindler May 24, 2023
1cd15f3
Remove throws clause (relic)
uschindler May 24, 2023
e898401
don't use integer vectors on x86 unless we have AVX2 or AVX3
rmuir May 24, 2023
8da5432
Rename some gradle files and apijars
uschindler May 24, 2023
fe8abaf
Track references to superclasses and interfaces correctly
uschindler May 24, 2023
8a6a33c
add changes
uschindler May 24, 2023
dd4eaac
Merge remote-tracking branch 'remotes/origin/main' into panama_vector
uschindler May 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gradle/java/memorysegment-mrjar.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ configure(project(":lucene:core")) {
"-Xlint:-options",
"--patch-module", "java.base=${apijar}",
"--add-exports", "java.base/java.lang.foreign=ALL-UNNAMED",
"--add-exports", "java.base/jdk.incubator.vector=ALL-UNNAMED", // This is a hack, but does it matter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can live with this. If so, then we should have a more suitable comment.

// just patch into java.base since that is already resolved and present

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it is a hack, but we should maybe say "it's ok because it works for compilation and has no effect on runtime or classfile output.

Renaming the apijars to be more general should be a separate PR as it needs aligning and conflict resolution with the already open java 21 one for mmap.

]
}
}
Expand Down
2 changes: 1 addition & 1 deletion gradle/testing/defaults-tests.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ allprojects {

// Lucene needs to optional modules at runtime, which we want to enforce for testing
// (if the runner JVM does not support them, it will fail tests):
jvmArgs '--add-modules', 'jdk.unsupported,jdk.management'
jvmArgs '--add-modules', 'jdk.unsupported,jdk.management,jdk.incubator.vector'
ChrisHegarty marked this conversation as resolved.
Show resolved Hide resolved
uschindler marked this conversation as resolved.
Show resolved Hide resolved

uschindler marked this conversation as resolved.
Show resolved Hide resolved
def loggingConfigFile = layout.projectDirectory.file("${resources}/logging.properties")
def tempDir = layout.projectDirectory.dir(testsTmpDir.toString())
Expand Down
206 changes: 141 additions & 65 deletions lucene/core/src/java/org/apache/lucene/util/VectorUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,19 @@

package org.apache.lucene.util;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.Logger;

/** Utilities for computations with numeric arrays */
public final class VectorUtil {

private static final Logger LOG = Logger.getLogger(VectorUtil.class.getName());

private static final VectorUtilProvider PROVIDER;

private VectorUtil() {}

/**
Expand All @@ -28,71 +38,7 @@ private VectorUtil() {}
* @throws IllegalArgumentException if the vectors' dimensions differ.
*/
public static float dotProduct(float[] a, float[] b) {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
float res = 0f;
/*
* If length of vector is larger than 8, we use unrolled dot product to accelerate the
* calculation.
*/
int i;
for (i = 0; i < a.length % 8; i++) {
res += b[i] * a[i];
}
if (a.length < 8) {
return res;
}
for (; i + 31 < a.length; i += 32) {
res +=
b[i + 0] * a[i + 0]
+ b[i + 1] * a[i + 1]
+ b[i + 2] * a[i + 2]
+ b[i + 3] * a[i + 3]
+ b[i + 4] * a[i + 4]
+ b[i + 5] * a[i + 5]
+ b[i + 6] * a[i + 6]
+ b[i + 7] * a[i + 7];
res +=
b[i + 8] * a[i + 8]
+ b[i + 9] * a[i + 9]
+ b[i + 10] * a[i + 10]
+ b[i + 11] * a[i + 11]
+ b[i + 12] * a[i + 12]
+ b[i + 13] * a[i + 13]
+ b[i + 14] * a[i + 14]
+ b[i + 15] * a[i + 15];
res +=
b[i + 16] * a[i + 16]
+ b[i + 17] * a[i + 17]
+ b[i + 18] * a[i + 18]
+ b[i + 19] * a[i + 19]
+ b[i + 20] * a[i + 20]
+ b[i + 21] * a[i + 21]
+ b[i + 22] * a[i + 22]
+ b[i + 23] * a[i + 23];
res +=
b[i + 24] * a[i + 24]
+ b[i + 25] * a[i + 25]
+ b[i + 26] * a[i + 26]
+ b[i + 27] * a[i + 27]
+ b[i + 28] * a[i + 28]
+ b[i + 29] * a[i + 29]
+ b[i + 30] * a[i + 30]
+ b[i + 31] * a[i + 31];
}
for (; i + 7 < a.length; i += 8) {
res +=
b[i + 0] * a[i + 0]
+ b[i + 1] * a[i + 1]
+ b[i + 2] * a[i + 2]
+ b[i + 3] * a[i + 3]
+ b[i + 4] * a[i + 4]
+ b[i + 5] * a[i + 5]
+ b[i + 6] * a[i + 6]
+ b[i + 7] * a[i + 7];
}
return res;
return PROVIDER.dotProduct(a, b);
}

/**
Expand Down Expand Up @@ -270,4 +216,134 @@ public static float dotProductScore(byte[] a, byte[] b) {
float denom = (float) (a.length * (1 << 15));
return 0.5f + dotProduct(a, b) / denom;
}

interface VectorUtilProvider {

// just dot product for now
float dotProduct(float[] a, float[] b);
}

private static VectorUtilProvider lookupProvider() {
// TODO: add a check
final int runtimeVersion = Runtime.version().feature();
if (runtimeVersion == 20) { // TODO: do we want JDK 19?
try {
ensureReadability();
ChrisHegarty marked this conversation as resolved.
Show resolved Hide resolved
final var lookup = MethodHandles.lookup();
final var cls = lookup.findClass("org.apache.lucene.util.JDKVectorUtilProvider");
// we use method handles, so we do not need to deal with setAccessible as we have private
// access through the lookup:
final var constr = lookup.findConstructor(cls, MethodType.methodType(void.class));
try {
return (VectorUtilProvider) constr.invoke();
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable th) {
throw new AssertionError(th);
}
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new LinkageError("JDKVectorUtilProvider is missing correctly typed constructor", e);
} catch (ClassNotFoundException cnfe) {
throw new LinkageError("JDKVectorUtilProvider is missing in Lucene JAR file", cnfe);
}
} else if (runtimeVersion >= 21) {
LOG.warning(
"You are running with Java 21 or later. To make full use of the Vector API, please update Apache Lucene.");
}
return new LuceneVectorUtilProvider();
}

// Extracted to a method to be able to apply the SuppressForbidden annotation
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static <T> T doPrivileged(PrivilegedAction<T> action) {
return AccessController.doPrivileged(action);
}

static void ensureReadability() {
ModuleLayer.boot().modules().stream()
.filter(m -> m.getName().equals("jdk.incubator.vector"))
.findFirst()
.ifPresentOrElse(
vecMod -> VectorUtilProvider.class.getModule().addReads(vecMod),
() -> LOG.warning("vector incubator module not present"));
}

static {
PROVIDER =
ChrisHegarty marked this conversation as resolved.
Show resolved Hide resolved
doPrivileged(VectorUtil::lookupProvider); // TODO check what permissions we actually need
}

static final class LuceneVectorUtilProvider implements VectorUtilProvider {

@Override
public float dotProduct(float[] a, float[] b) {
if (a.length != b.length) {
throw new IllegalArgumentException(
"vector dimensions differ: " + a.length + "!=" + b.length);
}
float res = 0f;
/*
* If length of vector is larger than 8, we use unrolled dot product to accelerate the
* calculation.
*/
int i;
for (i = 0; i < a.length % 8; i++) {
res += b[i] * a[i];
}
if (a.length < 8) {
return res;
}
for (; i + 31 < a.length; i += 32) {
res +=
b[i + 0] * a[i + 0]
+ b[i + 1] * a[i + 1]
+ b[i + 2] * a[i + 2]
+ b[i + 3] * a[i + 3]
+ b[i + 4] * a[i + 4]
+ b[i + 5] * a[i + 5]
+ b[i + 6] * a[i + 6]
+ b[i + 7] * a[i + 7];
res +=
b[i + 8] * a[i + 8]
+ b[i + 9] * a[i + 9]
+ b[i + 10] * a[i + 10]
+ b[i + 11] * a[i + 11]
+ b[i + 12] * a[i + 12]
+ b[i + 13] * a[i + 13]
+ b[i + 14] * a[i + 14]
+ b[i + 15] * a[i + 15];
res +=
b[i + 16] * a[i + 16]
+ b[i + 17] * a[i + 17]
+ b[i + 18] * a[i + 18]
+ b[i + 19] * a[i + 19]
+ b[i + 20] * a[i + 20]
+ b[i + 21] * a[i + 21]
+ b[i + 22] * a[i + 22]
+ b[i + 23] * a[i + 23];
res +=
b[i + 24] * a[i + 24]
+ b[i + 25] * a[i + 25]
+ b[i + 26] * a[i + 26]
+ b[i + 27] * a[i + 27]
+ b[i + 28] * a[i + 28]
+ b[i + 29] * a[i + 29]
+ b[i + 30] * a[i + 30]
+ b[i + 31] * a[i + 31];
}
for (; i + 7 < a.length; i += 8) {
res +=
b[i + 0] * a[i + 0]
+ b[i + 1] * a[i + 1]
+ b[i + 2] * a[i + 2]
+ b[i + 3] * a[i + 3]
+ b[i + 4] * a[i + 4]
+ b[i + 5] * a[i + 5]
+ b[i + 6] * a[i + 6]
+ b[i + 7] * a[i + 7];
}
return res;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.util;

import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;

public final class JDKVectorUtilProvider implements VectorUtil.VectorUtilProvider {
ChrisHegarty marked this conversation as resolved.
Show resolved Hide resolved

static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;

public JDKVectorUtilProvider() {}

@Override
public float dotProduct(float[] a, float[] b) {
var upperBound = SPECIES.loopBound(a.length);
var sum = FloatVector.zero(SPECIES);
var i = 0;
for (; i < upperBound; i += SPECIES.length()) {
var va = FloatVector.fromArray(SPECIES, a, i);
var vb = FloatVector.fromArray(SPECIES, b, i);
sum = va.fma(vb, sum);
}
var c = sum.reduceLanes(VectorOperators.ADD);
for (; i < a.length; i++) { // tail loop
c += a[i] * b[i];
}
return c;
}
}