This is an automated email from the ASF dual-hosted git repository.

gianm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new f46ee871953 feat: simd sqrt (#19742)
f46ee871953 is described below

commit f46ee87195396a3be42303bd8c23324e2c1eba0e
Author: Clint Wylie <[email protected]>
AuthorDate: Thu Jul 23 20:25:04 2026 -0700

    feat: simd sqrt (#19742)
---
 .../benchmark/query/SqlExpressionBenchmark.java    |  9 ++-
 ...VectorMathUnivariateDoubleProcessorFactory.java | 29 +++++++-
 .../math/expr/vector/VectorMathProcessors.java     |  2 +-
 .../expr/vector/simd/SimdDoubleSqrtProcessor.java  | 59 ++++++++++++++++
 .../vector/simd/SimdLongToDoubleSqrtProcessor.java | 63 +++++++++++++++++
 .../simd/SimdLongToDoubleUnaryProcessor.java       | 82 ++++++++++++++++++++++
 .../math/expr/vector/simd/SimdProcessors.java      | 14 ++++
 .../expr/vector/simd/SimdSupportedUnaryOp.java     |  3 +-
 8 files changed, 256 insertions(+), 5 deletions(-)

diff --git 
a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
 
b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
index 43a1bb3413c..dc386debdd9 100644
--- 
a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
+++ 
b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
@@ -176,7 +176,10 @@ public class SqlExpressionBenchmark extends 
SqlBaseQueryBenchmark
       "SELECT SUM(ABS(long4)) FROM expressions",
       "SELECT SUM(ABS(double1)) FROM expressions",
       // 68: unary abs of a binary subtraction (composes SIMD sub with SIMD 
abs)
-      "SELECT SUM(ABS(long1 - long4)) FROM expressions"
+      "SELECT SUM(ABS(long1 - long4)) FROM expressions",
+      // 69,70: unary sqrt on double and long inputs (long input exercises the 
SIMD widening path)
+      "SELECT SUM(SQRT(double1)) FROM expressions",
+      "SELECT SUM(SQRT(long1)) FROM expressions"
   );
 
   @Param({
@@ -261,7 +264,9 @@ public class SqlExpressionBenchmark extends 
SqlBaseQueryBenchmark
       "65",
       "66",
       "67",
-      "68"
+      "68",
+      "69",
+      "70"
   })
   private String query;
 
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateDoubleProcessorFactory.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateDoubleProcessorFactory.java
index 593170dde3e..5d0c547de4c 100644
--- 
a/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateDoubleProcessorFactory.java
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateDoubleProcessorFactory.java
@@ -20,32 +20,56 @@
 package org.apache.druid.math.expr.vector;
 
 import org.apache.druid.math.expr.Expr;
+import org.apache.druid.math.expr.ExpressionProcessing;
 import 
org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction;
 import 
org.apache.druid.math.expr.vector.functional.DoubleUnivariateLongFunction;
+import org.apache.druid.math.expr.vector.simd.SimdProcessors;
+import org.apache.druid.math.expr.vector.simd.SimdSupportedUnaryOp;
+
+import javax.annotation.Nullable;
 
 /**
  * Make a 1 argument math processor with the following type rules
  *    long    -> double
  *    double  -> double
- * using simple scalar functions {@link DoubleUnivariateLongFunction} and 
{@link DoubleUnivariateDoubleFunction}
+ * using simple scalar functions {@link DoubleUnivariateLongFunction} and 
{@link DoubleUnivariateDoubleFunction}.
+ *
+ * If a non-null {@link SimdSupportedUnaryOp} is supplied to the constructor 
and
+ * {@link ExpressionProcessing#useVectorApi()} is true, this factory will 
return SIMD-specialized processors backed
+ * by the JDK incubator {@code jdk.incubator.vector} API instead of the 
standard scalar implementations.
  */
 public class SimpleVectorMathUnivariateDoubleProcessorFactory extends 
