gianm commented on code in PR #19768:
URL: https://github.com/apache/druid/pull/19768#discussion_r3786703422
##########
processing/src/main/java/org/apache/druid/math/expr/ExpressionProcessingConfig.java:
##########
@@ -70,6 +75,7 @@ public ExpressionProcessingConfig(
"true"
);
this.useVectorApi = getWithPropertyFallbackFalse(useVectorApi,
USE_VECTOR_API);
+ this.useVectorMathApi = getWithPropertyFallbackFalse(useVectorMathApi,
USE_VECTOR_MATH_API);
Review Comment:
IMO this should be `true` by default, since I believe most people that
enable `useVectorApi` will want this. Setting it to `false` is a niche thing.
##########
processing/src/main/java/org/apache/druid/math/expr/ExpressionProcessing.java:
##########
@@ -99,6 +99,22 @@ public static boolean useVectorApi()
return INSTANCE.useVectorApi();
}
+ /**
+ * Whether SIMD dispatch is allowed for math ops backed by the JDK's
VO_MATHLIB path (LOG, EXP, SIN, etc). Off by
+ * default; opt-in via {@link
ExpressionProcessingConfig#USE_VECTOR_MATH_API}, and additionally requires
+ * {@link #useVectorApi()}.
+ *
+ * <p>These ops route through Intel SVML / Arm SLEEF once the JIT compiles
the vector loop to C2; before that
+ * compilation, they fall back to per-lane {@link Math} calls. The two paths
can differ by up to 1 ulp, so a
Review Comment:
This says up to 1 ulp, but `configuration/index.md` says "a few ulps" and
the test `SimdVoMathlibParityTest.MAX_ULPS` is checking for 4 ulps. Please make
all the commentary about accuracy consistent.
##########
processing/src/main/java/org/apache/druid/math/expr/ExpressionProcessing.java:
##########
@@ -99,6 +99,22 @@ public static boolean useVectorApi()
return INSTANCE.useVectorApi();
}
+ /**
+ * Whether SIMD dispatch is allowed for math ops backed by the JDK's
VO_MATHLIB path (LOG, EXP, SIN, etc). Off by
Review Comment:
IMO should be on by default (see other comment).
##########
processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleAcosProcessor.java:
##########
@@ -0,0 +1,58 @@
+/*
+ * 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.druid.math.expr.vector.simd;
+
+import jdk.incubator.vector.DoubleVector;
+import jdk.incubator.vector.VectorOperators;
+import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import
org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction;
+
+import java.util.Arrays;
+
+/**
+ * SIMD specialization of {@code (double[]) -> double[]} arc cosine. See
{@link SimdSupportedUnaryOp#ACOS} for
+ * the shared VO_MATHLIB performance notes.
+ */
+public final class SimdDoubleAcosProcessor extends SimdDoubleUnaryProcessor
Review Comment:
There are so many of these. I wonder if generating the classes at runtime
would be better than having all the sources here. Could be something to explore
in a follow-up.
##########
processing/src/main/java/org/apache/druid/math/expr/ExpressionProcessing.java:
##########
@@ -45,19 +45,19 @@ public class ExpressionProcessing
@VisibleForTesting
public static void initializeForTests()
{
- INSTANCE = new ExpressionProcessingConfig(null, null, null, null);
+ INSTANCE = new ExpressionProcessingConfig(null, null, null, null, null);
}
@VisibleForTesting
public static void initializeForHomogenizeNullMultiValueStrings()
{
- INSTANCE = new ExpressionProcessingConfig(null, true, null, null);
+ INSTANCE = new ExpressionProcessingConfig(null, true, null, null, null);
}
@VisibleForTesting
public static void initializeForVectorApiTests()
{
- INSTANCE = new ExpressionProcessingConfig(null, null, null, true);
+ INSTANCE = new ExpressionProcessingConfig(null, null, null, true, true);
Review Comment:
This seems like it could be a legit issue with
`VectorExprResultConsistencyVectorApiTest`, possibly dependent on the order in
which things are run.
##########
processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateDoubleProcessorFactory.java:
##########
@@ -64,10 +66,20 @@ protected SimpleVectorMathUnivariateDoubleProcessorFactory(
this.simdOp = simdOp;
}
+ private boolean simdEnabled()
+ {
+ if (simdOp == null || !ExpressionProcessing.useVectorApi()) {
+ return false;
+ }
+ // VO_MATHLIB ops (SVML/SLEEF-backed transcendentals) sit behind the
additional useVectorMathApi opt-in
+ // because they can produce different bits than Math.<op> once JIT tier
transitions the loop from C1 to C2.
+ return !simdOp.isMathLib() || ExpressionProcessing.useVectorMathApi();
Review Comment:
Should probably have a version of this check in `SimdSupportedBinaryOp` and
`SimpleVectorMathBivariateProcessorFactory` too. Maybe nothing would return
true today, but it seems useful to have it there so it's not forgotten in the
future when more ops are added.
Or, possibly even better, move this all into `simdOp.isSimdEnabled()`.
##########
docs/configuration/index.md:
##########
@@ -652,6 +652,7 @@ the `expression` aggregator/post-aggregator, and any SQL
functions that lower to
|`druid.expressions.homogenizeNullMultiValueStringArrays`|If true, multi-value
string expression input values of `null`, `[]`, and `[null]` are all coerced to
`[null]`. Provided for backwards compatibility with Druid 0.22 and earlier. If
false (the default), this coercion only happens when single-value expressions
are implicitly mapped across multi-value rows, so the single-valued expression
is evaluated with an input of `null`.|false|
|`druid.expressions.allowVectorizeFallback`|If true, the vectorized query
engine handles expressions without a native vectorized implementation using a
fallback processor that invokes the scalar expression evaluator in a loop. If
false, such expressions cannot be vectorized and the query falls back to the
non-vectorized engine.|true|
|`druid.expressions.useVectorApi`|If true, vectorized expression vector
processors and numeric vector aggregators dispatch to SIMD specializations
backed by the JDK incubator Vector API (`jdk.incubator.vector`) where
available. Requires `--add-modules=jdk.incubator.vector` on the JVM command
line (see [strong encapsulation](../operations/java.md#strong-encapsulation)).
Off by default while the Vector API remains an incubator JDK feature.|false|
+|`druid.expressions.useVectorMathApi`|If true (and `useVectorApi` is also
true), math expressions whose SIMD path is backed by the JDK's VO_MATHLIB
routing (Intel SVML on x86, SLEEF on Arm) dispatch to that SIMD path. Results
can differ from the scalar `Math.<op>` by up to a few ulps, and the exact bits
can shift once the JIT promotes the SIMD loop from C1 to C2, meaning a
long-running query can produce different bits for the same input across the
tier transition. Safe for `SUM`/`MIN`/`MAX`/range-filter workloads; **do not
enable** if queries rely on exact-bit equality of these functions (for example
`GROUP BY sin(x)` where all rows with the same `x` must land in the same group,
or `WHERE sin(x) = sin(y)`). Off by default.|false|
Review Comment:
We definitely shouldn't encourage users to rely on exact-bit equality for
floating point numbers. It's better to suggest that people truncate or round
for comparison.
##########
processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleAcosProcessor.java:
##########
@@ -0,0 +1,58 @@
+/*
+ * 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.druid.math.expr.vector.simd;
+
+import jdk.incubator.vector.DoubleVector;
+import jdk.incubator.vector.VectorOperators;
+import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import
org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction;
+
+import java.util.Arrays;
+
+/**
+ * SIMD specialization of {@code (double[]) -> double[]} arc cosine. See
{@link SimdSupportedUnaryOp#ACOS} for
+ * the shared VO_MATHLIB performance notes.
+ */
+public final class SimdDoubleAcosProcessor extends SimdDoubleUnaryProcessor
+{
+ public SimdDoubleAcosProcessor(ExprVectorProcessor<?> input,
DoubleUnivariateDoubleFunction scalarFallback)
+ {
+ super(input, scalarFallback);
+ }
+
+ @Override
+ protected void processVector(double[] input, boolean[] inputNulls, int
currentSize)
+ {
+ final int laneCount = SPECIES.length();
+ final int upperBound = SPECIES.loopBound(currentSize);
+ int i = 0;
+ for (; i < upperBound; i += laneCount) {
+ DoubleVector.fromArray(SPECIES, input,
i).lanewise(VectorOperators.ACOS).intoArray(outValues, i);
+ }
+ for (; i < currentSize; i++) {
+ outValues[i] = scalarFallback.process(input[i]);
Review Comment:
This approach of doing scalar fallbacks means that the accuracy
discrepancies are more pervasive than the docs in `configuration/index.md`
suggest. The final vector in a cursor (which is likely to be shorter than the
max size) will be using different math ops than the other vectors. Probably the
best way to fix it is to use a vector op here too, with a mask.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]