VectorMathUnivariateDoubleProcessorFactory
 {
   private final DoubleUnivariateLongFunction longFunction;
   private final DoubleUnivariateDoubleFunction doubleFunction;
+  @Nullable
+  private final SimdSupportedUnaryOp simdOp;
 
   public SimpleVectorMathUnivariateDoubleProcessorFactory(
       DoubleUnivariateLongFunction longFunction,
       DoubleUnivariateDoubleFunction doubleFunction
   )
+  {
+    this(longFunction, doubleFunction, null);
+  }
+
+  protected SimpleVectorMathUnivariateDoubleProcessorFactory(
+      DoubleUnivariateLongFunction longFunction,
+      DoubleUnivariateDoubleFunction doubleFunction,
+      @Nullable SimdSupportedUnaryOp simdOp
+  )
   {
     this.longFunction = longFunction;
     this.doubleFunction = doubleFunction;
+    this.simdOp = simdOp;
   }
 
   @Override
   public final ExprVectorProcessor<double[]> 
longProcessor(Expr.VectorInputBindingInspector inspector, Expr arg)
   {
+    if (simdOp != null && ExpressionProcessing.useVectorApi()) {
+      return 
SimdProcessors.makeLongToDoubleUnary(arg.asVectorProcessor(inspector), simdOp, 
longFunction);
+    }
     return new DoubleUnivariateLongFunctionVectorProcessor(
         arg.asVectorProcessor(inspector),
         longFunction
@@ -55,6 +79,9 @@ public class SimpleVectorMathUnivariateDoubleProcessorFactory 
extends VectorMath
   @Override
   public final ExprVectorProcessor<double[]> 
doubleProcessor(Expr.VectorInputBindingInspector inspector, Expr arg)
   {
+    if (simdOp != null && ExpressionProcessing.useVectorApi()) {
+      return SimdProcessors.makeDoubleUnary(arg.asVectorProcessor(inspector), 
simdOp, doubleFunction);
+    }
     return new DoubleUnivariateDoubleFunctionVectorProcessor(
         arg.asVectorProcessor(inspector),
         doubleFunction
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java
index 17b9a629faf..86f71c662f0 100644
--- 
a/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java
@@ -779,7 +779,7 @@ public class VectorMathProcessors
 
     public Sqrt()
     {
-      super(Math::sqrt, Math::sqrt);
+      super(Math::sqrt, Math::sqrt, SimdSupportedUnaryOp.SQRT);
     }
   }
 
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleSqrtProcessor.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleSqrtProcessor.java
new file mode 100644
index 00000000000..f7512effa7a
--- /dev/null
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleSqrtProcessor.java
@@ -0,0 +1,59 @@
+/*
+ * 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[]} square root. {@code 
lanewise(VectorOperators.SQRT)} is
+ * emitted with the operator literally inline so the JIT statically resolves 
it to the platform's double-sqrt
+ * intrinsic (e.g. {@code vsqrtpd} on x86).
+ */
+public final class SimdDoubleSqrtProcessor extends SimdDoubleUnaryProcessor
+{
+  public SimdDoubleSqrtProcessor(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.SQRT).intoArray(outValues, i);
+    }
+    for (; i < currentSize; i++) {
+      outValues[i] = scalarFallback.process(input[i]);
+    }
+    if (inputNulls == null) {
+      Arrays.fill(outNulls, 0, currentSize, false);
+    } else {
+      System.arraycopy(inputNulls, 0, outNulls, 0, currentSize);
+    }
+  }
+}
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongToDoubleSqrtProcessor.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongToDoubleSqrtProcessor.java
new file mode 100644
index 00000000000..a38670d0382
--- /dev/null
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongToDoubleSqrtProcessor.java
@@ -0,0 +1,63 @@
+/*
+ * 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.LongVector;
+import jdk.incubator.vector.VectorOperators;
+import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import 
org.apache.druid.math.expr.vector.functional.DoubleUnivariateLongFunction;
+
+import java.util.Arrays;
+
+/**
+ * SIMD specialization of {@code (long[]) -> double[]} square root. The long 
input is widened lane-by-lane to a
+ * {@link DoubleVector} via {@code castShape} and then {@code 
lanewise(VectorOperators.SQRT)} is emitted with the
+ * operator literally inline so the JIT statically resolves it to the 
platform's double-sqrt intrinsic (e.g.
+ * {@code vsqrtpd} on x86).
+ */
+public final class SimdLongToDoubleSqrtProcessor extends 
SimdLongToDoubleUnaryProcessor
+{
+  public SimdLongToDoubleSqrtProcessor(ExprVectorProcessor<?> input, 
DoubleUnivariateLongFunction scalarFallback)
+  {
+    super(input, scalarFallback);
+  }
+
+  @Override
+  protected void processVector(long[] input, boolean[] inputNulls, int 
currentSize)
+  {
+    final int laneCount = DOUBLE_SPECIES.length();
+    final int upperBound = DOUBLE_SPECIES.loopBound(currentSize);
+    int i = 0;
+    for (; i < upperBound; i += laneCount) {
+      final DoubleVector va =
+          (DoubleVector) LongVector.fromArray(LONG_SPECIES, input, 
i).castShape(DOUBLE_SPECIES, 0);
+      va.lanewise(VectorOperators.SQRT).intoArray(outValues, i);
+    }
+    for (; i < currentSize; i++) {
+      outValues[i] = scalarFallback.process(input[i]);
+    }
+    if (inputNulls == null) {
+      Arrays.fill(outNulls, 0, currentSize, false);
+    } else {
+      System.arraycopy(inputNulls, 0, outNulls, 0, currentSize);
+    }
+  }
+}
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongToDoubleUnaryProcessor.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongToDoubleUnaryProcessor.java
new file mode 100644
index 00000000000..6436b20d158
--- /dev/null
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongToDoubleUnaryProcessor.java
@@ -0,0 +1,82 @@
+/*
+ * 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.LongVector;
+import jdk.incubator.vector.VectorSpecies;
+import org.apache.druid.math.expr.Expr;
+import org.apache.druid.math.expr.ExpressionType;
+import org.apache.druid.math.expr.vector.CastToTypeVectorProcessor;
+import org.apache.druid.math.expr.vector.ExprEvalDoubleVector;
+import org.apache.druid.math.expr.vector.ExprEvalVector;
+import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import 
org.apache.druid.math.expr.vector.functional.DoubleUnivariateLongFunction;
+
+import javax.annotation.Nullable;
+
+/**
+ * Abstract base for SIMD processors that compute {@code (long[]) -> double[]} 
unary ops — the long input is
+ * widened lane-by-lane to a {@link DoubleVector} via {@code 
castShape(DoubleVector.SPECIES_PREFERRED, 0)} in each
+ * subclass's hot loop before the op. See {@link SimdLongUnaryProcessor} for 
the general design rationale.
+ */
+abstract class SimdLongToDoubleUnaryProcessor implements 
ExprVectorProcessor<double[]>
+{
+  static final VectorSpecies<Long> LONG_SPECIES = LongVector.SPECIES_PREFERRED;
+  static final VectorSpecies<Double> DOUBLE_SPECIES = 
DoubleVector.SPECIES_PREFERRED;
+
+  private final ExprVectorProcessor<long[]> input;
+  final DoubleUnivariateLongFunction scalarFallback;
+  final double[] outValues;
+  final boolean[] outNulls;
+
+  protected SimdLongToDoubleUnaryProcessor(
+      ExprVectorProcessor<?> input,
+      DoubleUnivariateLongFunction scalarFallback
+  )
+  {
+    this.input = CastToTypeVectorProcessor.cast(input, ExpressionType.LONG);
+    this.scalarFallback = scalarFallback;
+    this.outValues = new double[this.input.maxVectorSize()];
+    this.outNulls = new boolean[this.input.maxVectorSize()];
+  }
+
+  @Override
+  public final ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding 
bindings)
+  {
+    final ExprEvalVector<long[]> lhs = input.evalVector(bindings);
+    processVector(lhs.values(), lhs.getNullVector(), 
bindings.getCurrentVectorSize());
+    return new ExprEvalDoubleVector(outValues, outNulls);
+  }
+
+  protected abstract void processVector(long[] input, @Nullable boolean[] 
inputNulls, int currentSize);
+
+  @Override
+  public final ExpressionType getOutputType()
+  {
+    return ExpressionType.DOUBLE;
+  }
+
+  @Override
+  public final int maxVectorSize()
+  {
+    return outValues.length;
+  }
+}
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java
index c7ce4878ee8..a6f820eb7ce 100644
--- 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java
@@ -25,6 +25,7 @@ import 
org.apache.druid.math.expr.vector.functional.DoubleBivariateDoubleLongFun
 import 
org.apache.druid.math.expr.vector.functional.DoubleBivariateDoublesFunction;
 import 
org.apache.druid.math.expr.vector.functional.DoubleBivariateLongDoubleFunction;
 import 
org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction;
+import 
org.apache.druid.math.expr.vector.functional.DoubleUnivariateLongFunction;
 import org.apache.druid.math.expr.vector.functional.LongBivariateLongsFunction;
 import org.apache.druid.math.expr.vector.functional.LongUnivariateLongFunction;
 
@@ -124,7 +125,20 @@ public final class SimdProcessors
     return switch (op) {
       case NEG -> new SimdDoubleNegProcessor(input, scalarFallback);
       case ABS -> new SimdDoubleAbsProcessor(input, scalarFallback);
+      case SQRT -> new SimdDoubleSqrtProcessor(input, scalarFallback);
       default -> throw DruidException.defensive("Unsupported SIMD unary 
op[%s]", op);
     };
   }
+
+  public static ExprVectorProcessor<double[]> makeLongToDoubleUnary(
+      ExprVectorProcessor<?> input,
+      SimdSupportedUnaryOp op,
+      DoubleUnivariateLongFunction scalarFallback
+  )
+  {
+    return switch (op) {
+      case SQRT -> new SimdLongToDoubleSqrtProcessor(input, scalarFallback);
+      default -> throw DruidException.defensive("Unsupported SIMD unary op[%s] 
for long->double", op);
+    };
+  }
 }
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java
index 260fd24d2ac..f7f7e4bc498 100644
--- 
a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java
@@ -31,5 +31,6 @@ package org.apache.druid.math.expr.vector.simd;
 public enum SimdSupportedUnaryOp
 {
   NEG,
-  ABS
+  ABS,
+  SQRT
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to